Esempio n. 1
0
    def remove_if_equals(self, name, old_ref):
        """Remove a refname only if it currently equals old_ref.

        This method does not follow symbolic references. It can be used to
        perform an atomic compare-and-delete operation.

        :param name: The refname to delete.
        :param old_ref: The old sha the refname must refer to, or None to delete
            unconditionally.
        :return: True if the delete was successful, False otherwise.
        """
        self._check_refname(name)
        filename = self.refpath(name)
        ensure_dir_exists(os.path.dirname(filename))
        f = GitFile(filename, 'wb')
        try:
            if old_ref is not None:
                orig_ref = self.read_loose_ref(name)
                if orig_ref is None:
                    orig_ref = self.get_packed_refs().get(name, None)
                if orig_ref != old_ref:
                    return False
            # may only be packed
            try:
                os.remove(filename)
            except OSError as e:
                if e.errno != errno.ENOENT:
                    raise
            self._remove_packed_ref(name)
        finally:
            # never write, we just wanted the lock
            f.abort()
        return True
Esempio n. 2
0
    def remove_if_equals(self, name, old_ref):
        """Remove a refname only if it currently equals old_ref.

        This method does not follow symbolic references. It can be used to
        perform an atomic compare-and-delete operation.

        :param name: The refname to delete.
        :param old_ref: The old sha the refname must refer to, or None to delete
            unconditionally.
        :return: True if the delete was successful, False otherwise.
        """
        self._check_refname(name)
        filename = self.refpath(name)
        ensure_dir_exists(os.path.dirname(filename))
        f = GitFile(filename, 'wb')
        try:
            if old_ref is not None:
                orig_ref = self.read_loose_ref(name)
                if orig_ref is None:
                    orig_ref = self.get_packed_refs().get(name, None)
                if orig_ref != old_ref:
                    return False
            # may only be packed
            try:
                os.remove(filename)
            except OSError as e:
                if e.errno != errno.ENOENT:
                    raise
            self._remove_packed_ref(name)
        finally:
            # never write, we just wanted the lock
            f.abort()
        return True
Esempio n. 3
0
    def remove_if_equals(self, name, old_ref, committer=None, timestamp=None,
                         timezone=None, message=None):
        """Remove a refname only if it currently equals old_ref.

        This method does not follow symbolic references. It can be used to
        perform an atomic compare-and-delete operation.

        :param name: The refname to delete.
        :param old_ref: The old sha the refname must refer to, or None to
            delete unconditionally.
        :param message: Optional message
        :return: True if the delete was successful, False otherwise.
        """
        self._check_refname(name)
        filename = self.refpath(name)
        ensure_dir_exists(os.path.dirname(filename))
        f = GitFile(filename, 'wb')
        try:
            if old_ref is not None:
                orig_ref = self.read_loose_ref(name)
                if orig_ref is None:
                    orig_ref = self.get_packed_refs().get(name, ZERO_SHA)
                if orig_ref != old_ref:
                    return False

            # remove the reference file itself
            try:
                os.remove(filename)
            except OSError as e:
                if e.errno != errno.ENOENT:  # may only be packed
                    raise

            self._remove_packed_ref(name)
            self._log(name, old_ref, None, committer=committer,
                      timestamp=timestamp, timezone=timezone, message=message)
        finally:
            # never write, we just wanted the lock
            f.abort()

        # outside of the lock, clean-up any parent directory that might now
        # be empty. this ensures that re-creating a reference of the same
        # name of what was previously a directory works as expected
        parent = name
        while True:
            try:
                parent, _ = parent.rsplit(b'/', 1)
            except ValueError:
                break

            parent_filename = self.refpath(parent)
            try:
                os.rmdir(parent_filename)
            except OSError:
                # this can be caused by the parent directory being
                # removed by another process, being not empty, etc.
                # in any case, this is non fatal because we already
                # removed the reference, just ignore it
                break

        return True
