def do_commit(self, message, committer=None, author=None, commit_timestamp=None, commit_timezone=None, author_timestamp=None, author_timezone=None, tree=None): """Create a new commit. :param message: Commit message :param committer: Committer fullname :param author: Author fullname (defaults to committer) :param commit_timestamp: Commit timestamp (defaults to now) :param commit_timezone: Commit timestamp timezone (defaults to GMT) :param author_timestamp: Author timestamp (defaults to commit timestamp) :param author_timezone: Author timestamp timezone (defaults to commit timestamp timezone) :param tree: SHA1 of the tree root to use (if not specified the current index will be committed). :return: New commit SHA1 """ import time c = Commit() if tree is None: index = self.open_index() c.tree = index.commit(self.object_store) else: c.tree = tree # TODO: Allow username to be missing, and get it from .git/config if committer is None: raise ValueError("committer not set") c.committer = committer if commit_timestamp is None: commit_timestamp = time.time() c.commit_time = int(commit_timestamp) if commit_timezone is None: # FIXME: Use current user timezone rather than UTC commit_timezone = 0 c.commit_timezone = commit_timezone if author is None: author = committer c.author = author if author_timestamp is None: author_timestamp = commit_timestamp c.author_time = int(author_timestamp) if author_timezone is None: author_timezone = commit_timezone c.author_timezone = author_timezone c.message = message try: old_head = self.refs["HEAD"] c.parents = [old_head] self.object_store.add_object(c) ok = self.refs.set_if_equals("HEAD", old_head, c.id) except KeyError: c.parents = [] self.object_store.add_object(c) ok = self.refs.add_if_new("HEAD", c.id) if not ok: # Fail if the atomic compare-and-swap failed, leaving the commit and # all its objects as garbage. raise CommitError("HEAD changed during commit") return c.id
def create_commit(repo, files=None, tree=None, parent=None, author=AUTHOR, message="No message given"): object_store = repo.object_store if not tree: tree = Tree() for f in files: blob = Blob.from_string(f[2]) object_store.add_object(blob) tree.add(f[0], f[1], blob.id) commit = Commit() if parent: commit.parents = [parent] else: commit.parents = [] # Check that we have really updated the tree if parent: parent_commit = repo.get_object(parent) if parent_commit.tree == tree.id: raise NoChangesException() commit.tree = tree.id commit.author = commit.committer = author commit.commit_time = commit.author_time = get_ts() tz = parse_timezone('+0100')[0] commit.commit_timezone = commit.author_timezone = tz commit.encoding = "UTF-8" commit.message = message object_store.add_object(tree) object_store.add_object(commit) return commit
def commit(self, name, email='*****@*****.**', message='wip', parents=None): if not self.is_head: return False # initial-commit if not self.snapshot_commit: parents = [] elif not parents: parents = [self.snapshot_commit.id] if not self.snapshot_commit or self.root_node.git_object.id != self.snapshot_commit.tree: c = Commit() c.tree = self.root_node.git_object.id c.parents = parents c.author = c.committer = '%s <%s>' % (name.encode('utf-8'), email.encode('utf-8')) c.commit_time = c.author_time = int(time()) c.commit_timezone = c.author_timezone = 0 c.encoding = "UTF-8" c.message = message self.repo.object_store.add_object(c) self.repo.refs[self.ref] = c.id return c return False
def update_content(self, new_content, author, email, message): new_content = new_content.encode('UTF-8') author = author.encode('UTF-8') message = message.encode('UTF-8') email = email.encode('UTF-8') # create blob, add to existing tree blob = Blob.from_string(new_content) self.tree[self.title] = (0100644, blob.id) # commit commit = Commit() commit.tree = self.tree.id commit.parents = [self.head.id] commit.author = commit.committer = "%s <%s>" % (author, email) commit.commit_time = commit.author_time = int(time()) tz = parse_timezone('+0100')[0] # FIXME: get proper timezone commit.commit_timezone = commit.author_timezone = tz commit.encoding = 'UTF-8' commit.message = message # save everything object_store = self.repo.object_store object_store.add_object(blob) object_store.add_object(self.tree) object_store.add_object(commit) self.repo.refs['refs/heads/master'] = commit.id
def _create_commit(tree, reason='', branch=False, parents=None, request=None): """ Creates a new commit based on the provided information. """ commit = Commit() if request and 'flatpages.git.author_name' in request.registry.settings: author = request.registry.settings['flatpages.git.author_name'] else: author = 'Anonymous' if request and 'flatpages.git.author_email' in request.registry.settings: author_email = request.registry.settings['flatpages.git.author_email'] author = '{0} <{1}>'.format(author, author_email) else: if request: author = '{0} <anonymous@{0}>'.format(request.host) else: author = '{0} <anonymous@{0}example.com>' # TODO: Right now, all times are in UTC time. Even though everything should # use UTC time in a perfect world - this isn't the case in the real world. commit.commit_timezone = commit.author_timezone = parse_timezone('0000')[0] commit.commit_time = commit.author_time = int(time.time()) commit.author = commit.committer = author commit.tree = tree.id commit.encoding = 'UTF-8' commit.message = reason if parents: commit.parents = parents return commit
def test_send_pack_no_sideband64k_with_update_ref_error(self): # No side-bank-64k reported by server shouldn't try to parse # side band data pkts = [b'55dcc6bf963f922e1ed5c4bbaaefcfacef57b1d7 capabilities^{}' b'\x00 report-status delete-refs ofs-delta\n', b'', b"unpack ok", b"ng refs/foo/bar pre-receive hook declined", b''] for pkt in pkts: if pkt == b'': self.rin.write(b"0000") else: self.rin.write(("%04x" % (len(pkt)+4)).encode('ascii') + pkt) self.rin.seek(0) tree = Tree() commit = Commit() commit.tree = tree commit.parents = [] commit.author = commit.committer = b'test user' commit.commit_time = commit.author_time = 1174773719 commit.commit_timezone = commit.author_timezone = 0 commit.encoding = b'UTF-8' commit.message = b'test message' def determine_wants(refs): return {b'refs/foo/bar': commit.id, } def generate_pack_contents(have, want): return [(commit, None), (tree, ''), ] self.assertRaises(UpdateRefsError, self.client.send_pack, "blah", determine_wants, generate_pack_contents)
def _commit(tree_dict, message): head = _get_current_head() tree = _get_current_tree() for name, contents in list(tree_dict.items()): if contents is None: del tree[name] else: blob = Blob.from_string(contents) _repo.object_store.add_object(blob) tree[name] = (0o100644, blob.id) commit = Commit() commit.parents = [head.id] if head else [] commit.tree = tree.id commit.author = commit.committer = "{0} <{1}>".format(_config.get("user", "name"), _config.get("user", "email")) commit.author_time = commit.commit_time = int(time()) commit.author_timezone = commit.commit_timezone = 0 commit.encoding = "UTF-8" commit.message = message _repo.object_store.add_object(tree) _repo.object_store.add_object(commit) _repo["refs/heads/clask"] = commit.id
def delete_file(self, subdir, filename, commit_msg): try: subdir_tree = _walk_git_repo_tree(self.repo, self.current_tree, subdir) except KeyError: raise FileNotFoundException('No subdir named %r' % subdir) if not filename in subdir_tree: raise FileNotFoundException('%r not in %s' % (filename, subdir)) del subdir_tree[filename] # create new root tree tree = self.current_tree tree.add(stat.S_IFDIR, subdir, subdir_tree.id) # create commit # FIXME: factor this out! commit = Commit() commit.parents = [self.current_commit.id] commit.tree = tree.id commit.author = commit.committer = self.wiki_user commit.commit_time = commit.author_time = int(time.time()) commit.commit_timezone = commit.author_timezone = parse_timezone( time.timezone)[0] commit.encoding = 'UTF-8' commit.message = commit_msg.encode('utf-8') # store all objects self.repo.object_store.add_object(subdir_tree) self.repo.object_store.add_object(tree) self.repo.object_store.add_object(commit) # update the branch self.repo.refs[self.head] = commit.id
def create_commit(data, marker=b"Default", blob=None): if not blob: blob = Blob.from_string(b"The blob content " + marker) tree = Tree() tree.add(b"thefile_" + marker, 0o100644, blob.id) cmt = Commit() if data: assert isinstance(data[-1], Commit) cmt.parents = [data[-1].id] cmt.tree = tree.id author = b"John Doe " + marker + b" <*****@*****.**>" cmt.author = cmt.committer = author tz = parse_timezone(b"-0200")[0] cmt.commit_time = cmt.author_time = int(time()) cmt.commit_timezone = cmt.author_timezone = tz cmt.encoding = b"UTF-8" cmt.message = b"The commit message " + marker tag = Tag() tag.tagger = b"*****@*****.**" tag.message = b"Annotated tag" tag.tag_timezone = parse_timezone(b"-0200")[0] tag.tag_time = cmt.author_time tag.object = (Commit, cmt.id) tag.name = b"v_" + marker + b"_0.1" return blob, tree, tag, cmt
def create_commit(data, marker='Default', blob=None): if not blob: blob = Blob.from_string('The blob content %s' % marker) tree = Tree() tree.add("thefile_%s" % marker, 0o100644, blob.id) cmt = Commit() if data: assert isinstance(data[-1], Commit) cmt.parents = [data[-1].id] cmt.tree = tree.id author = "John Doe %s <*****@*****.**>" % marker cmt.author = cmt.committer = author tz = parse_timezone('-0200')[0] cmt.commit_time = cmt.author_time = int(time()) cmt.commit_timezone = cmt.author_timezone = tz cmt.encoding = "UTF-8" cmt.message = "The commit message %s" % marker tag = Tag() tag.tagger = "*****@*****.**" tag.message = "Annotated tag" tag.tag_timezone = parse_timezone('-0200')[0] tag.tag_time = cmt.author_time tag.object = (Commit, cmt.id) tag.name = "v_%s_0.1" % marker return blob, tree, tag, cmt
def create_commit(metadata, parents, tree_id): """Create a new Git commit object, and add it to the object store. Args: metadata: Dictionary containing metadata to construct the commit, including commit message and author data. parents: The parents of this commit. tree: The tree of files to use for this commit. Returns: New commit object. """ commit = Commit() commit.tree = tree_id commit.author = "%s <%s>" % (metadata["GIT_AUTHOR_NAME"], metadata["GIT_AUTHOR_EMAIL"]) commit.author_time = \ utc_time_from_string(metadata["GIT_AUTHOR_DATE"]) commit.author_timezone = 0 commit.committer = "%s <%s>" % (metadata["GIT_COMMITTER_NAME"], metadata["GIT_COMMITTER_EMAIL"]) commit.commit_time = \ utc_time_from_string(metadata["GIT_COMMITTER_DATE"]) commit.commit_timezone = 0 commit.encoding = "UTF-8" commit.message = metadata["MESSAGE"] commit.parents = parents gitrepo.object_store.add_object(commit) return commit
def commit_handler(self, cmd): """Process a CommitCommand.""" commit = Commit() if cmd.author is not None: author = cmd.author else: author = cmd.committer (author_name, author_email, author_timestamp, author_timezone) = author (committer_name, committer_email, commit_timestamp, commit_timezone) = cmd.committer commit.author = "%s <%s>" % (author_name, author_email) commit.author_timezone = author_timezone commit.author_time = int(author_timestamp) commit.committer = "%s <%s>" % (committer_name, committer_email) commit.commit_timezone = commit_timezone commit.commit_time = int(commit_timestamp) commit.message = cmd.message commit.parents = [] contents = {} commit.tree = commit_tree( self.repo.object_store, ((path, hexsha, mode) for (path, (mode, hexsha)) in contents.iteritems()) ) if self.last_commit is not None: commit.parents.append(self.last_commit) commit.parents += cmd.merges self.repo.object_store.add_object(commit) self.repo[cmd.ref] = commit.id self.last_commit = commit.id if cmd.mark: self.markers[cmd.mark] = commit.id
def commit_handler(self, cmd): """Process a CommitCommand.""" commit = Commit() if cmd.author is not None: author = cmd.author else: author = cmd.committer (author_name, author_email, author_timestamp, author_timezone) = author (committer_name, committer_email, commit_timestamp, commit_timezone) = cmd.committer commit.author = author_name + b" <" + author_email + b">" commit.author_timezone = author_timezone commit.author_time = int(author_timestamp) commit.committer = committer_name + b" <" + committer_email + b">" commit.commit_timezone = commit_timezone commit.commit_time = int(commit_timestamp) commit.message = cmd.message commit.parents = [] if cmd.from_: self._reset_base(cmd.from_) for filecmd in cmd.iter_files(): if filecmd.name == b"filemodify": if filecmd.data is not None: blob = Blob.from_string(filecmd.data) self.repo.object_store.add(blob) blob_id = blob.id else: assert filecmd.dataref.startswith(b":"), \ ("non-marker refs not supported yet (%r)" % filecmd.dataref) blob_id = self.markers[filecmd.dataref[1:]] self._contents[filecmd.path] = (filecmd.mode, blob_id) elif filecmd.name == b"filedelete": del self._contents[filecmd.path] elif filecmd.name == b"filecopy": self._contents[filecmd.dest_path] = self._contents[ filecmd.src_path] elif filecmd.name == b"filerename": self._contents[filecmd.new_path] = self._contents[ filecmd.old_path] del self._contents[filecmd.old_path] elif filecmd.name == b"filedeleteall": self._contents = {} else: raise Exception("Command %s not supported" % filecmd.name) commit.tree = commit_tree( self.repo.object_store, ((path, hexsha, mode) for (path, (mode, hexsha)) in self._contents.items())) if self.last_commit != ZERO_SHA: commit.parents.append(self.last_commit) for merge in cmd.merges: if merge.startswith(b':'): merge = self.markers[merge[1:]] commit.parents.append(merge) self.repo.object_store.add_object(commit) self.repo[cmd.ref] = commit.id self.last_commit = commit.id if cmd.mark: self.markers[cmd.mark] = commit.id
def delete_file(self, subdir, filename, commit_msg): try: subdir_tree = _walk_git_repo_tree(self.repo, self.current_tree, subdir) except KeyError: raise FileNotFoundException('No subdir named %r' % subdir) if not filename in subdir_tree: raise FileNotFoundException('%r not in %s' % (filename, subdir)) del subdir_tree[filename] # create new root tree tree = self.current_tree tree.add(stat.S_IFDIR, subdir, subdir_tree.id) # create commit # FIXME: factor this out! commit = Commit() commit.parents = [self.current_commit.id] commit.tree = tree.id commit.author = commit.committer = self.wiki_user commit.commit_time = commit.author_time = int(time.time()) commit.commit_timezone = commit.author_timezone = parse_timezone(time.timezone)[0] commit.encoding = 'UTF-8' commit.message = commit_msg.encode('utf-8') # store all objects self.repo.object_store.add_object(subdir_tree) self.repo.object_store.add_object(tree) self.repo.object_store.add_object(commit) # update the branch self.repo.refs[self.head] = commit.id
def _do_commit(self, index, author, message, ctime, parent_rev=None): committer = b'%s <>' % author.encode('utf8') commit = Commit() commit.tree = index.commit(self.repo.object_store) commit.author = commit.committer = committer commit.commit_time = commit.author_time = ctime commit.encoding = b'UTF-8' commit.commit_timezone = commit.author_timezone = 0 commit.message = message.encode('utf8') try: curr_head = self.repo.head() commit.parents = [curr_head] # if parent_rev and len(parent_rev) == 40: # commit.parents.append(parent_rev.encode('ascii')) except KeyError: curr_head = None self.repo.object_store.add_object(commit) self.repo.refs.set_if_equals(b'HEAD', curr_head, commit.id, message=b"commit: " + commit.message, committer=commit.committer, timestamp=ctime, timezone=0) index.write()
def test_send_pack_no_sideband64k_with_update_ref_error(self): # No side-bank-64k reported by server shouldn't try to parse # side band data pkts = ['55dcc6bf963f922e1ed5c4bbaaefcfacef57b1d7 capabilities^{}' '\x00 report-status delete-refs ofs-delta\n', '', "unpack ok", "ng refs/foo/bar pre-receive hook declined", ''] for pkt in pkts: if pkt == '': self.rin.write("0000") else: self.rin.write("%04x%s" % (len(pkt)+4, pkt)) self.rin.seek(0) tree = Tree() commit = Commit() commit.tree = tree commit.parents = [] commit.author = commit.committer = 'test user' commit.commit_time = commit.author_time = 1174773719 commit.commit_timezone = commit.author_timezone = 0 commit.encoding = 'UTF-8' commit.message = 'test message' def determine_wants(refs): return {'refs/foo/bar': commit.id, } def generate_pack_contents(have, want): return [(commit, None), (tree, ''), ] self.assertRaises(UpdateRefsError, self.client.send_pack, "blah", determine_wants, generate_pack_contents)
def test_send_pack_no_sideband64k_with_update_ref_error(self): # No side-bank-64k reported by server shouldn't try to parse # side band data pkts = [b'55dcc6bf963f922e1ed5c4bbaaefcfacef57b1d7 capabilities^{}' b'\x00 report-status delete-refs ofs-delta\n', b'', b"unpack ok", b"ng refs/foo/bar pre-receive hook declined", b''] for pkt in pkts: if pkt == b'': self.rin.write(b"0000") else: self.rin.write(("%04x" % (len(pkt)+4)).encode('ascii') + pkt) self.rin.seek(0) tree = Tree() commit = Commit() commit.tree = tree commit.parents = [] commit.author = commit.committer = b'test user' commit.commit_time = commit.author_time = 1174773719 commit.commit_timezone = commit.author_timezone = 0 commit.encoding = b'UTF-8' commit.message = b'test message' def update_refs(refs): return {b'refs/foo/bar': commit.id, } def generate_pack_data(have, want, ofs_delta=False): return pack_objects_to_data([(commit, None), (tree, ''), ]) self.assertRaises(UpdateRefsError, self.client.send_pack, "blah", update_refs, generate_pack_data)
def _update_file(self, name, subdir, filename, data, commit_msg): # first, create a new blob for the data blob = Blob.from_string(data.encode('utf-8')) # fetch the old tree object, add new page try: subdir_tree = _walk_git_repo_tree(self.repo, self.current_tree, subdir) except KeyError: # we need to create the subdir_tree as well, since it does not exist # yet subdir_tree = Tree() subdir_tree.add(_git_default_file_mode, filename, blob.id) # create new root tree tree = self.current_tree tree.add(stat.S_IFDIR, subdir, subdir_tree.id) # create commit commit = Commit() commit.parents = [self.current_commit.id] commit.tree = tree.id commit.author = commit.committer = self.wiki_user commit.commit_time = commit.author_time = int(time.time()) commit.commit_timezone = commit.author_timezone = parse_timezone(time.timezone)[0] commit.encoding = 'UTF-8' commit.message = commit_msg.encode('utf-8') # store all objects self.repo.object_store.add_object(blob) self.repo.object_store.add_object(subdir_tree) self.repo.object_store.add_object(tree) self.repo.object_store.add_object(commit) # update the branch self.repo.refs[self.head] = commit.id
def export_hg_commit(self, rev): self.ui.note(_("converting revision %s\n") % hex(rev)) oldenc = self.swap_out_encoding() ctx = self.repo.changectx(rev) extra = ctx.extra() commit = Commit() (time, timezone) = ctx.date() commit.author = self.get_git_author(ctx) commit.author_time = int(time) commit.author_timezone = -timezone if 'committer' in extra: # fixup timezone (name, timestamp, timezone) = extra['committer'].rsplit(' ', 2) commit.committer = name commit.commit_time = timestamp # work around a timezone format change if int(timezone) % 60 != 0: #pragma: no cover timezone = parse_timezone(timezone) # Newer versions of Dulwich return a tuple here if isinstance(timezone, tuple): timezone, neg_utc = timezone commit._commit_timezone_neg_utc = neg_utc else: timezone = -int(timezone) commit.commit_timezone = timezone else: commit.committer = commit.author commit.commit_time = commit.author_time commit.commit_timezone = commit.author_timezone commit.parents = [] for parent in self.get_git_parents(ctx): hgsha = hex(parent.node()) git_sha = self.map_git_get(hgsha) if git_sha: commit.parents.append(git_sha) commit.message = self.get_git_message(ctx) if 'encoding' in extra: commit.encoding = extra['encoding'] tree_sha = commit_tree(self.git.object_store, self.iterblobs(ctx)) commit.tree = tree_sha self.git.object_store.add_object(commit) self.map_set(commit.id, ctx.hex()) self.swap_out_encoding(oldenc) return commit.id
def commit_handler(self, cmd): """Process a CommitCommand.""" commit = Commit() if cmd.author is not None: author = cmd.author else: author = cmd.committer (author_name, author_email, author_timestamp, author_timezone) = author (committer_name, committer_email, commit_timestamp, commit_timezone) = cmd.committer commit.author = author_name + b" <" + author_email + b">" commit.author_timezone = author_timezone commit.author_time = int(author_timestamp) commit.committer = committer_name + b" <" + committer_email + b">" commit.commit_timezone = commit_timezone commit.commit_time = int(commit_timestamp) commit.message = cmd.message commit.parents = [] if cmd.from_: cmd.from_ = self.lookup_object(cmd.from_) self._reset_base(cmd.from_) for filecmd in cmd.iter_files(): if filecmd.name == b"filemodify": if filecmd.data is not None: blob = Blob.from_string(filecmd.data) self.repo.object_store.add(blob) blob_id = blob.id else: blob_id = self.lookup_object(filecmd.dataref) self._contents[filecmd.path] = (filecmd.mode, blob_id) elif filecmd.name == b"filedelete": del self._contents[filecmd.path] elif filecmd.name == b"filecopy": self._contents[filecmd.dest_path] = self._contents[ filecmd.src_path] elif filecmd.name == b"filerename": self._contents[filecmd.new_path] = self._contents[ filecmd.old_path] del self._contents[filecmd.old_path] elif filecmd.name == b"filedeleteall": self._contents = {} else: raise Exception("Command %s not supported" % filecmd.name) commit.tree = commit_tree( self.repo.object_store, ((path, hexsha, mode) for (path, (mode, hexsha)) in self._contents.items())) if self.last_commit != ZERO_SHA: commit.parents.append(self.last_commit) for merge in cmd.merges: commit.parents.append(self.lookup_object(merge)) self.repo.object_store.add_object(commit) self.repo[cmd.ref] = commit.id self.last_commit = commit.id if cmd.mark: self.markers[cmd.mark] = commit.id
def _do_commit(self, tree, parents, author, timezone, message): commit = Commit() commit.tree = tree if type(tree) in (str, unicode) else tree.id commit.parents = parents commit.author = commit.committer = author.encode(self._encoding) commit.commit_time = commit.author_time = int(time()) commit.commit_timezone = commit.author_timezone = timezone commit.encoding = self._encoding commit.message = message self._repo.object_store.add_object(commit) return commit.id
def make_base(self): c = Commit() c.tree = 'd80c186a03f423a81b39df39dc87fd269736ca86' c.parents = ['ab64bbdcc51b170d21588e5c5d391ee5c0c96dfd', '4cffe90e0a41ad3f5190079d7c8f036bde29cbe6'] c.author = 'James Westby <*****@*****.**>' c.committer = 'James Westby <*****@*****.**>' c.commit_time = 1174773719 c.author_time = 1174773719 c.commit_timezone = 0 c.author_timezone = 0 c.message = 'Merge ../b\n' return c
def commit(self): # XXX: evidence for the rest of # this functions is supposed not to exist # yes, its that # XXX: generate all objects at once and # add them as pack instead of legacy objects r = self.repo.repo store = r.object_store new_objects = [] names = sorted(self.contents) nametree = defaultdict(list) for name in names: base = name.strip('/') while base: nbase = os.path.dirname(base) nametree[nbase].append(base) base = nbase if self.base_commit: tree = r.tree(self.base_commit.commit.tree) tree._ensure_parsed() print tree._entries else: tree = Tree() for src, dest in self.renames: src = src.strip('/') dest = dest.strip('/') tree[dest] = tree[src] del tree[src] for name in names: blob = Blob() blob.data = self.contents[name] new_objects.append((blob, name)) tree.add(0555, os.path.basename(name), blob.id) new_objects.append((tree, '')) commit = Commit() if self.base_commit: commit.parents = [self.base_commit.commit.id] commit.tree = tree.id commit.message = self.extra['message'] commit.committer = self.author commit.commit_time = int(self.time_unix) commit.commit_timezone = self.time_offset commit.author = self.author commit.author_time = int(self.time_unix) commit.author_timezone = self.time_offset new_objects.append((commit, '')) store.add_objects(new_objects) self.repo.repo.refs['HEAD'] = commit.id
def commit(self, message): self._validate_unicode_text(message, 'commit message') c = Commit() c.parents = [ self.repository.lookup_bzr_revision_id(revid)[0] for revid in self.parents ] c.tree = commit_tree(self.store, self._iterblobs()) encoding = self._revprops.pop(u'git-explicit-encoding', 'utf-8') c.encoding = encoding.encode('ascii') c.committer = fix_person_identifier(self._committer.encode(encoding)) try: author = self._revprops.pop('author') except KeyError: try: authors = self._revprops.pop('authors').splitlines() except KeyError: author = self._committer else: if len(authors) > 1: raise Exception("Unable to convert multiple authors") elif len(authors) == 0: author = self._committer else: author = authors[0] c.author = fix_person_identifier(author.encode(encoding)) bugstext = self._revprops.pop('bugs', None) if bugstext is not None: message += "\n" for url, status in bugtracker.decode_bug_urls(bugstext): if status == bugtracker.FIXED: message += "Fixes: %s\n" % url elif status == bugtracker.RELATED: message += "Bug: %s\n" % url else: raise bugtracker.InvalidBugStatus(status) if self._revprops: raise NotImplementedError(self._revprops) c.commit_time = int(self._timestamp) c.author_time = int(self._timestamp) c.commit_timezone = self._timezone c.author_timezone = self._timezone c.message = message.encode(encoding) if (self._config_stack.get('create_signatures') == _mod_config.SIGN_ALWAYS): strategy = gpg.GPGStrategy(self._config_stack) c.gpgsig = strategy.sign(c.as_raw_string(), gpg.MODE_DETACH) self.store.add_object(c) self.repository.commit_write_group() self._new_revision_id = self._mapping.revision_id_foreign_to_bzr(c.id) return self._new_revision_id
def do_commit(): global droid, localrepo, repo if localrepo==None: droid.makeToast("Set local repository first!") else: object_store = repo.object_store progress_to_log() if repo["refs/heads/master"] == None: tree = Tree() else: tree = object_store[repo["refs/heads/master"].tree] if do_tree_for_commit(tree): object_store.add_object(tree) commit = Commit() commit.tree = tree.id if repo.refs["refs/heads/master"] == None: commit.parents = [] def_comment = "Initial commit" else: commit.parents = [repo.refs["refs/heads/master"]] def_comment = "" name = droid.fullQueryDetail("editName").result["text"] email = droid.fullQueryDetail("editEmail").result["text"] author = name + " <" + email + ">" commit.author = commit.committer = author commit.commit_time = commit.author_time = int(time()) tz = parse_timezone('+0000')[0] commit.commit_timezone = commit.author_timezone = tz commit.encoding = "UTF-8" commit.message = showinput("Message", "Enter commit message", def_comment) if commit.message: object_store.add_object(commit) repo.refs['refs/heads/master'] = commit.id else: droid.makeToast("Commit cancelled.") else: droid.makeToast("Nothing to commit.")
def commit(self): # FIXME: this breaks if git repository just got initialized and no # inital commit has been done before. # FIXME: the working copy/tree has to be updated as well otherwise the # newly commited file will be out of sync with the working copy # (maybe we have to add the file to the index/stage? check how # RabbitVCS does it.) # TODO: maybe commit should be a method of the file object so that one # could write: # fh = open("file", 'w') # fh.write("blabla") # fh.close() # fh.commit() if self.opened: blob = Blob.from_raw_chunks(Blob.type_num, self._fh.readlines()) else: raise FileNotOpenError # FIXME: get mode from physical file mode = 0100644 head = self.repo.refs['refs/heads/' + self.branch] # head = self.repo.head() prev_commit = self.repo[head] tree = self.repo[prev_commit.tree] tree[self.path] = (mode, blob.id) # populate Git commit object commit = Commit() commit.tree = tree.id commit.parents = [head] commit.author = commit.committer = self.author commit.commit_time = commit.author_time = int(time.time()) commit.commit_timezone = commit.author_timezone = 0 commit.encoding = "UTF-8" # FIXME: create useful commit message commit.message = "Committing %s" % self.path self.repo.object_store.add_object(blob) self.repo.object_store.add_object(tree) self.repo.object_store.add_object(commit) self.repo.refs['refs/heads/' + self.branch] = commit.id
def create_log(repo, contents, filename, overwrite=False): """creates a log with the specified content. This function creates a log file in the git repository specified by LOGS_PATH in settings.py. If a file with name filename exists, False is returned, unless overwrite=True. Arguments: contents the contents of the log, as a simple string filename the specific filename to use. overwrite whether or not to overwrite existing files. defaults to False, does change behavior when filename=None. Returns: False on failure, the filename to which the log was saved on success. Raises: GitFileError when the file exists while overwrite is False """ if not filename: return "Error: empty filename" if not contents: return "Error: empty contents" if type(contents) is list: contents=''.join(contents) if path.exists(path.join(LOGS_PATH, filename)) and not overwrite: return "Error: file exists, overwrite not specified" #create file blob = Blob.from_string(contents) tree = get_latest_tree(repo) tree[filename]=(default_perms, blob.id) commit = Commit() commit.tree=tree.id commit.parents=[repo.head()] commit.author = commit.committer = "Logwriter [email protected]" commit.commit_time = commit.author_time = int(time()) commit.commit_timezone = commit.author_timezone = parse_timezone('+0100') commit.encoding = "UTF-8" commit.message = "Writing log file %s"%(filename) store=repo.object_store store.add_object(blob) store.add_object(tree) store.add_object(commit) repo.refs['refs/heads/master'] = commit.id return True
def make_commit(repo, tree_id, message): """Build a commit object on the same pattern. Only changing values are required as parameters. """ commit = Commit() try: commit.parents = [repo.head()] except KeyError: # The initial commit has no parent pass commit.tree = tree_id commit.message = message commit.author = commit.committer = AUTHOR commit.commit_time = commit.author_time = int(time()) commit.commit_timezone = commit.author_timezone = TZ commit.encoding = ENCODING return commit
def make_commit(repo, tree, message, author, timezone, encoding="UTF-8"): """build a Commit object""" commit = Commit() try: commit.parents = [repo.head()] except KeyError: #the initial commit has no parent pass if isinstance(tree, dulwich.objects.Tree): tree_id = tree.id elif isinstance(tree, str): tree_id = tree commit.tree = tree_id commit.message = message commit.author = commit.committer = author commit.commit_time = commit.author_time = int(time()) commit.commit_timezone = commit.author_timezone = parse_timezone(timezone) commit.encoding = encoding return commit
def to_commit(self): new_commit = Commit() new_commit.parents = self.parent_ids new_commit.tree = self.tree.id new_commit.author = self.author new_commit.committer = self.committer new_commit.author_time = self.author_time new_commit.commit_time = self.commit_time new_commit.commit_timezone = self.commit_timezone new_commit.author_timezone = self.author_timezone new_commit.encoding = self.encoding new_commit.message = self.message.encode(self.encoding) return new_commit
def test_send_pack_new_ref(self): self.rin.write( '0064310ca9477129b8586fa2afc779c1f57cf64bba6c ' 'refs/heads/master\x00 report-status delete-refs ofs-delta\n' '0000000eunpack ok\n' '0019ok refs/heads/blah12\n' '0000') self.rin.seek(0) tree = Tree() commit = Commit() commit.tree = tree commit.parents = [] commit.author = commit.committer = 'test user' commit.commit_time = commit.author_time = 1174773719 commit.commit_timezone = commit.author_timezone = 0 commit.encoding = 'UTF-8' commit.message = 'test message' def determine_wants(refs): return { 'refs/heads/blah12': commit.id, 'refs/heads/master': '310ca9477129b8586fa2afc779c1f57cf64bba6c' } def generate_pack_contents(have, want): return [ (commit, None), (tree, ''), ] f = BytesIO() write_pack_objects(f, generate_pack_contents(None, None)) self.client.send_pack('/', determine_wants, generate_pack_contents) self.assertIn(self.rout.getvalue(), [ '007f0000000000000000000000000000000000000000 %s ' 'refs/heads/blah12\x00report-status ofs-delta0000%s' % (commit.id, f.getvalue()), '007f0000000000000000000000000000000000000000 %s ' 'refs/heads/blah12\x00ofs-delta report-status0000%s' % (commit.id, f.getvalue()) ])
def test_send_pack_new_ref(self): self.rin.write( b'0064310ca9477129b8586fa2afc779c1f57cf64bba6c ' b'refs/heads/master\x00 report-status delete-refs ofs-delta\n' b'0000000eunpack ok\n' b'0019ok refs/heads/blah12\n' b'0000') self.rin.seek(0) tree = Tree() commit = Commit() commit.tree = tree commit.parents = [] commit.author = commit.committer = b'test user' commit.commit_time = commit.author_time = 1174773719 commit.commit_timezone = commit.author_timezone = 0 commit.encoding = b'UTF-8' commit.message = b'test message' def update_refs(refs): return { b'refs/heads/blah12': commit.id, b'refs/heads/master': b'310ca9477129b8586fa2afc779c1f57cf64bba6c' } def generate_pack_data(have, want, ofs_delta=False): return pack_objects_to_data([ (commit, None), (tree, b''), ]) f = BytesIO() write_pack_data(f, *generate_pack_data(None, None)) self.client.send_pack(b'/', update_refs, generate_pack_data) self.assertIn(self.rout.getvalue(), [ b'007f0000000000000000000000000000000000000000 ' + commit.id + b' refs/heads/blah12\x00report-status ofs-delta0000' + f.getvalue(), b'007f0000000000000000000000000000000000000000 ' + commit.id + b' refs/heads/blah12\x00ofs-delta report-status0000' + f.getvalue() ])
def test_git_submodule_exists(self): repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: filea = Blob.from_string(b'file alalala') subtree = Tree() subtree[b'a'] = (stat.S_IFREG | 0o644, filea.id) c = Commit() c.tree = subtree.id c.committer = c.author = b'Somebody <*****@*****.**>' c.commit_time = c.author_time = 42342 c.commit_timezone = c.author_timezone = 0 c.parents = [] c.message = b'Subcommit' tree = Tree() tree[b'c'] = (S_IFGITLINK, c.id) os.mkdir(os.path.join(repo_dir, 'c')) repo.object_store.add_objects( [(o, None) for o in [tree]]) build_index_from_tree(repo.path, repo.index_path(), repo.object_store, tree.id) # Verify index entries index = repo.open_index() self.assertEqual(len(index), 1) # filea apath = os.path.join(repo.path, 'c/a') self.assertFalse(os.path.exists(apath)) # dir c cpath = os.path.join(repo.path, 'c') self.assertTrue(os.path.isdir(cpath)) self.assertEqual(index[b'c'][4], S_IFGITLINK) # mode self.assertEqual(index[b'c'][8], c.id) # sha
def test_send_pack_new_ref(self): self.rin.write( b'0064310ca9477129b8586fa2afc779c1f57cf64bba6c ' b'refs/heads/master\x00 report-status delete-refs ofs-delta\n' b'0000000eunpack ok\n' b'0019ok refs/heads/blah12\n' b'0000') self.rin.seek(0) tree = Tree() commit = Commit() commit.tree = tree commit.parents = [] commit.author = commit.committer = b'test user' commit.commit_time = commit.author_time = 1174773719 commit.commit_timezone = commit.author_timezone = 0 commit.encoding = b'UTF-8' commit.message = b'test message' def determine_wants(refs): return { b'refs/heads/blah12': commit.id, b'refs/heads/master': b'310ca9477129b8586fa2afc779c1f57cf64bba6c' } def generate_pack_data(have, want, ofs_delta=False): return pack_objects_to_data([(commit, None), (tree, b''), ]) f = BytesIO() write_pack_data(f, *generate_pack_data(None, None)) self.client.send_pack(b'/', determine_wants, generate_pack_data) self.assertIn( self.rout.getvalue(), [b'007f0000000000000000000000000000000000000000 ' + commit.id + b' refs/heads/blah12\x00report-status ofs-delta0000' + f.getvalue(), b'007f0000000000000000000000000000000000000000 ' + commit.id + b' refs/heads/blah12\x00ofs-delta report-status0000' + f.getvalue()])
def new(self, repo): """ Create a new version of a repo.Local object. :param repo: Instance of repo.Local. :return: New Version instance. """ #TODO: subclass Commit, pass parent as init param try: # create new commit instance and set metadata commit = Commit() author = os.environ.get('USER') commit.author = commit.committer = author commit.commit_time = commit.author_time = int(time()) tz = parse_timezone('-0200')[0] commit.commit_timezone = commit.author_timezone = tz commit.encoding = "UTF-8" commit.message = '' # set previous version as parent to this one parent = repo.versions(-1) if parent: commit.parents = [parent.id] # create new tree, add entries from previous version tree = Tree() curr = repo.versions(-1) if curr: for item in curr.items(): tree.addItem(item) commit.tree = tree.id # create new version, and add tree version = Version(repo=repo, commit=commit, tree=tree) return version except Exception, e: traceback.print_exc() return VersionError(e)
def test_git_submodule_exists(self): repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: filea = Blob.from_string(b'file alalala') subtree = Tree() subtree[b'a'] = (stat.S_IFREG | 0o644, filea.id) c = Commit() c.tree = subtree.id c.committer = c.author = b'Somebody <*****@*****.**>' c.commit_time = c.author_time = 42342 c.commit_timezone = c.author_timezone = 0 c.parents = [] c.message = b'Subcommit' tree = Tree() tree[b'c'] = (S_IFGITLINK, c.id) os.mkdir(os.path.join(repo_dir, 'c')) repo.object_store.add_objects( [(o, None) for o in [tree]]) build_index_from_tree( repo.path, repo.index_path(), repo.object_store, tree.id) # Verify index entries index = repo.open_index() self.assertEqual(len(index), 1) # filea apath = os.path.join(repo.path, 'c/a') self.assertFalse(os.path.exists(apath)) # dir c cpath = os.path.join(repo.path, 'c') self.assertTrue(os.path.isdir(cpath)) self.assertEqual(index[b'c'][4], S_IFGITLINK) # mode self.assertEqual(index[b'c'][8], c.id) # sha
def test_send_pack_new_ref(self): self.rin.write( '0064310ca9477129b8586fa2afc779c1f57cf64bba6c ' 'refs/heads/master\x00 report-status delete-refs ofs-delta\n' '0000000eunpack ok\n' '0019ok refs/heads/blah12\n' '0000') self.rin.seek(0) tree = Tree() commit = Commit() commit.tree = tree commit.parents = [] commit.author = commit.committer = 'test user' commit.commit_time = commit.author_time = 1174773719 commit.commit_timezone = commit.author_timezone = 0 commit.encoding = 'UTF-8' commit.message = 'test message' def determine_wants(refs): return { 'refs/heads/blah12': commit.id, 'refs/heads/master': '310ca9477129b8586fa2afc779c1f57cf64bba6c' } def generate_pack_contents(have, want): return [(commit, None), (tree, ''), ] f = BytesIO() write_pack_objects(f, generate_pack_contents(None, None)) self.client.send_pack('/', determine_wants, generate_pack_contents) self.assertIn( self.rout.getvalue(), ['007f0000000000000000000000000000000000000000 %s ' 'refs/heads/blah12\x00report-status ofs-delta0000%s' % (commit.id, f.getvalue()), '007f0000000000000000000000000000000000000000 %s ' 'refs/heads/blah12\x00ofs-delta report-status0000%s' % (commit.id, f.getvalue())])
def write(self, data): commit = Commit() # commit metadata author = b"tinydb" commit.author = commit.committer = author commit.commit_time = commit.author_time = int(time.time()) tz = time.timezone if (time.localtime().tm_isdst) else time.altzone commit.commit_timezone = commit.author_timezone = tz commit.encoding = b'UTF-8' commit.message = ( 'Updated by tinydb-git {}'.format(__version__).encode('utf8')) # prepare blob blob = Blob.from_string(self._serialize(data)) try: parent_commit = self.repo[self._refname] except KeyError: # branch does not exist, start with an empty tree tree = Tree() else: commit.parents = [parent_commit.id] tree = self.repo[parent_commit.tree] # no subdirs in filename, add directly to tree tree.add(self.filename, 0o100644, blob.id) commit.tree = tree.id # add objects self.repo.object_store.add_object(blob) self.repo.object_store.add_object(tree) self.repo.object_store.add_object(commit) # update refs self.repo.refs[self._refname] = commit.id
def write(self, data): commit = Commit() # commit metadata author = b"tinydb" commit.author = commit.committer = author commit.commit_time = commit.author_time = int(time.time()) tz = time.timezone if (time.localtime().tm_isdst) else time.altzone commit.commit_timezone = commit.author_timezone = tz commit.encoding = b'UTF-8' commit.message = ('Updated by tinydb-git {}'.format(__version__) .encode('utf8')) # prepare blob blob = Blob.from_string(self._serialize(data)) try: parent_commit = self.repo[self._refname] except KeyError: # branch does not exist, start with an empty tree tree = Tree() else: commit.parents = [parent_commit.id] tree = self.repo[parent_commit.tree] # no subdirs in filename, add directly to tree tree.add(self.filename, 0o100644, blob.id) commit.tree = tree.id # add objects self.repo.object_store.add_object(blob) self.repo.object_store.add_object(tree) self.repo.object_store.add_object(commit) # update refs self.repo.refs[self._refname] = commit.id
def _update_file(self, name, subdir, filename, data, commit_msg): # first, create a new blob for the data blob = Blob.from_string(data.encode('utf-8')) # fetch the old tree object, add new page try: subdir_tree = _walk_git_repo_tree(self.repo, self.current_tree, subdir) except KeyError: # we need to create the subdir_tree as well, since it does not exist # yet subdir_tree = Tree() subdir_tree.add(_git_default_file_mode, filename, blob.id) # create new root tree tree = self.current_tree tree.add(stat.S_IFDIR, subdir, subdir_tree.id) # create commit commit = Commit() commit.parents = [self.current_commit.id] commit.tree = tree.id commit.author = commit.committer = self.wiki_user commit.commit_time = commit.author_time = int(time.time()) commit.commit_timezone = commit.author_timezone = parse_timezone( time.timezone)[0] commit.encoding = 'UTF-8' commit.message = commit_msg.encode('utf-8') # store all objects self.repo.object_store.add_object(blob) self.repo.object_store.add_object(subdir_tree) self.repo.object_store.add_object(tree) self.repo.object_store.add_object(commit) # update the branch self.repo.refs[self.head] = commit.id
def create_todo_commit(self, text, message, author_name, author_email, parent_id=None): author = '{} <{}>'.format(author_name, author_email).encode('utf8') # create TODO branch blob = Blob.from_string(text.encode('utf8')) tree = Tree() tree.add(b'TODO', 0o100644, blob.id) commit = Commit() commit.tree = tree.id commit.message = message.encode('utf8') commit.encoding = 'UTF-8' if parent_id: commit.parents = [parent_id] tz = arrow.now().utcoffset().seconds commit.author = commit.committer = author commit.author_time = commit.commit_time = int(time()) commit.commit_timezone = commit.author_timezone = tz # add objects to repo return commit, tree, blob
def commit(self, message, author=None): commit = Commit() commit.tree = self.tree.id if author is None: config = self.repo.get_config_stack() author = self.repo._get_user_identity(config) else: author = author.encode(self.encoding) commit.author = commit.committer = author commit.commit_time = commit.author_time = int(time()) tz = timezone commit.commit_timezone = commit.author_timezone = tz commit.message = message.encode(self.encoding) commit.encoding = self.encoding.encode('ascii') if self.org_commit_id: commit.parents = [self.org_commit_id] commit_id = commit.id self.changed_objects[commit_id] = commit self.repo.object_store.add_objects([ (obj, None) for obj in self.changed_objects.values() ]) self.repo.refs.set_if_equals(self.branch, self.org_commit_id, commit_id) if hasattr(self.repo, 'has_index') and self.repo.has_index(): # Apply patch to working tree. try: subprocess.call( ['git', 'cherry-pick', commit_id, '--no-commit'], cwd=self.repo.path) except Exception: logging.getLogger(__name__).exception( 'Error updating working tree:') self.reset()
def export_hg_commit(self, rev, exporter): self.ui.note(_("converting revision %s\n") % hex_(rev)) oldenc = self.swap_out_encoding() ctx = self.repo.changectx(rev) extra = ctx.extra() commit = Commit() (time, timezone) = ctx.date() # work around to bad timezone offets - dulwich does not handle # sub minute based timezones. In the one known case, it was a # manual edit that led to the unusual value. Based on that, # there is no reason to round one way or the other, so do the # simplest and round down. timezone -= (timezone % 60) commit.author = self.get_git_author(ctx) commit.author_time = int(time) commit.author_timezone = -timezone if 'committer' in extra: # fixup timezone (name, timestamp, timezone) = extra['committer'].rsplit(' ', 2) commit.committer = name commit.commit_time = timestamp # work around a timezone format change if int(timezone) % 60 != 0: #pragma: no cover timezone = parse_timezone(timezone) # Newer versions of Dulwich return a tuple here if isinstance(timezone, tuple): timezone, neg_utc = timezone commit._commit_timezone_neg_utc = neg_utc else: timezone = -int(timezone) commit.commit_timezone = timezone else: commit.committer = commit.author commit.commit_time = commit.author_time commit.commit_timezone = commit.author_timezone commit.parents = [] for parent in self.get_git_parents(ctx): hgsha = hex_(parent.node()) git_sha = self.map_git_get(hgsha) if git_sha: if git_sha not in self.git.object_store: raise hgutil.Abort( _('Parent SHA-1 not present in Git' 'repo: %s' % git_sha)) commit.parents.append(git_sha) commit.message = self.get_git_message(ctx) if 'encoding' in extra: commit.encoding = extra['encoding'] for obj, nodeid in exporter.update_changeset(ctx): self.git.object_store.add_object(obj) tree_sha = exporter.root_tree_sha if tree_sha not in self.git.object_store: raise hgutil.Abort( _('Tree SHA-1 not present in Git repo: %s' % tree_sha)) commit.tree = tree_sha self.git.object_store.add_object(commit) self.map_set(commit.id, ctx.hex()) self.swap_out_encoding(oldenc) return commit.id
def do_commit(self, message=None, committer=None, author=None, commit_timestamp=None, commit_timezone=None, author_timestamp=None, author_timezone=None, tree=None, encoding=None, ref=b'HEAD', merge_heads=None): """Create a new commit. :param message: Commit message :param committer: Committer fullname :param author: Author fullname (defaults to committer) :param commit_timestamp: Commit timestamp (defaults to now) :param commit_timezone: Commit timestamp timezone (defaults to GMT) :param author_timestamp: Author timestamp (defaults to commit timestamp) :param author_timezone: Author timestamp timezone (defaults to commit timestamp timezone) :param tree: SHA1 of the tree root to use (if not specified the current index will be committed). :param encoding: Encoding :param ref: Optional ref to commit to (defaults to current branch) :param merge_heads: Merge heads (defaults to .git/MERGE_HEADS) :return: New commit SHA1 """ import time c = Commit() if tree is None: index = self.open_index() c.tree = index.commit(self.object_store) else: if len(tree) != 40: raise ValueError("tree must be a 40-byte hex sha string") c.tree = tree if merge_heads is None: # FIXME: Read merge heads from .git/MERGE_HEADS merge_heads = [] # TODO: Allow username to be missing, and get it from .git/config if committer is None: raise ValueError("committer not set") c.committer = committer if commit_timestamp is None: commit_timestamp = time.time() c.commit_time = int(commit_timestamp) if commit_timezone is None: # FIXME: Use current user timezone rather than UTC commit_timezone = 0 c.commit_timezone = commit_timezone if author is None: author = committer c.author = author if author_timestamp is None: author_timestamp = commit_timestamp c.author_time = int(author_timestamp) if author_timezone is None: author_timezone = commit_timezone c.author_timezone = author_timezone if encoding is not None: c.encoding = encoding if message is None: # FIXME: Try to read commit message from .git/MERGE_MSG raise ValueError("No commit message specified") c.message = message try: old_head = self.refs[ref] c.parents = [old_head] + merge_heads self.object_store.add_object(c) ok = self.refs.set_if_equals(ref, old_head, c.id) except KeyError: c.parents = merge_heads self.object_store.add_object(c) ok = self.refs.add_if_new(ref, c.id) if not ok: # Fail if the atomic compare-and-swap failed, leaving the commit and # all its objects as garbage. raise CommitError("%s changed during commit" % (ref,)) return c.id
def __setitem__(self, path, raw): # XXX: I don't have much idea, what I'm doing here and I might # just corrupt your repository... # Mark directory as special (None, None) marker value if raw is None: super(Head, self).__setitem__(path, (None, None)) return # Get old mode or use the default try: mode = super(Head, self).__getitem__(path)[1] except KeyError: mode = 0100644 # Get existing entries for the content tree entries = [(key, sha_mode[0], cleanup_mode(sha_mode[1])) for key, sha_mode in super(Head, self).iteritems() if sha_mode[0] is not None and key is not path] # Get author # TODO: refactor to use plone.api or maybe use product_config from Products.CMFCore.utils import getToolByName portal_members = getToolByName(getSite(), 'portal_membership') member = portal_members.getAuthenticatedMember() author = '{0:s} <{1:s}>'.format( member.getProperty('fullname', '') or member.getId(), member.getProperty('email', '') or '*****@*****.**' ) # Get timezone tz_diff = dateutil.tz.tzlocal().utcoffset(datetime.datetime.now()) # Create commit commit = Commit() commit.author = author commit.committer = commit.author commit.commit_time = int(time.time()) commit.author_time = commit.commit_time commit.commit_timezone = tz_diff.seconds commit.author_timezone = tz_diff.seconds if tz_diff < datetime.timedelta(0): commit._author_timezone_neg_utc = True commit._commit_timezone_neg_utc = True commit.encoding = 'UTF-8' commit.message = 'Update {0:s}'.format(path) commit.parents = [self._head] # Create blob and commit tree blob = Blob.from_string(raw) entries.append((path, blob.id, cleanup_mode(mode))) commit.tree = commit_tree(self._repo.object_store, entries) # Save blob and commit self._repo.object_store.add_object(blob) self._repo.object_store.add_object(commit) def determine_wants(haves): # Set new head for the branch return {self.__name__: commit.id} # Push to remote refs = self.__parent__._client.send_pack( self.__parent__._host_path, determine_wants, self._repo.object_store.generate_pack_contents, progress=logger.info ) # Update heads for ref, sha in refs.items(): if sha in self._repo.object_store: self._repo.refs[ref] = sha # Update "index" super(Head, self).__setitem__(path, (blob.id, mode))
def __setitem__(self, path, raw): # XXX: I don't have much idea, what I'm doing here and I might # just corrupt your repository... # Mark directory as special (None, None) marker value if raw is None: super(Head, self).__setitem__(path, (None, None)) return # Get old mode or use the default try: mode = super(Head, self).__getitem__(path)[1] except KeyError: mode = 0100644 # Get existing entries for the content tree entries = [(key, sha_mode[0], cleanup_mode(sha_mode[1])) for key, sha_mode in super(Head, self).iteritems() if sha_mode[0] is not None and key is not path] # Get author # TODO: refactor to use plone.api or maybe use product_config from Products.CMFCore.utils import getToolByName portal_members = getToolByName(getSite(), 'portal_membership') member = portal_members.getAuthenticatedMember() author = '{0:s} <{1:s}>'.format( member.getProperty('fullname', '') or member.getId(), member.getProperty('email', '') or '*****@*****.**') # Get timezone tz_diff = dateutil.tz.tzlocal().utcoffset(datetime.datetime.now()) # Create commit commit = Commit() commit.author = author commit.committer = commit.author commit.commit_time = int(time.time()) commit.author_time = commit.commit_time commit.commit_timezone = tz_diff.seconds commit.author_timezone = tz_diff.seconds if tz_diff < datetime.timedelta(0): commit._author_timezone_neg_utc = True commit._commit_timezone_neg_utc = True commit.encoding = 'UTF-8' commit.message = 'Update {0:s}'.format(path) commit.parents = [self._head] # Create blob and commit tree blob = Blob.from_string(raw) entries.append((path, blob.id, cleanup_mode(mode))) commit.tree = commit_tree(self._repo.object_store, entries) # Save blob and commit self._repo.object_store.add_object(blob) self._repo.object_store.add_object(commit) def determine_wants(haves): # Set new head for the branch return {self.__name__: commit.id} # Push to remote refs = self.__parent__._client.send_pack( self.__parent__._host_path, determine_wants, self._repo.object_store.generate_pack_contents, progress=logger.info) # Update heads for ref, sha in refs.items(): if sha in self._repo.object_store: self._repo.refs[ref] = sha # Update "index" super(Head, self).__setitem__(path, (blob.id, mode))
def do_commit(self, message=None, committer=None, author=None, commit_timestamp=None, commit_timezone=None, author_timestamp=None, author_timezone=None, tree=None, encoding=None, ref=b'HEAD', merge_heads=None): """Create a new commit. :param message: Commit message :param committer: Committer fullname :param author: Author fullname (defaults to committer) :param commit_timestamp: Commit timestamp (defaults to now) :param commit_timezone: Commit timestamp timezone (defaults to GMT) :param author_timestamp: Author timestamp (defaults to commit timestamp) :param author_timezone: Author timestamp timezone (defaults to commit timestamp timezone) :param tree: SHA1 of the tree root to use (if not specified the current index will be committed). :param encoding: Encoding :param ref: Optional ref to commit to (defaults to current branch) :param merge_heads: Merge heads (defaults to .git/MERGE_HEADS) :return: New commit SHA1 """ import time c = Commit() if tree is None: index = self.open_index() c.tree = index.commit(self.object_store) else: if len(tree) != 40: raise ValueError("tree must be a 40-byte hex sha string") c.tree = tree try: self.hooks['pre-commit'].execute() except HookError as e: raise CommitError(e) except KeyError: # no hook defined, silent fallthrough pass if merge_heads is None: # FIXME: Read merge heads from .git/MERGE_HEADS merge_heads = [] if committer is None: # FIXME: Support GIT_COMMITTER_NAME/GIT_COMMITTER_EMAIL environment # variables committer = self._get_user_identity() c.committer = committer if commit_timestamp is None: # FIXME: Support GIT_COMMITTER_DATE environment variable commit_timestamp = time.time() c.commit_time = int(commit_timestamp) if commit_timezone is None: # FIXME: Use current user timezone rather than UTC commit_timezone = 0 c.commit_timezone = commit_timezone if author is None: # FIXME: Support GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL environment # variables author = committer c.author = author if author_timestamp is None: # FIXME: Support GIT_AUTHOR_DATE environment variable author_timestamp = commit_timestamp c.author_time = int(author_timestamp) if author_timezone is None: author_timezone = commit_timezone c.author_timezone = author_timezone if encoding is not None: c.encoding = encoding if message is None: # FIXME: Try to read commit message from .git/MERGE_MSG raise ValueError("No commit message specified") try: c.message = self.hooks['commit-msg'].execute(message) if c.message is None: c.message = message except HookError as e: raise CommitError(e) except KeyError: # no hook defined, message not modified c.message = message if ref is None: # Create a dangling commit c.parents = merge_heads self.object_store.add_object(c) else: try: old_head = self.refs[ref] c.parents = [old_head] + merge_heads self.object_store.add_object(c) ok = self.refs.set_if_equals(ref, old_head, c.id) except KeyError: c.parents = merge_heads self.object_store.add_object(c) ok = self.refs.add_if_new(ref, c.id) if not ok: # Fail if the atomic compare-and-swap failed, leaving the commit and # all its objects as garbage. raise CommitError("%s changed during commit" % (ref,)) try: self.hooks['post-commit'].execute() except HookError as e: # silent failure warnings.warn("post-commit hook failed: %s" % e, UserWarning) except KeyError: # no hook defined, silent fallthrough pass return c.id
def do_commit(self, message=None, committer=None, author=None, commit_timestamp=None, commit_timezone=None, author_timestamp=None, author_timezone=None, tree=None, encoding=None, ref=b'HEAD', merge_heads=None): """Create a new commit. :param message: Commit message :param committer: Committer fullname :param author: Author fullname (defaults to committer) :param commit_timestamp: Commit timestamp (defaults to now) :param commit_timezone: Commit timestamp timezone (defaults to GMT) :param author_timestamp: Author timestamp (defaults to commit timestamp) :param author_timezone: Author timestamp timezone (defaults to commit timestamp timezone) :param tree: SHA1 of the tree root to use (if not specified the current index will be committed). :param encoding: Encoding :param ref: Optional ref to commit to (defaults to current branch) :param merge_heads: Merge heads (defaults to .git/MERGE_HEADS) :return: New commit SHA1 """ import time c = Commit() if tree is None: index = self.open_index() c.tree = index.commit(self.object_store) else: if len(tree) != 40: raise ValueError("tree must be a 40-byte hex sha string") c.tree = tree try: self.hooks['pre-commit'].execute() except HookError as e: raise CommitError(e) except KeyError: # no hook defined, silent fallthrough pass if merge_heads is None: # FIXME: Read merge heads from .git/MERGE_HEADS merge_heads = [] if committer is None: # FIXME: Support GIT_COMMITTER_NAME/GIT_COMMITTER_EMAIL environment # variables committer = self._get_user_identity() c.committer = committer if commit_timestamp is None: # FIXME: Support GIT_COMMITTER_DATE environment variable commit_timestamp = time.time() c.commit_time = int(commit_timestamp) if commit_timezone is None: # FIXME: Use current user timezone rather than UTC commit_timezone = 0 c.commit_timezone = commit_timezone if author is None: # FIXME: Support GIT_AUTHOR_NAME/GIT_AUTHOR_EMAIL environment # variables author = committer c.author = author if author_timestamp is None: # FIXME: Support GIT_AUTHOR_DATE environment variable author_timestamp = commit_timestamp c.author_time = int(author_timestamp) if author_timezone is None: author_timezone = commit_timezone c.author_timezone = author_timezone if encoding is not None: c.encoding = encoding if message is None: # FIXME: Try to read commit message from .git/MERGE_MSG raise ValueError("No commit message specified") try: c.message = self.hooks['commit-msg'].execute(message) if c.message is None: c.message = message except HookError as e: raise CommitError(e) except KeyError: # no hook defined, message not modified c.message = message if ref is None: # Create a dangling commit c.parents = merge_heads self.object_store.add_object(c) else: try: old_head = self.refs[ref] c.parents = [old_head] + merge_heads self.object_store.add_object(c) ok = self.refs.set_if_equals(ref, old_head, c.id) except KeyError: c.parents = merge_heads self.object_store.add_object(c) ok = self.refs.add_if_new(ref, c.id) if not ok: # Fail if the atomic compare-and-swap failed, leaving the # commit and all its objects as garbage. raise CommitError("%s changed during commit" % (ref,)) try: self.hooks['post-commit'].execute() except HookError as e: # silent failure warnings.warn("post-commit hook failed: %s" % e, UserWarning) except KeyError: # no hook defined, silent fallthrough pass return c.id
def do_commit(self, message='', author=None, committer=None, branch='master', parent=None): if isinstance(message, unicode): message = message.encode('utf-8') repo = self.repo try: parent = self._get_commit(parent, branch) root = repo[parent.tree] except BranchDoesNotExist: if branch == 'master': # initial commit root = Tree() else: raise cache = {} paths = set() objects = set() for path, (action, data) in self.changes.iteritems(): path = clean_path(path) paths.add(path) dirname, filename = os.path.split(path) trees = self._collect(root, dirname, cache) if action == WRITE: blob = Blob.from_string(data) trees[-1][2][filename] = (self.file_mode, blob.id) cache[blob.id] = blob elif action == DELETE: del trees[-1][2][filename] elif action == RENAME: old = self._collect(root, data, cache) mode, name, obj = old[-1] del old[-2][2][name] trees[-1][2][filename] = (mode, obj.id) cache.update(self._link(old[:-1])) paths.add(data) cache.update(self._link(trees)) else: objects.add(root) # collect all objects that have to be committed for path in paths: objects.update( [obj for mode, name, obj in self._collect(root, path, cache)]) # create the commit c = Commit() if parent: c.parents = [parent.id] c.tree = root.id c.committer = committer or self.committer c.author = author or c.committer t = time.localtime() c.commit_time = c.author_time = int(time.mktime(t)) c.commit_timezone = c.author_timezone = t.tm_isdst * 3600 - time.timezone c.encoding = "UTF-8" c.message = message objects.add(c) # write everything to disk for obj in objects: repo.object_store.add_object(obj) repo.refs['refs/heads/%s' % branch] = c.id return DulwichCommit(self, c)
def edit(self, content=None, username=None, *virtual_path, **keywords): '''id: the git id of the blob before it was edited branch: master (default)''' #setup the defaults branch = "master" url = ManagedPath(virtual_path) if "branch" in keywords: branch = keywords["branch"] sha = self.sha print "sha is: ", sha print "keywords: ", keywords commit = sha print "content is: ", content print "self.filename is: ", self.filename if content is None: repo = Repo(self.package.path()) set_head(repo, branch) if not sha: print "repo.head() = ", repo.head() sha = dulwich.object_store.tree_lookup_path(repo.get_object, repo.get_object(repo.head()).tree, self.filename)[1] obj = repo.get_object(sha) contents = obj.as_pretty_string() return_contents = "<form action=\"" + cherrypy.url() + "\" method=\"POST\">" return_contents = return_contents + "<textarea name=content rows='20' cols='120'>" + contents + "</textarea><br />" #if the user isn't logged in ... if not hasattr(cherrypy.session, "login"): return_contents = return_contents + "username: <input type=text name=username value=\"anonymous\"><br />" if sha: return_contents = return_contents + "<input type=hidden name=id value=\"" + sha + "\">" return_contents = return_contents + "<input type=hidden name=\"branch\" value=\"" + branch + "\">" return_contents = return_contents + "<input type=submit name=submit value=edit></form>" self.content = return_contents self.branch = branch return self.respond() elif (sha or branch): #it's been edited if username==None and hasattr(cherrypy.session, "login"): if cherrypy.session.login==None: raise ValueError, "FileViewer.edit: no username supplied" elif username==None or username=="anonymous": anon = True #whether or not the user is anonymous if SESSION_KEY in cherrypy.session.keys(): username = cherrypy.session[SESSION_KEY].username anon = False else: username = "******" #at least until we get access control lists working if anon: if branch=="master": #don't let anonymous users modify branch "master" branch = "anonymous" branch = "anonymous" #make the blob blob = Blob.from_string(content) repo = Repo(self.package.path()) #change to the right branch last_head = repo.head() set_head(repo, "master") last_commit = repo.get_object(repo.head()) tree = repo.tree(repo.get_object(repo.head()).tree) #set the file tree[self.filename] = (0100644, blob.id) #make the commit commit = Commit() commit.tree = tree.id commit.parents = [last_head] commit.author = commit.committer = username commit.commit_time = commit.author_time = int(time.time()) commit.commit_timezone = commit.author_timezone = parse_timezone("-0600") commit.encoding = "UTF-8" commit.message = "not implemented yet" repo.object_store.add_object(blob) repo.object_store.add_object(tree) repo.object_store.add_object(commit) repo.refs["refs/heads/" + branch] = commit.id repo.refs["HEAD"] = "ref: refs/heads/" + branch new_link = "<a href=\"/package/" + self.package.name + ":" + branch + "/" + self.filename + "/" + blob.id + "\">go to the new version</a>" self.new_link = new_link self.content = add_newlines("edited (name=%s, branch=%s, sha=%s) new link: %s\n\n\n" % (username, branch, sha, new_link)) self.content = self.content + "<pre>" + content + "</pre>" self.branch = branch return self.respond()
# again, not in the object store yet store.add_object(commit) # nothing points at this Tree yet! # ...so, we will add a "master" branch repo.refs[b'refs/heads/master'] = commit.id print("Head: {}".format(repo.head().decode('ascii'))) # next, create another commit, changing the contents of our file b2 = Blob.from_string(b"Blobfish are fish, not people\n") t2 = Tree() t2.add(b"a_file.txt", 0o100644, b2.id) c2 = Commit() c2.tree = t2 c2.parents = [commit.id] # note: parents, not parent! c2.author = c2.committer = b"meejah <*****@*****.**>" c2.commit_time = c2.author_time = int(time()) # seconds since epoch c2.commit_timezone = c2.author_timezone = -7 * (60 * 60) # seconds offset; MST c2.encoding = b"utf8" c2.message = b"blobfish are aquatic animals" print(" blob: {}".format(b2.sha().hexdigest())) print(" tree: {}".format(t2.sha().hexdigest())) print("commit: {}".format(c2.sha().hexdigest())) store.add_object(b2) store.add_object(t2) store.add_object(c2) # actually extend master branch
def do_commit(self, message=None, committer=None, author=None, commit_timestamp=None, commit_timezone=None, author_timestamp=None, author_timezone=None, tree=None, encoding=None, ref='HEAD', merge_heads=None): """Create a new commit. :param message: Commit message :param committer: Committer fullname :param author: Author fullname (defaults to committer) :param commit_timestamp: Commit timestamp (defaults to now) :param commit_timezone: Commit timestamp timezone (defaults to GMT) :param author_timestamp: Author timestamp (defaults to commit timestamp) :param author_timezone: Author timestamp timezone (defaults to commit timestamp timezone) :param tree: SHA1 of the tree root to use (if not specified the current index will be committed). :param encoding: Encoding :param ref: Optional ref to commit to (defaults to current branch) :param merge_heads: Merge heads (defaults to .git/MERGE_HEADS) :return: New commit SHA1 """ import time c = Commit() if tree is None: index = self.open_index() c.tree = index.commit(self.object_store) else: if len(tree) != 40: raise ValueError("tree must be a 40-byte hex sha string") c.tree = tree if merge_heads is None: # FIXME: Read merge heads from .git/MERGE_HEADS merge_heads = [] # TODO: Allow username to be missing, and get it from .git/config if committer is None: raise ValueError("committer not set") c.committer = committer if commit_timestamp is None: commit_timestamp = time.time() c.commit_time = int(commit_timestamp) if commit_timezone is None: # FIXME: Use current user timezone rather than UTC commit_timezone = 0 c.commit_timezone = commit_timezone if author is None: author = committer c.author = author if author_timestamp is None: author_timestamp = commit_timestamp c.author_time = int(author_timestamp) if author_timezone is None: author_timezone = commit_timezone c.author_timezone = author_timezone if encoding is not None: c.encoding = encoding if message is None: # FIXME: Try to read commit message from .git/MERGE_MSG raise ValueError("No commit message specified") c.message = message try: old_head = self.refs[ref] c.parents = [old_head] + merge_heads self.object_store.add_object(c) ok = self.refs.set_if_equals(ref, old_head, c.id) except KeyError: c.parents = merge_heads self.object_store.add_object(c) ok = self.refs.add_if_new(ref, c.id) if not ok: # Fail if the atomic compare-and-swap failed, leaving the commit and # all its objects as garbage. raise CommitError("%s changed during commit" % (ref,)) return c.id
def export_commit(self, rev, tree_sha, parent_lookup, lossy, verifiers): """Turn a Bazaar revision in to a Git commit :param tree_sha: Tree sha for the commit :param parent_lookup: Function for looking up the GIT sha equiv of a bzr revision :param lossy: Whether to store roundtripping information. :param verifiers: Verifiers info :return dulwich.objects.Commit represent the revision: """ from dulwich.objects import Commit, Tag commit = Commit() commit.tree = tree_sha if not lossy: metadata = CommitSupplement() metadata.verifiers = verifiers else: metadata = None parents = [] for p in rev.parent_ids: try: git_p = parent_lookup(p) except KeyError: git_p = None if metadata is not None: metadata.explicit_parent_ids = rev.parent_ids if git_p is not None: if len(git_p) != 40: raise AssertionError("unexpected length for %r" % git_p) parents.append(git_p) commit.parents = parents try: encoding = rev.properties[u'git-explicit-encoding'] except KeyError: encoding = rev.properties.get(u'git-implicit-encoding', 'utf-8') try: commit.encoding = rev.properties[u'git-explicit-encoding'].encode( 'ascii') except KeyError: pass commit.committer = fix_person_identifier(rev.committer.encode( encoding)) commit.author = fix_person_identifier( rev.get_apparent_authors()[0].encode(encoding)) # TODO(jelmer): Don't use this hack. long = getattr(__builtins__, 'long', int) commit.commit_time = long(rev.timestamp) if u'author-timestamp' in rev.properties: commit.author_time = long(rev.properties[u'author-timestamp']) else: commit.author_time = commit.commit_time commit._commit_timezone_neg_utc = ( u"commit-timezone-neg-utc" in rev.properties) commit.commit_timezone = rev.timezone commit._author_timezone_neg_utc = ( u"author-timezone-neg-utc" in rev.properties) if u'author-timezone' in rev.properties: commit.author_timezone = int(rev.properties[u'author-timezone']) else: commit.author_timezone = commit.commit_timezone if u'git-gpg-signature' in rev.properties: commit.gpgsig = rev.properties[u'git-gpg-signature'].encode( 'utf-8', 'surrogateescape') commit.message = self._encode_commit_message(rev, rev.message, encoding) if not isinstance(commit.message, bytes): raise TypeError(commit.message) if metadata is not None: try: mapping_registry.parse_revision_id(rev.revision_id) except errors.InvalidRevisionId: metadata.revision_id = rev.revision_id mapping_properties = set( [u'author', u'author-timezone', u'author-timezone-neg-utc', u'commit-timezone-neg-utc', u'git-implicit-encoding', u'git-gpg-signature', u'git-explicit-encoding', u'author-timestamp', u'file-modes']) for k, v in rev.properties.items(): if k not in mapping_properties: metadata.properties[k] = v if not lossy and metadata: if self.roundtripping: commit.message = inject_bzr_metadata(commit.message, metadata, encoding) else: raise NoPushSupport( None, None, self, revision_id=rev.revision_id) if not isinstance(commit.message, bytes): raise TypeError(commit.message) i = 0 propname = u'git-mergetag-0' while propname in rev.properties: commit.mergetag.append(Tag.from_string(rev.properties[propname])) i += 1 propname = u'git-mergetag-%d' % i if u'git-extra' in rev.properties: commit.extra.extend( [l.split(b' ', 1) for l in rev.properties[u'git-extra'].splitlines()]) return commit