def __init__(self, repo, message, ref=None, commit_cls=sync_commit.Commit, initial_empty=False): """Object to be used as a context manager for commiting changes to the repo. This class provides low-level access to the git repository in order to make commits without requiring a checkout. It also enforces locking so that only one process may make a commit at a time. In order to use the object, one initalises it and then invokes it as a context manager e.g. with CommitBuilder(repo, "Some commit message" ref=ref) as commit_builder: # Now we have acquired the lock so that the commit ref points to is fixed commit_builder.add_tree({"some/path": "Some file data"}) commit_bulder.delete(["another/path"]) # On exiting the context, the commit is created, the ref updated to point at the # new commit and the lock released # To get the created commit we call get commit = commit_builder.get() The class may be used reentrantly. This is to support a pattern where a method may be called either with an existing commit_builder instance or create a new instance, and in either case use a with block. In order to improve the performance of the low-level access here, we use libgit2 to access the repository. """ # Class state self.repo = repo self.pygit2_repo = pygit2_get(repo) self.message = message if message is not None else "" self.commit_cls = commit_cls self.initial_empty = initial_empty if not ref: self.ref = None elif hasattr(ref, "path"): self.ref = ref.path else: self.ref = ref self._count = 0 # State set for the life of the context manager self.lock = RepoLock(repo) self.parents = None self.commit = None self.index = None self.has_changes = False
def do_configure_repos(git_gecko, git_wpt, *args, **kwargs): import repos name = kwargs.get("repo") r = repos.wrappers[name](env.config) with RepoLock(r.repo()): r.configure( os.path.abspath(os.path.normpath(kwargs.get("config_file"))))
def _update_gecko(git_gecko): with RepoLock(git_gecko): logger.info("Fetching mozilla-unified") # Not using the built in fetch() function since that tries to parse the output # and sometimes fails git_gecko.git.fetch("mozilla") if "autoland" in [item.name for item in git_gecko.remotes]: logger.info("Fetching autoland") git_gecko.git.fetch("autoland")
def do_fetch(git_gecko, git_wpt, *args, **kwargs): import repos c = env.config name = kwargs.get("repo") r = repos.wrappers[name](c) logger.info("Fetching %s in %s..." % (name, r.root)) pyrepo = r.repo() with RepoLock(pyrepo): try: pyrepo.git.fetch(*r.fetch_args) except git.GitCommandError as e: # GitPython fails when git warns about adding known host key for new IP if re.search(".*Warning: Permanently added.*host key.*", e.stderr) is not None: logger.debug(e.stderr) else: raise e
def _update_wpt(git_wpt): with RepoLock(git_wpt): logger.info("Fetching web-platform-tests") git_wpt.git.fetch("origin")
class CommitBuilder(object): def __init__(self, repo, message, ref=None, commit_cls=sync_commit.Commit, initial_empty=False): """Object to be used as a context manager for commiting changes to the repo. This class provides low-level access to the git repository in order to make commits without requiring a checkout. It also enforces locking so that only one process may make a commit at a time. In order to use the object, one initalises it and then invokes it as a context manager e.g. with CommitBuilder(repo, "Some commit message" ref=ref) as commit_builder: # Now we have acquired the lock so that the commit ref points to is fixed commit_builder.add_tree({"some/path": "Some file data"}) commit_bulder.delete(["another/path"]) # On exiting the context, the commit is created, the ref updated to point at the # new commit and the lock released # To get the created commit we call get commit = commit_builder.get() The class may be used reentrantly. This is to support a pattern where a method may be called either with an existing commit_builder instance or create a new instance, and in either case use a with block. In order to improve the performance of the low-level access here, we use libgit2 to access the repository. """ # Class state self.repo = repo self.pygit2_repo = pygit2_get(repo) self.message = message if message is not None else "" self.commit_cls = commit_cls self.initial_empty = initial_empty if not ref: self.ref = None elif hasattr(ref, "path"): self.ref = ref.path else: self.ref = ref self._count = 0 # State set for the life of the context manager self.lock = RepoLock(repo) self.parents = None self.commit = None self.index = None self.has_changes = False def __enter__(self): self._count += 1 if self._count != 1: return self self.lock.__enter__() # First we create an empty index self.index = pygit2.Index() if self.ref is not None: try: ref = self.pygit2_repo.lookup_reference(self.ref) except KeyError: self.parents = [] else: self.parents = [ref.peel().id] if not self.initial_empty: self.index.read_tree(ref.peel().tree) else: self.parents = [] return self def __exit__(self, *args, **kwargs): self._count -= 1 if self._count != 0: return if not self.has_changes: if self.parents: sha1 = self.parents[0] else: return None else: tree_id = self.index.write_tree(self.pygit2_repo) sha1 = self.pygit2_repo.create_commit(self.ref, self.pygit2_repo.default_signature, self.pygit2_repo.default_signature, self.message, tree_id, self.parents) self.lock.__exit__(*args, **kwargs) self.commit = self.commit_cls(self.repo, sha1) def add_tree(self, tree): self.has_changes = True for path, data in tree.iteritems(): blob = self.pygit2_repo.create_blob(data) index_entry = pygit2.IndexEntry(path, blob, pygit2.GIT_FILEMODE_BLOB) self.index.add(index_entry) def delete(self, delete): self.has_changes = True if delete: for path in delete: self.index.remove(path) def get(self): return self.commit