Esempio n. 4
0
    def add_if_new(self, name, ref):
        """Add a new reference only if it does not already exist.

        This method follows symrefs, and only ensures that the last ref in the
        chain does not exist.

        :param name: The refname to set.
        :param ref: The new sha the refname will refer to.
        :return: True if the add was successful, False otherwise.
        """
        try:
            realname, contents = self._follow(name)
            if contents is not None:
                return False
        except KeyError:
            realname = name
        self._check_refname(realname)
        filename = self.refpath(realname)
        ensure_dir_exists(os.path.dirname(filename))
        with GitFile(filename, 'wb') as f:
            if os.path.exists(filename) or name in self.get_packed_refs():
                f.abort()
                return False
            try:
                f.write(ref + b'\n')
            except (OSError, IOError):
                f.abort()
                raise
        return True
    def remove_if_equals(self, name, old_ref, committer=None, timestamp=None,
                         timezone=None, message=None):
        """Remove a refname only if it currently equals old_ref.

        This method does not follow symbolic references. It can be used to
        perform an atomic compare-and-delete operation.

        :param name: The refname to delete.
        :param old_ref: The old sha the refname must refer to, or None to
            delete unconditionally.
        :param message: Optional message
        :return: True if the delete was successful, False otherwise.
        """
        self._check_refname(name)
        filename = self.refpath(name)
        ensure_dir_exists(os.path.dirname(filename))
        f = GitFile(filename, 'wb')
        try:
            if old_ref is not None:
                orig_ref = self.read_loose_ref(name)
                if orig_ref is None:
                    orig_ref = self.get_packed_refs().get(name, ZERO_SHA)
                if orig_ref != old_ref:
                    return False

            # remove the reference file itself
            try:
                os.remove(filename)
            except OSError as e:
                if e.errno != errno.ENOENT:  # may only be packed
                    raise

            self._remove_packed_ref(name)
            self._log(name, old_ref, None, committer=committer,
                      timestamp=timestamp, timezone=timezone, message=message)
        finally:
            # never write, we just wanted the lock
            f.abort()

        # outside of the lock, clean-up any parent directory that might now
        # be empty. this ensures that re-creating a reference of the same
        # name of what was previously a directory works as expected
        parent = name
        while True:
            try:
                parent, _ = parent.rsplit(b'/', 1)
            except ValueError:
                break

            parent_filename = self.refpath(parent)
            try:
                os.rmdir(parent_filename)
            except OSError as e:
                # this can be caused by the parent directory being
                # removed by another process, being not empty, etc.
                # in any case, this is non fatal because we already
                # removed the reference, just ignore it
                break

        return True
Esempio n. 6
0
    def add_if_new(self, name, ref):
        """Add a new reference only if it does not already exist.

        This method follows symrefs, and only ensures that the last ref in the
        chain does not exist.

        :param name: The refname to set.
        :param ref: The new sha the refname will refer to.
        :return: True if the add was successful, False otherwise.
        """

        try:
            realname, contents = self._follow(name)
            if contents is not None:
                return False
        except KeyError:
            realname = name
        self._check_refname(realname)
        filename = self.refpath(realname)
        ensure_dir_exists(os.path.dirname(filename))
        with GitFile(filename, 'wb') as f:
            if os.path.exists(filename) or name in self.get_packed_refs():
                f.abort()
                return False
            try:
                f.write(ref.hex_bytes + b'\n')
            except (OSError, IOError):
                f.abort()
                raise
        return True
