Пример #1
0
class RepoWriteLock:
    def __init__(self, url):
        self.url = url
        self.transport = None
        self.client = None
        self.socket = socket()

    def __enter__(self):
        self.socket.connect((interpret_urlish(self.url)[1], 22))
        self.transport = Transport(self.socket)
        self.transport.start_client()
        authenticate_transport(self.transport)
        self.client = self.transport.open_sftp_client()
        self.client.chdir(interpret_urlish(self.url)[2])

        self._lock()

    def _lock(self):
        target_locks = self.client.listdir("locks")
        target_locks.sort()

        if target_locks:
            raise RuntimeError("repo is locked; try again later")
        else:
            self.client.mkdir("locks/write_lock")

    def _unlock(self):
        self.client.rmdir("locks/write_lock")

    def __exit__(self, *args):
        self._unlock()

        self.client.close()
        self.transport.close()
        self.socket.close()
Пример #2
0
class Repository:
    def __init__(self, url):
        self.url = url
        self.index = {}

        self.read_lock = RepoReadLock(url)
        self.write_lock = RepoWriteLock(url)

        self.client = None
        self.transport = None
        self.socket = socket()

        self.opened = False

    def open(self):
        """
        Opens the connection
        """

        self.socket.connect((interpret_urlish(self.url)[1], 22))
        self.transport = Transport(self.socket)
        self.transport.start_client()
        authenticate_transport(self.transport)
        self.client = self.transport.open_sftp_client()
        target_path = interpret_urlish(self.url)[2]
        try:
            self.client.stat(target_path)
        except IOError:
            self.client.mkdir(target_path)
        self.client.chdir(target_path)
        self.opened = True

    def close(self):
        """
        Closes the connection
        """

        if not self.opened:
            return
        self.client.close()
        self.transport.close()
        self.socket.close()
        self.opened = False

    def update(self):
        """
        Update the information in this class to match that of the remote.

        Raises exceptions if remote is invalid or in an invalid state
        """

        if not self.opened:
            self.open()

        with self.read_lock:
            with self.client.open("index.json") as f:
                self.index = json.load(f)

    def get_script(self, hname=None):
        """
        Get the script object
        """
        if hname is None:
            hname = self.index["start"]
        return self.index["scripts"][hname]

    def download_script(self, hname=None):
        if hname is None:
            hname = self.index["start"]
        with self.read_lock:
            with self.client.open("scripts/" + hname + ".py", "r") as f:
                return f.read()

    def get_revision(self):
        return self.index["revision"]

    def append_script(self, script_obj, script_contents):
        h = sha512()
        h.update(script_contents.encode("utf-7"))
        hname = h.hexdigest()
        script_obj["prev"] = self.index["end"]

        with self.write_lock:
            self.index["revision"] += 1
            if self.index["end"]:
                self.index["scripts"][self.index["end"]]["next"] = hname
            self.index["end"] = hname
            self.index["scripts"][hname] = script_obj

            if self.index["start"] == "":
                self.index["start"] = hname

            self._write()
            with self.client.open("scripts/" + hname + ".py", "w") as f:
                f.write(script_contents)

    def _write(self):
        with self.client.open("index.json", "w") as f:
            json.dump(self.index, f)

    def write(self):
        with self.write_lock:
            self._write()

    def __iter__(self):
        return FollowChainIterator(self, self.index["start"])

    def iterate_from(self, pos):
        return FollowChainIterator(self, pos)

    def new(self):
        if not self.opened:
            self.open()

        try:
            self.client.stat("index.json")
            raise RuntimeError(
                "already init-ed, manually delete the folder to re-init")
        except IOError:
            pass

        # create the skeleton fs
        self.client.mkdir("locks")
        self.client.mkdir("scripts")

        # create a basic index.json
        self.index = {
            "version": 1,
            "revision": 0,
            "start": "",
            "end": "",
            "scripts": {}
        }

        self.write()