def make_dummy_commit(self, dest): b = objects.Blob.from_string(b'hi') dest.object_store.add_object(b) t = index.commit_tree(dest.object_store, [(b'hi', b.id, 0o100644)]) c = objects.Commit() c.author = c.committer = b'Foo Bar <*****@*****.**>' c.author_time = c.commit_time = 0 c.author_timezone = c.commit_timezone = 0 c.message = b'hi' c.tree = t dest.object_store.add_object(c) return c.id
def commit(self, message, author, parents=None, branch=None, date=None, **kwargs): """ Performs in-memory commit (doesn't check workdir in any way) and returns newly created ``Changeset``. Updates repository's ``revisions``. :param message: message of the commit :param author: full username, i.e. "Joe Doe <*****@*****.**>" :param parents: single parent or sequence of parents from which commit would be derieved :param date: ``datetime.datetime`` instance. Defaults to ``datetime.datetime.now()``. :param branch: branch name, as string. If none given, default backend's branch would be used. :raises ``CommitError``: if any error occurs while committing """ self.check_integrity(parents) from .repository import GitRepository if branch is None: branch = GitRepository.DEFAULT_BRANCH_NAME repo = self.repository._repo object_store = repo.object_store ENCODING = "UTF-8" DIRMOD = 040000 # Create tree and populates it with blobs commit_tree = self.parents[0] and repo[self.parents[0]._commit.tree] or\ objects.Tree() for node in self.added + self.changed: # Compute subdirs if needed dirpath, nodename = posixpath.split(node.path) dirnames = dirpath and dirpath.split('/') or [] parent = commit_tree ancestors = [('', parent)] # Tries to dig for the deepest existing tree while dirnames: curdir = dirnames.pop(0) try: dir_id = parent[curdir][1] except KeyError: # put curdir back into dirnames and stops dirnames.insert(0, curdir) break else: # If found, updates parent parent = self.repository._repo[dir_id] ancestors.append((curdir, parent)) # Now parent is deepest existing tree and we need to create subtrees # for dirnames (in reverse order) [this only applies for nodes from added] new_trees = [] if not node.is_binary: content = node.content.encode(ENCODING) else: content = node.content blob = objects.Blob.from_string(content) node_path = node.name.encode(ENCODING) if dirnames: # If there are trees which should be created we need to build # them now (in reverse order) reversed_dirnames = list(reversed(dirnames)) curtree = objects.Tree() curtree[node_path] = node.mode, blob.id new_trees.append(curtree) for dirname in reversed_dirnames[:-1]: newtree = objects.Tree() #newtree.add(DIRMOD, dirname, curtree.id) newtree[dirname] = DIRMOD, curtree.id new_trees.append(newtree) curtree = newtree parent[reversed_dirnames[-1]] = DIRMOD, curtree.id else: parent.add(name=node_path, mode=node.mode, hexsha=blob.id) new_trees.append(parent) # Update ancestors for parent, tree, path in reversed([ (a[1], b[1], b[0]) for a, b in zip(ancestors, ancestors[1:]) ]): parent[path] = DIRMOD, tree.id object_store.add_object(tree) object_store.add_object(blob) for tree in new_trees: object_store.add_object(tree) for node in self.removed: paths = node.path.split('/') tree = commit_tree trees = [tree] # Traverse deep into the forest... for path in paths: try: obj = self.repository._repo[tree[path][1]] if isinstance(obj, objects.Tree): trees.append(obj) tree = obj except KeyError: break # Cut down the blob and all rotten trees on the way back... for path, tree in reversed(zip(paths, trees)): del tree[path] if tree: # This tree still has elements - don't remove it or any # of it's parents break object_store.add_object(commit_tree) # Create commit commit = objects.Commit() commit.tree = commit_tree.id commit.parents = [p._commit.id for p in self.parents if p] commit.author = commit.committer = safe_str(author) commit.encoding = ENCODING commit.message = safe_str(message) # Compute date if date is None: date = time.time() elif isinstance(date, datetime.datetime): date = time.mktime(date.timetuple()) author_time = kwargs.pop('author_time', date) commit.commit_time = int(date) commit.author_time = int(author_time) tz = time.timezone author_tz = kwargs.pop('author_timezone', tz) commit.commit_timezone = tz commit.author_timezone = author_tz object_store.add_object(commit) ref = 'refs/heads/%s' % branch repo.refs[ref] = commit.id repo.refs.set_symbolic_ref('HEAD', ref) # Update vcs repository object & recreate dulwich repo self.repository.revisions.append(commit.id) # invalidate parsed refs after commit self.repository._parsed_refs = self.repository._get_parsed_refs() tip = self.repository.get_changeset() self.reset() return tip
def commit(self, wire, commit_data, branch, commit_tree, updated, removed): repo = self._factory.repo(wire) object_store = repo.object_store # Create tree and populates it with blobs commit_tree = commit_tree and repo[commit_tree] or objects.Tree() for node in updated: # Compute subdirs if needed dirpath, nodename = vcspath.split(node['path']) dirnames = map(safe_str, dirpath and dirpath.split('/') or []) parent = commit_tree ancestors = [('', parent)] # Tries to dig for the deepest existing tree while dirnames: curdir = dirnames.pop(0) try: dir_id = parent[curdir][1] except KeyError: # put curdir back into dirnames and stops dirnames.insert(0, curdir) break else: # If found, updates parent parent = repo[dir_id] ancestors.append((curdir, parent)) # Now parent is deepest existing tree and we need to create # subtrees for dirnames (in reverse order) # [this only applies for nodes from added] new_trees = [] blob = objects.Blob.from_string(node['content']) if dirnames: # If there are trees which should be created we need to build # them now (in reverse order) reversed_dirnames = list(reversed(dirnames)) curtree = objects.Tree() curtree[node['node_path']] = node['mode'], blob.id new_trees.append(curtree) for dirname in reversed_dirnames[:-1]: newtree = objects.Tree() newtree[dirname] = (DIR_STAT, curtree.id) new_trees.append(newtree) curtree = newtree parent[reversed_dirnames[-1]] = (DIR_STAT, curtree.id) else: parent.add(name=node['node_path'], mode=node['mode'], hexsha=blob.id) new_trees.append(parent) # Update ancestors reversed_ancestors = reversed([ (a[1], b[1], b[0]) for a, b in zip(ancestors, ancestors[1:]) ]) for parent, tree, path in reversed_ancestors: parent[path] = (DIR_STAT, tree.id) object_store.add_object(tree) object_store.add_object(blob) for tree in new_trees: object_store.add_object(tree) for node_path in removed: paths = node_path.split('/') tree = commit_tree trees = [tree] # Traverse deep into the forest... for path in paths: try: obj = repo[tree[path][1]] if isinstance(obj, objects.Tree): trees.append(obj) tree = obj except KeyError: break # Cut down the blob and all rotten trees on the way back... for path, tree in reversed(zip(paths, trees)): del tree[path] if tree: # This tree still has elements - don't remove it or any # of it's parents break object_store.add_object(commit_tree) # Create commit commit = objects.Commit() commit.tree = commit_tree.id for k, v in commit_data.iteritems(): setattr(commit, k, v) object_store.add_object(commit) self.create_branch(wire, branch, commit.id) # dulwich set-ref ref = 'refs/heads/%s' % branch repo.refs[ref] = commit.id return commit.id