Esempio n. 7
0
File: Git.py Progetto: timl/bcfg2
        def pull(self):
            try:
                remote_refs = self.client.fetch(
                    self.origin_path, self.repo,
                    determine_wants=self.repo.object_store.determine_wants_all)
            except KeyError:
                etype, err = sys.exc_info()[:2]
                # try to work around bug
                # https://bugs.launchpad.net/dulwich/+bug/1025886
                try:
                    # pylint: disable=W0212
                    self.client._fetch_capabilities.remove('thin-pack')
                # pylint: enable=W0212
                except KeyError:
                    raise etype(err)
                remote_refs = self.client.fetch(
                    self.origin_path, self.repo,
                    determine_wants=self.repo.object_store.determine_wants_all)

            tree_id = self.repo[remote_refs['HEAD']].tree
            # iterate over tree content, giving path and blob sha.
            for entry in self.repo.object_store.iter_tree_contents(tree_id):
                entry_in_path = entry.in_path(self.repo.path)
                ensure_dir_exists(os.path.split(entry_in_path.path)[0])
                GitFile(entry_in_path.path,
                        'wb').write(self.repo[entry.sha].data)
Esempio n. 8
0
    def set_if_equals(self,
                      name,
                      old_ref,
                      new_ref,
                      committer=None,
                      timestamp=None,
                      timezone=None,
                      message=None):
        """Set a refname to new_ref only if it currently equals old_ref.

        This method follows all symbolic references, and can be used to perform
        an atomic compare-and-swap operation.

        :param name: The refname to set.
        :param old_ref: The old sha the refname must refer to, or None to set
            unconditionally.
        :param new_ref: The new sha the refname will refer to.
        :param message: Set message for reflog
        :return: True if the set was successful, False otherwise.
        """
        self._check_refname(name)
        try:
            realnames, _ = self.follow(name)
            realname = realnames[-1]
        except (KeyError, IndexError):
            realname = name
        filename = self.refpath(realname)
        ensure_dir_exists(os.path.dirname(filename))
        with GitFile(filename, 'wb') as f:
            if old_ref is not None:
                try:
                    # read again while holding the lock
                    orig_ref = self.read_loose_ref(realname)
                    if orig_ref is None:
                        orig_ref = self.get_packed_refs().get(
                            realname, ZERO_SHA)
                    if orig_ref != old_ref:
                        f.abort()
                        return False
                except (OSError, IOError):
                    f.abort()
                    raise
            try:
                f.write(new_ref + b'\n')
            except (OSError, IOError):
                f.abort()
                raise
            self._log(realname,
                      old_ref,
                      new_ref,
                      committer=committer,
                      timestamp=timestamp,
                      timezone=timezone,
                      message=message)
        return True
Esempio n. 9
0
    def set_if_equals(self, name, old_ref, new_ref, committer=None,
                      timestamp=None, timezone=None, message=None):
        """Set a refname to new_ref only if it currently equals old_ref.

        This method follows all symbolic references, and can be used to perform
        an atomic compare-and-swap operation.

        :param name: The refname to set.
        :param old_ref: The old sha the refname must refer to, or None to set
            unconditionally.
        :param new_ref: The new sha the refname will refer to.
        :param message: Set message for reflog
        :return: True if the set was successful, False otherwise.
        """
        self._check_refname(name)
        try:
            realnames, _ = self.follow(name)
            realname = realnames[-1]
        except (KeyError, IndexError):
            realname = name
        filename = self.refpath(realname)

        # make sure none of the ancestor folders is in packed refs
        probe_ref = os.path.dirname(realname)
        packed_refs = self.get_packed_refs()
        while probe_ref:
            if packed_refs.get(probe_ref, None) is not None:
                raise OSError(errno.ENOTDIR,
                              'Not a directory: {}'.format(filename))
            probe_ref = os.path.dirname(probe_ref)

        ensure_dir_exists(os.path.dirname(filename))
        with GitFile(filename, 'wb') as f:
            if old_ref is not None:
                try:
                    # read again while holding the lock
                    orig_ref = self.read_loose_ref(realname)
                    if orig_ref is None:
                        orig_ref = self.get_packed_refs().get(
                                realname, ZERO_SHA)
                    if orig_ref != old_ref:
                        f.abort()
                        return False
                except (OSError, IOError):
                    f.abort()
                    raise
            try:
                f.write(new_ref + b'\n')
            except (OSError, IOError):
                f.abort()
                raise
            self._log(realname, old_ref, new_ref, committer=committer,
                      timestamp=timestamp, timezone=timezone, message=message)
        return True
Esempio n. 10
0
def fetch_refs(remote_name = 'origin', local='.'):
    """
    Fetch references from a Git remote repository
    :param remote_name: <str> git name of remote repository, _default='origin'_
    :param local: <str> full path to local repository, _default='.'_
    :return entries: <TreeEntry> named tuples
    """
    #import rpdb; rpdb.set_trace()
    # **Fetch refs from remote**
    # create a dulwich Repo object from path to local repo
    r = Repo(local)  # local repository
    objsto = r.object_store  # create a ObjectStore object from the local repo
    determine_wants = objsto.determine_wants_all  # built in dulwich function
    gitdir = os.path.join(local, r.controldir())  # the git folder
    cnf_file = os.path.join(gitdir, 'config')  # path to config
    cnf = ConfigFile.from_path(cnf_file)  # config
    remote = cnf.get(('remote', remote_name), 'url')  # url of remote
    # correctly parse host path and create dulwich Client object from it
    client, host_path = get_transport_and_path(remote)
    remote_refs = client.fetch(host_path, r, determine_wants, sys.stdout.write)

    # **Store refs fetched by dulwich**
    dulwich_refs = os.path.join(gitdir, DULWICH_REFS)
    with open(dulwich_refs, 'wb') as file:
        writer = csv.writer(file, delimiter=' ')
        for key, value in remote_refs.items():
            writer.writerow([key, value])

    # **save remote refs shas for future checkout**
    remote_dir = os.path.join(gitdir, 'refs', 'remotes', remote_name)  # .git/refs/remotes
    ensure_dir_exists(remote_dir)  # built in dulwich function
    headref = 0
    # head branch ref
    if remote_refs.has_key('HEAD'):
        headref = remote_refs.pop('HEAD')  # sha of HEAD
        i_head = remote_refs.values().index(headref)  # index of head ref
        head_branch = remote_refs.keys()[i_head]  # name of head branch
        branch_key = head_branch.rsplit('/',1)[-1]  # branch
        head_file = os.path.join(remote_dir, 'HEAD')  # path to branch shas file
        head_ref = '/'.join(['refs','remotes',remote_name,branch_key])
        with open(head_file, 'wb') as GitFile:
            GitFile.write('ref: ' + head_ref + '\n')
    # remote branch refs
    for key, value in remote_refs.items():
        key = key.rsplit('/',1)[-1]  # get just the remote's branch
        reffile = os.path.join(remote_dir, key)  # path to branch shas file
        with open(reffile, 'wb') as GitFile:
            GitFile.write(value + '\n')
    if headref:
        remote_refs['HEAD'] = headref  # restore HEAD sha

    return remote_refs
Esempio n. 11
0
    def add_if_new(
        self,
        name,
        ref,
        committer=None,
        timestamp=None,
        timezone=None,
        message=None,
    ):
        """Add a new reference only if it does not already exist.

        This method follows symrefs, and only ensures that the last ref in the
        chain does not exist.

        Args:
          name: The refname to set.
          ref: The new sha the refname will refer to.
          message: Optional message for reflog
        Returns: True if the add was successful, False otherwise.
        """
        try:
            realnames, contents = self.follow(name)
            if contents is not None:
                return False
            realname = realnames[-1]
        except (KeyError, IndexError):
            realname = name
        self._check_refname(realname)
        filename = self.refpath(realname)
        ensure_dir_exists(os.path.dirname(filename))
        with GitFile(filename, "wb") as f:
            if os.path.exists(filename) or name in self.get_packed_refs():
                f.abort()
                return False
            try:
                f.write(ref + b"\n")
            except (OSError, IOError):
                f.abort()
                raise
            else:
                self._log(
                    name,
                    None,
                    ref,
                    committer=committer,
                    timestamp=timestamp,
                    timezone=timezone,
                    message=message,
                )
        return True
Esempio n. 12
0
 def add_if_new(self, name, ref):
     """Add a new reference only if it does not already exist."""
     self._check_refname(name)
     filename = self.refpath(name)
     ensure_dir_exists(os.path.dirname(filename))
     f = GitFile(filename, 'wb')
     try:
         if os.path.exists(filename) or name in self.get_packed_refs():
             f.abort()
             return False
         try:
             f.write(ref+"\n")
         except (OSError, IOError):
             f.abort()
             raise
     finally:
         f.close()
     return True
Esempio n. 13
0
    def set_if_equals(self, name, old_ref, new_ref):
        """Set a refname to new_ref only if it currently equals old_ref.

        This method follows all symbolic references, and can be used to perform
        an atomic compare-and-swap operation.

        :param name: The refname to set.
        :param old_ref: The old sha the refname must refer to, or None to set
            unconditionally.
        :param new_ref: The new sha the refname will refer to.
        :return: True if the set was successful, False otherwise.
        """
        self._check_refname(name)
        try:
            realname, _ = self._follow(name)
        except KeyError:
            realname = name
        filename = self.refpath(realname)
        ensure_dir_exists(os.path.dirname(filename))
        f = GitFile(filename, 'wb')
        try:
            if old_ref is not None:
                try:
                    # read again while holding the lock
                    orig_ref = self.read_loose_ref(realname)
                    if orig_ref is None:
                        orig_ref = self.get_packed_refs().get(realname, None)
                    if orig_ref != old_ref:
                        f.abort()
                        return False
                except (OSError, IOError):
                    f.abort()
                    raise
            try:
                f.write(new_ref+"\n")
            except (OSError, IOError):
                f.abort()
                raise
        finally:
            f.close()
        return True
Esempio n. 14
0
    def set_if_equals(self, name, old_ref, new_ref):
        """Set a refname to new_ref only if it currently equals old_ref.

        This method follows all symbolic references, and can be used to perform
        an atomic compare-and-swap operation.

        :param name: The refname to set.
        :param old_ref: The old sha the refname must refer to, or None to set
            unconditionally.
        :param new_ref: The new sha the refname will refer to.
        :return: True if the set was successful, False otherwise.
        """
        self._check_refname(name)
        try:
            realname, _ = self._follow(name)
        except KeyError:
            realname = name
        filename = self.refpath(realname)
        ensure_dir_exists(os.path.dirname(filename))
        f = GitFile(filename, 'wb')
        try:
            if old_ref is not None:
                try:
                    # read again while holding the lock
                    orig_ref = self.read_loose_ref(realname)
                    if orig_ref is None:
                        orig_ref = self.get_packed_refs().get(realname, None)
                    if orig_ref != old_ref:
                        f.abort()
                        return False
                except (OSError, IOError):
                    f.abort()
                    raise
            try:
                f.write(new_ref + "\n")
            except (OSError, IOError):
                f.abort()
                raise
        finally:
            f.close()
        return True
Esempio n. 15
0
def checkout(repo_path='.', co_ref='HEAD'):
    """
    Checkout a reference from a Git repository
    :param repo_path: <str> path of repository
    :param co_ref: <str> name of checkout reference
    :return entries: <TreeEntry> named tuples
    """
    # TODO: try using index.build_index_from_tree
    repo = Repo(repo_path)
    obj_sto = repo.object_store
    # TODO: catch not a reference
    tree_id = repo[co_ref].tree
    # TODO: error out if unstaged or uncommited files
    entries = []
    for entry in obj_sto.iter_tree_contents(tree_id):
        entry_in_path = entry.in_path(repo.path)
        path = os.path.split(entry_in_path.path)
        ensure_dir_exists(path[0])
        path = os.path.join(*path)
        with open(path, 'wb') as GitFile:
            GitFile.write(repo[entry_in_path.sha].data)
        os.chmod(path, entry_in_path.mode)
        entries.append(entry)
    return entries
Esempio n. 16
0
    def add_if_new(self, name, ref, committer=None, timestamp=None,
                   timezone=None, message=None):
        """Add a new reference only if it does not already exist.

        This method follows symrefs, and only ensures that the last ref in the
        chain does not exist.

        :param name: The refname to set.
        :param ref: The new sha the refname will refer to.
        :param message: Optional message for reflog
        :return: True if the add was successful, False otherwise.
        """
        try:
            realnames, contents = self.follow(name)
            if contents is not None:
                return False
            realname = realnames[-1]
        except (KeyError, IndexError):
            realname = name
        self._check_refname(realname)
        filename = self.refpath(realname)
        ensure_dir_exists(os.path.dirname(filename))
        with GitFile(filename, 'wb') as f:
            if os.path.exists(filename) or name in self.get_packed_refs():
                f.abort()
                return False
            try:
                f.write(ref + b'\n')
            except (OSError, IOError):
                f.abort()
                raise
            else:
                self._log(name, None, ref, committer=committer,
                          timestamp=timestamp, timezone=timezone,
                          message=message)
        return True
Esempio n. 17
0
    def set_if_equals(
        self,
        name,
        old_ref,
        new_ref,
        committer=None,
        timestamp=None,
        timezone=None,
        message=None,
    ):
        """Set a refname to new_ref only if it currently equals old_ref.

        This method follows all symbolic references, and can be used to perform
        an atomic compare-and-swap operation.

        Args:
          name: The refname to set.
          old_ref: The old sha the refname must refer to, or None to set
            unconditionally.
          new_ref: The new sha the refname will refer to.
          message: Set message for reflog
        Returns: True if the set was successful, False otherwise.
        """
        self._check_refname(name)
        try:
            realnames, _ = self.follow(name)
            realname = realnames[-1]
        except (KeyError, IndexError):
            realname = name
        filename = self.refpath(realname)

        # make sure none of the ancestor folders is in packed refs
        probe_ref = os.path.dirname(realname)
        packed_refs = self.get_packed_refs()
        while probe_ref:
            if packed_refs.get(probe_ref, None) is not None:
                raise NotADirectoryError(filename)
            probe_ref = os.path.dirname(probe_ref)

        ensure_dir_exists(os.path.dirname(filename))
        with GitFile(filename, "wb") as f:
            if old_ref is not None:
                try:
                    # read again while holding the lock
                    orig_ref = self.read_loose_ref(realname)
                    if orig_ref is None:
                        orig_ref = self.get_packed_refs().get(realname, ZERO_SHA)
                    if orig_ref != old_ref:
                        f.abort()
                        return False
                except (OSError, IOError):
                    f.abort()
                    raise
            try:
                f.write(new_ref + b"\n")
            except (OSError, IOError):
                f.abort()
                raise
            self._log(
                realname,
                old_ref,
                new_ref,
                committer=committer,
                timestamp=timestamp,
                timezone=timezone,
                message=message,
            )
        return True
Esempio n. 18
0
 def setUp(self):
     self.gitroot = os.path.dirname(import_repo_to_dir("server_new.export"))
     self.dest = os.path.join(self.gitroot, "dest")
     file.ensure_dir_exists(self.dest)
     run_git_or_fail(["init", "--quiet", "--bare"], cwd=self.dest)
Esempio n. 19
0
 def setUp(self):
     self.gitroot = os.path.dirname(
         import_repo_to_dir("server_new.export").rstrip(os.sep))
     self.dest = os.path.join(self.gitroot, "dest")
     file.ensure_dir_exists(self.dest)
     run_git_or_fail(["init", "--quiet", "--bare"], cwd=self.dest)
Esempio n. 20
0
 def setUp(self):
     self.gitroot = os.path.dirname(
             import_repo_to_dir('server_new.export').rstrip(os.sep))
     self.dest = os.path.join(self.gitroot, 'dest')
     file.ensure_dir_exists(self.dest)
     run_git_or_fail(['init', '--quiet', '--bare'], cwd=self.dest)