def content(mode, hexsha): if hexsha is None: return Blob.from_string(b'') elif S_ISGITLINK(mode): return Blob.from_string(b"Submodule commit " + hexsha + b"\n") else: return store[hexsha]
def test_git_dir(self): if os.name != "posix": self.skipTest("test depends on POSIX shell") repo_dir = tempfile.mkdtemp() repo = Repo.init(repo_dir) self.addCleanup(shutil.rmtree, repo_dir) # Populate repo filea = Blob.from_string("file a") filee = Blob.from_string("d") tree = Tree() tree[".git/a"] = (stat.S_IFREG | 0o644, filea.id) tree["c/e"] = (stat.S_IFREG | 0o644, filee.id) repo.object_store.add_objects([(o, None) for o in [filea, filee, 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, ".git", "a") self.assertFalse(os.path.exists(apath)) # filee epath = os.path.join(repo.path, "c", "e") self.assertTrue(os.path.exists(epath)) self.assertReasonableIndexEntry(index["c/e"], stat.S_IFREG | 0o644, 1, filee.id) self.assertFileContents(epath, "d")
def test_symlink(self): repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: # Populate repo filed = Blob.from_string(b'file d') filee = Blob.from_string(b'd') tree = Tree() tree[b'c/d'] = (stat.S_IFREG | 0o644, filed.id) tree[b'c/e'] = (stat.S_IFLNK, filee.id) # symlink repo.object_store.add_objects([(o, None) for o in [filed, filee, tree]]) build_index_from_tree(repo.path, repo.index_path(), repo.object_store, tree.id) # Verify index entries index = repo.open_index() # symlink to d epath = os.path.join(repo.path, 'c', 'e') self.assertTrue(os.path.exists(epath)) self.assertReasonableIndexEntry( index[b'c/e'], stat.S_IFLNK, 0 if sys.platform == 'win32' else 1, filee.id) self.assertFileContents(epath, 'd', symlink=True)
def test_object_diff_bin_blob_force(self): f = BytesIO() # Prepare two slightly different PNG headers b1 = Blob.from_string( b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" b"\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b" ) b2 = Blob.from_string( b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" b"\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3" ) store = MemoryObjectStore() store.add_objects([(b1, None), (b2, None)]) write_object_diff(f, store, (b"foo.png", 0o644, b1.id), (b"bar.png", 0o644, b2.id), diff_binary=True) self.assertEqual( [ b"diff --git a/foo.png b/bar.png", b"index f73e47d..06364b7 644", b"--- a/foo.png", b"+++ b/bar.png", b"@@ -1,4 +1,4 @@", b" \x89PNG", b" \x1a", b" \x00\x00\x00", b"-IHDR\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b", b"\\ No newline at end of file", b"+IHDR\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3", b"\\ No newline at end of file", ], f.getvalue().splitlines(), )
def test_commit_with_change(self): a = Blob.from_string(b"The Foo\n") ta = Tree() ta.add(b"somename", 0o100644, a.id) ca = make_commit(tree=ta.id) b = Blob.from_string(b"The Bar\n") tb = Tree() tb.add(b"somename", 0o100644, b.id) cb = make_commit(tree=tb.id, parents=[ca.id]) self.repo.object_store.add_objects( [(a, None), (b, None), (ta, None), (tb, None), (ca, None), (cb, None)]) outstream = StringIO() porcelain.show(self.repo.path, objects=[cb.id], outstream=outstream) self.assertMultiLineEqual(outstream.getvalue(), """\ -------------------------------------------------- commit: 2c6b6c9cb72c130956657e1fdae58e5b103744fa Author: Test Author <*****@*****.**> Committer: Test Committer <*****@*****.**> Date: Fri Jan 01 2010 00:00:00 +0000 Test message. diff --git a/somename b/somename index ea5c7bf..fd38bcb 100644 --- a/somename +++ b/somename @@ -1 +1 @@ -The Foo +The Bar """)
def test_object_diff_bin_blob_force(self): f = StringIO() # Prepare two slightly different PNG headers b1 = Blob.from_string( "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" "\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b") b2 = Blob.from_string( "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" "\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3") store = MemoryObjectStore() store.add_objects([(b1, None), (b2, None)]) write_object_diff(f, store, ('foo.png', 0644, b1.id), ('bar.png', 0644, b2.id), diff_binary=True) self.assertEqual([ 'diff --git a/foo.png b/bar.png', 'index f73e47d..06364b7 644', '--- a/foo.png', '+++ b/bar.png', '@@ -1,4 +1,4 @@', ' \x89PNG', ' \x1a', ' \x00\x00\x00', '-IHDR\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b', '\\ No newline at end of file', '+IHDR\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3', '\\ No newline at end of file' ], f.getvalue().splitlines())
def test_git_dir(self): repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: # Populate repo filea = Blob.from_string(b'file a') filee = Blob.from_string(b'd') tree = Tree() tree[b'.git/a'] = (stat.S_IFREG | 0o644, filea.id) tree[b'c/e'] = (stat.S_IFREG | 0o644, filee.id) repo.object_store.add_objects([(o, None) for o in [filea, filee, 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, '.git', 'a') self.assertFalse(os.path.exists(apath)) # filee epath = os.path.join(repo.path, 'c', 'e') self.assertTrue(os.path.exists(epath)) self.assertReasonableIndexEntry(index[b'c/e'], stat.S_IFREG | 0o644, 1, filee.id) self.assertFileContents(epath, b'd')
def test_simple_delta(self): b1 = Blob.from_string("a" * 101) b2 = Blob.from_string("a" * 100) delta = create_delta(b1.as_raw_string(), b2.as_raw_string()) self.assertEqual([ (b1.type_num, b1.sha().digest(), None, b1.as_raw_string()), (b2.type_num, b2.sha().digest(), b1.sha().digest(), delta) ], list(deltify_pack_objects([(b1, ""), (b2, "")])))
def test_nonempty(self): if os.name != "posix": self.skipTest("test depends on POSIX shell") repo_dir = tempfile.mkdtemp() repo = Repo.init(repo_dir) self.addCleanup(shutil.rmtree, repo_dir) # Populate repo filea = Blob.from_string("file a") fileb = Blob.from_string("file b") filed = Blob.from_string("file d") filee = Blob.from_string("d") tree = Tree() tree["a"] = (stat.S_IFREG | 0o644, filea.id) tree["b"] = (stat.S_IFREG | 0o644, fileb.id) tree["c/d"] = (stat.S_IFREG | 0o644, filed.id) tree["c/e"] = (stat.S_IFLNK, filee.id) # symlink repo.object_store.add_objects([(o, None) for o in [filea, fileb, filed, filee, 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), 4) # filea apath = os.path.join(repo.path, "a") self.assertTrue(os.path.exists(apath)) self.assertReasonableIndexEntry(index["a"], stat.S_IFREG | 0o644, 6, filea.id) self.assertFileContents(apath, "file a") # fileb bpath = os.path.join(repo.path, "b") self.assertTrue(os.path.exists(bpath)) self.assertReasonableIndexEntry(index["b"], stat.S_IFREG | 0o644, 6, fileb.id) self.assertFileContents(bpath, "file b") # filed dpath = os.path.join(repo.path, "c", "d") self.assertTrue(os.path.exists(dpath)) self.assertReasonableIndexEntry(index["c/d"], stat.S_IFREG | 0o644, 6, filed.id) self.assertFileContents(dpath, "file d") # symlink to d epath = os.path.join(repo.path, "c", "e") self.assertTrue(os.path.exists(epath)) self.assertReasonableIndexEntry(index["c/e"], stat.S_IFLNK, 1, filee.id) self.assertFileContents(epath, "d", symlink=True) # Verify no extra files self.assertEqual([".git", "a", "b", "c"], sorted(os.listdir(repo.path))) self.assertEqual(["d", "e"], sorted(os.listdir(os.path.join(repo.path, "c"))))
def test_nonempty(self): repo_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: # Populate repo filea = Blob.from_string(b'file a') fileb = Blob.from_string(b'file b') filed = Blob.from_string(b'file d') tree = Tree() tree[b'a'] = (stat.S_IFREG | 0o644, filea.id) tree[b'b'] = (stat.S_IFREG | 0o644, fileb.id) tree[b'c/d'] = (stat.S_IFREG | 0o644, filed.id) repo.object_store.add_objects([(o, None) for o in [filea, fileb, filed, 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), 3) # filea apath = os.path.join(repo.path, 'a') self.assertTrue(os.path.exists(apath)) self.assertReasonableIndexEntry(index[b'a'], stat.S_IFREG | 0o644, 6, filea.id) self.assertFileContents(apath, b'file a') # fileb bpath = os.path.join(repo.path, 'b') self.assertTrue(os.path.exists(bpath)) self.assertReasonableIndexEntry(index[b'b'], stat.S_IFREG | 0o644, 6, fileb.id) self.assertFileContents(bpath, b'file b') # filed dpath = os.path.join(repo.path, 'c', 'd') self.assertTrue(os.path.exists(dpath)) self.assertReasonableIndexEntry(index[b'c/d'], stat.S_IFREG | 0o644, 6, filed.id) self.assertFileContents(dpath, b'file d') # Verify no extra files self.assertEqual(['.git', 'a', 'b', 'c'], sorted(os.listdir(repo.path))) self.assertEqual(['d'], sorted(os.listdir(os.path.join(repo.path, 'c'))))
def test_tree_diff(self): f = StringIO() store = MemoryObjectStore() added = Blob.from_string("add\n") removed = Blob.from_string("removed\n") changed1 = Blob.from_string("unchanged\nremoved\n") changed2 = Blob.from_string("unchanged\nadded\n") unchanged = Blob.from_string("unchanged\n") tree1 = Tree() tree1.add(0644, "removed.txt", removed.id) tree1.add(0644, "changed.txt", changed1.id) tree1.add(0644, "unchanged.txt", changed1.id) tree2 = Tree() tree2.add(0644, "added.txt", added.id) tree2.add(0644, "changed.txt", changed2.id) tree1.add(0644, "unchanged.txt", changed1.id) store.add_objects([(o, None) for o in [ tree1, tree2, added, removed, changed1, changed2, unchanged]]) write_tree_diff(f, store, tree1.id, tree2.id) self.assertEquals([ 'diff --git a/changed.txt b/changed.txt', 'index bf84e48..1be2436 644', '--- a/changed.txt', '+++ b/changed.txt', '@@ -1,2 +1,2 @@', ' unchanged', '-removed', '+added', 'diff --git a/removed.txt /dev/null', 'deleted mode 644', 'index 2c3f0b3..e69de29', '--- a/removed.txt', '+++ /dev/null', '@@ -1,1 +1,0 @@', '-removed', 'diff --git a/unchanged.txt /dev/null', 'deleted mode 644', 'index bf84e48..e69de29', '--- a/unchanged.txt', '+++ /dev/null', '@@ -1,2 +1,0 @@', '-unchanged', '-removed', 'diff --git /dev/null b/added.txt', 'new mode 644', 'index e69de29..76d4bb8 644', '--- /dev/null', '+++ b/added.txt', '@@ -1,0 +1,1 @@', '+add' ], f.getvalue().splitlines())
def test_blob_diff(self): f = BytesIO() write_blob_diff(f, ("foo.txt", 0o644, Blob.from_string(b"old\nsame\n")), ("bar.txt", 0o644, Blob.from_string(b"new\nsame\n"))) self.assertEqual([ b"diff --git a/foo.txt b/bar.txt", b"index 3b0f961..a116b51 644", b"--- a/foo.txt", b"+++ b/bar.txt", b"@@ -1,2 +1,2 @@", b"-old", b"+new", b" same" ], f.getvalue().splitlines())
def commit_diff(self, commit): """Return the list of changes introduced by `commit`.""" from klaus.utils import guess_is_binary if commit.parents: parent_tree = self[commit.parents[0]].tree else: parent_tree = None summary = {'nfiles': 0, 'nadditions': 0, 'ndeletions': 0} file_changes = [] # the changes in detail dulwich_changes = self.object_store.tree_changes(parent_tree, commit.tree) for (oldpath, newpath), (oldmode, newmode), (oldsha, newsha) in dulwich_changes: summary['nfiles'] += 1 try: oldblob = self.object_store[oldsha] if oldsha else Blob.from_string(b'') newblob = self.object_store[newsha] if newsha else Blob.from_string(b'') except KeyError: # newsha/oldsha are probably related to submodules. # Dulwich will handle that. pass # Check for binary files -- can't show diffs for these if guess_is_binary(newblob) or \ guess_is_binary(oldblob): file_changes.append({ 'is_binary': True, 'old_filename': oldpath or '/dev/null', 'new_filename': newpath or '/dev/null', 'chunks': None }) continue additions, deletions, chunks = render_diff( oldblob.splitlines(), newblob.splitlines()) change = { 'is_binary': False, 'old_filename': oldpath or '/dev/null', 'new_filename': newpath or '/dev/null', 'chunks': chunks, 'additions': additions, 'deletions': deletions, } summary['nadditions'] += additions summary['ndeletions'] += deletions file_changes.append(change) return summary, file_changes
def init_the_git(config): path = config.get('Local', 'path') repo = Repo.init(path) blob = Blob.from_string(open(os.path.join(path, '.git-dropbox.cnf')).read()) tree = Tree() tree.add(".git-dropbox.cnf", 0100644, blob.id) commit = Commit() commit.tree = tree.id commit.author = config.get('Local', 'user') commit.committer = 'Git-dropbox' commit.commit_time = int(time()) commit.author_time = os.path.getctime(os.path.join(path, '.git-dropbox.cnf')) commit.commit_timezone = commit.author_timezone = parse_timezone('-0200')[0] commit.encoding = 'UTF-8' commit.message = 'Initial commit' object_store = repo.object_store object_store.add_object(blob) object_store.add_object(tree) object_store.add_object(commit) repo.refs['refs/heads/master'] = commit.id
def test_commit_no_parent(self): a = Blob.from_string(b"The Foo\n") ta = Tree() ta.add(b"somename", 0o100644, a.id) ca = make_commit(tree=ta.id) self.repo.object_store.add_objects([(a, None), (ta, None), (ca, None)]) outstream = StringIO() porcelain.show(self.repo.path, objects=[ca.id], outstream=outstream) self.assertMultiLineEqual(outstream.getvalue(), """\ -------------------------------------------------- commit: 344da06c1bb85901270b3e8875c988a027ec087d Author: Test Author <*****@*****.**> Committer: Test Committer <*****@*****.**> Date: Fri Jan 01 2010 00:00:00 +0000 Test message. diff --git /dev/null b/somename new mode 100644 index 0000000..ea5c7bf 100644 --- /dev/null +++ b/somename @@ -0,0 +1 @@ +The Foo """)
def diff_tree(repo, tree_id, path=None): # FIXME: code a proper diff function, add to dulwich? if path is None: path = repo.path for entry in repo[tree_id].iteritems(): fpath = os.path.join(path, entry.path) if not os.path.exists(fpath): return True # an entry that should exist does not exist if S_ISGITLINK(entry.mode): raise NotImplementedError('Does not support submodules') elif S_ISDIR(entry.mode): if diff_tree(repo, entry.sha, fpath): return True # a subdir differs elif S_ISLNK(entry.mode): raise NotImplementedError('Symlinks currently not supported') elif S_ISREG(entry.mode): with open(fpath, 'rb') as f: b = Blob.from_string(f.read()) if not b.id == entry.sha: log.debug('File %s differs' % fpath) return True else: raise ValueError('Cannot deal with mode of %s' % entry) return False
def git_repo_init(gitdir): os.mkdir(gitdir) repo = Repo.init_bare(gitdir) blob = Blob.from_string("""Why, Hello there! This is your friendly Legislation tracker, Billy here. This is a git repo full of everything I write to the DB. This isn't super useful unless you're debugging production issues. Fondly, Bill, your local Billy instance.""") tree = Tree() tree.add("README", 0100644, blob.id) commit = Commit() commit.tree = tree.id author = "Billy <billy@localhost>" commit.author = commit.committer = author commit.commit_time = commit.author_time = int(time()) tz = parse_timezone('-0400')[0] commit.commit_timezone = commit.author_timezone = tz commit.encoding = "UTF-8" commit.message = "Initial commit" repo.object_store.add_object(blob) repo.object_store.add_object(tree) repo.object_store.add_object(commit) repo.refs['refs/heads/master'] = commit.id
def _put(self, key, data): commit = self._create_top_commit() commit.message = ( 'Updated key {}'.format(self.subdir + '/' + key)).encode('utf8') blob = Blob.from_string(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] objects_to_add = [blob] components = self._key_components(key) if self.subdir: components = self._subdir_components + components res = _on_tree(self.repo, tree, components, blob) objects_to_add.extend(res) commit.tree = res[-1].id objects_to_add.append(commit) # add objects for obj in objects_to_add: self.repo.object_store.add_object(obj) # update refs self.repo.refs[self._refname] = commit.id return key
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(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 _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 _file_is_modified(self, path, ref=None): """ Returns True if the current file (in the WT) has been modified from the blob in the commit's tree, False otherwise. :param path: path to the file relative to the repository root. :param ref: optional ref to compare the WT with, default is HEAD. This returns False for new files (not present in the tree). If this is unexpected, just call ``_file_in_tree`` first. It assumes that the given path does exist. Just expect an OSError if it doesn't. """ # handle no head scenario when this gets called before first commit try: self.head() except NoHeadSet: return False # get the tree tree = self.repo[self.head().tree] # get the blob from the tree blob1 = self._obj_from_tree(tree, path) if type(blob1) is not Blob: return False # make a second blob from the current file with open(os.path.join(self.root, path), 'r') as fp: blob2 = Blob.from_string(fp.read()) # are the two blobs equivalent? # if their contents are the same they should be... # calls dulwich.objects.ShaFile.__eq__, which just compares SHAs return blob1 != blob2
def test_no_decode_encode(self): repo_dir = tempfile.mkdtemp() repo_dir_bytes = repo_dir.encode(sys.getfilesystemencoding()) self.addCleanup(shutil.rmtree, repo_dir) with Repo.init(repo_dir) as repo: # Populate repo file = Blob.from_string(b'foo') tree = Tree() latin1_name = u'À'.encode('latin1') utf8_name = u'À'.encode('utf8') tree[latin1_name] = (stat.S_IFREG | 0o644, file.id) tree[utf8_name] = (stat.S_IFREG | 0o644, file.id) repo.object_store.add_objects( [(o, None) for o in [file, tree]]) build_index_from_tree( repo.path, repo.index_path(), repo.object_store, tree.id) # Verify index entries index = repo.open_index() latin1_path = os.path.join(repo_dir_bytes, latin1_name) self.assertTrue(os.path.exists(latin1_path)) utf8_path = os.path.join(repo_dir_bytes, utf8_name) self.assertTrue(os.path.exists(utf8_path))
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 write(files): repo = Repo(repo_path) blobs = {} dirs = {} def add_to_dirs(path): dirname = os.path.dirname(path) if path == '': return add_to_dirs(dirname) names = dirs.get(dirname, []) if path not in names: names.append(path) dirs[dirname] = names def savedir(dirname): tree = Tree() names = dirs[dirname] for name in names: basename = os.path.basename(name) sha = blobs.get(name, None) if sha is not None: tree.add(basename.encode('utf-8'), 0100644, sha) continue subtree = savedir(name) tree.add(basename.encode('utf-8'), 040000, subtree.id) repo.object_store.add_object(tree) return tree for metadata in files: blob = Blob.from_string(metadata.content) repo.object_store.add_object(blob) blobs[metadata.path[1:]] = blob.id add_to_dirs(metadata.path[1:]) tree = savedir('') commit = Commit() commit.tree = tree.id commit.author = author.encode('utf-8') commit.author_time = author_time commit.author_timezone = author_timezone commit.committer = committer.encode('utf-8') commit.commit_time = commit_time commit.commit_timezone = commit_timezone commit.encoding = encoding.encode('utf-8') commit.message = message.encode('utf-8') repo.object_store.add_object(commit) repo[ref] = commit.id
def serialize(self, value, git_store): git_blob = GitBlob.from_string(value) git_store.add_object(git_blob) return TreeEntry( mode=tree_entry_modes.raw_blob, sha=git_blob.id, )
def put(self, key, value, flatten_keys=True, branch='master', author=None, committer=None): """ Add/Update many key value pairs in the store. The entries param should be a python dict containing one or more key value pairs to store. The keys can be nested paths of objects to set. :param key: The key to store the entry/entries in :param value: The value to store. """ e = {key: value} if flatten_keys: e = flatten(e) root_tree = self._get_object(ROOT_PATH, branch) merge_heads = [] if not root_tree: root_tree = self._get_object(ROOT_PATH) merge_heads = [self.branch_head('master')] blobs=[] msg = '' for (key, value) in e.iteritems(): blob = Blob.from_string(self.serializer.dumps(value)) self.repo.object_store.add_object(blob) blobs.append((key, blob.id, stat.S_IFREG)) msg += "Put %s\n" % key root_id = self._add_tree(root_tree, blobs) sha = self.repo.do_commit( tree=root_id, message=msg, ref=self._branch_ref_name(branch), merge_heads=merge_heads, author=author, committer=committer ) return {'sha': sha}
def __init_code__(): # initialize the repo if it doesn't exists, or load it if it does if not path.exists(LOGS_PATH): print "creating folder "+ LOGS_PATH mkdir(LOGS_PATH) repo = Repo.init(LOGS_PATH) blob = Blob.from_string("data") tree =Tree() tree.add(0100644, "initfile", blob.id) c = Commit() c.tree = tree.id author = "Writer [email protected]" c.author=c.committer=author c.commit_time=c.author_time=int(time()) tz = parse_timezone('+0200') c.commit_timezone=c.author_timezone=tz c.encoding="UTF-8" c.message="initial commit" store = repo.object_store store.add_object(blob) store.add_object(tree) store.add_object(c) repo.refs['refs/heads/master'] = c.id repo.refs['HEAD'] = 'ref: refs/heads/master' print "success!" else: #this is how to create a Repo object from an existing repository from dulwich.errors import NotGitRepository try: repo = Repo(LOGS_PATH) except NotGitRepository as e: raise GitFileError("Error: the path %s exists but is not a git repository."%LOGS_PATH) return repo
def serialize(self, value, git_store): content = msgpack.packb(value) git_blob = GitBlob.from_string(content) git_store.add_object(git_blob) return TreeEntry( mode=tree_entry_modes.pack_blob, sha=git_blob.id, )
def get_blob(self, path): if not self.isdir: abspath = os.path.abspath(self.path) else: abspath = os.path.join(os.path.dirname(self.path), path) if os.path.isfile(abspath): with open(abspath, 'rb') as f: # tutorial says we can use from_file here - possibly wrong? return (MODE_XFILE if _is_executable(abspath) else MODE_RFILE, Blob.from_string(f.read())) elif os.path.islink(abspath): target = os.readlink(abspath) return (MODE_LNK, Blob.from_string(target)) else: raise RuntimeError('Can\'t handle %s' % abspath)
def test_copy_no_changes(self): a = Blob.from_string(b'a') delta = self.transform([('copy', (b'old', stat.S_IFREG | 0o644, a), (b'a', stat.S_IFREG | 0o644, a))]) expected_delta = TreeDelta() expected_delta.copied.append( TreeChange(b'git:a', ('old', 'a'), False, (True, True), (b'TREE_ROOT', b'TREE_ROOT'), ('old', 'a'), ('file', 'file'), (False, False), True)) self.assertEqual(expected_delta, delta)
def test_extra(self): self.build_tree(['a']) newa = Blob.from_string(b'contents of a\n') newt = Tree() newt.add(b"a", stat.S_IFREG | 0o644, newa.id) self.expectDelta([ ('add', (None, None, None), (b'', stat.S_IFDIR, newt.id)), ('add', (None, None, None), (b'a', stat.S_IFREG | 0o644, newa.id)), ], [b'a'], want_unversioned=True)
def test_delete(self): b = Blob.from_string(b'b') delta = self.transform([('remove', (b'a', stat.S_IFREG | 0o644, b), (None, None, None))]) expected_delta = TreeDelta() expected_delta.removed.append( TreeChange(b'git:a', ('a', None), True, (True, False), (b'TREE_ROOT', None), ('a', None), ('file', None), (False, None), False)) self.assertEqual(delta, expected_delta)
def test_blob_remove(self): f = BytesIO() write_blob_diff(f, ("bar.txt", 0o644, Blob.from_string("new\nsame\n")), (None, None, None)) self.assertEqual([ 'diff --git a/bar.txt /dev/null', 'deleted mode 644', 'index a116b51..0000000', '--- a/bar.txt', '+++ /dev/null', '@@ -1,2 +1,0 @@', '-new', '-same' ], f.getvalue().splitlines())
def _get_example_tar_stream(self, *tar_stream_args, **tar_stream_kwargs): store = MemoryObjectStore() b1 = Blob.from_string(b"somedata") store.add_object(b1) t1 = Tree() t1.add(b"somename", 0o100644, b1.id) store.add_object(t1) stream = b''.join( tar_stream(store, t1, *tar_stream_args, **tar_stream_kwargs)) return BytesIO(stream)
def test_blob_add(self): f = BytesIO() write_blob_diff(f, (None, None, None), (b"bar.txt", 0o644, Blob.from_string(b"new\nsame\n"))) self.assertEqual([ b'diff --git /dev/null b/bar.txt', b'new mode 644', b'index 0000000..a116b51 644', b'--- /dev/null', b'+++ b/bar.txt', b'@@ -1,0 +1,2 @@', b'+new', b'+same' ], f.getvalue().splitlines())
def test_with_file(self): child_ie = InventoryFile(b'bar', 'bar', b'bar') b = Blob.from_string(b"bla") t1 = directory_to_tree('', [child_ie], lambda p, x: b.id, {}, None, allow_empty=False) t2 = Tree() t2.add(b"bar", 0o100644, b.id) self.assertEqual(t1, t2)
def test_added_file(self): self.build_tree(['a']) self.wt.add(['a']) a = Blob.from_string(b'contents of a\n') t = Tree() t.add(b"a", stat.S_IFREG | 0o644, a.id) self.expectDelta([ ('add', (None, None, None), (b'', stat.S_IFDIR, t.id)), ('add', (None, None, None), (b'a', stat.S_IFREG | 0o644, a.id)) ])
def test_import_tree_with_unusual_mode_file(self): blob = Blob.from_string(b"bar1") tree = Tree() tree.add(b"foo", stat.S_IFREG | 0o664, blob.id) objects = {blob.id: blob, tree.id: tree} ret, child_modes = import_git_tree( self._texts, self._mapping, b"bla", b"bla", (None, tree.id), None, None, b"somerevid", [], objects.__getitem__, (None, stat.S_IFDIR), DummyStoreUpdater(), self._mapping.generate_file_id) self.assertEqual(child_modes, {b"bla/foo": stat.S_IFREG | 0o664})
def test_tree_diff(self): f = BytesIO() store = MemoryObjectStore() added = Blob.from_string(b"add\n") removed = Blob.from_string(b"removed\n") changed1 = Blob.from_string(b"unchanged\nremoved\n") changed2 = Blob.from_string(b"unchanged\nadded\n") unchanged = Blob.from_string(b"unchanged\n") tree1 = Tree() tree1.add(b"removed.txt", 0o644, removed.id) tree1.add(b"changed.txt", 0o644, changed1.id) tree1.add(b"unchanged.txt", 0o644, changed1.id) tree2 = Tree() tree2.add(b"added.txt", 0o644, added.id) tree2.add(b"changed.txt", 0o644, changed2.id) tree2.add(b"unchanged.txt", 0o644, changed1.id) store.add_objects([(o, None) for o in [ tree1, tree2, added, removed, changed1, changed2, unchanged]]) write_tree_diff(f, store, tree1.id, tree2.id) self.assertEqual([ b'diff --git /dev/null b/added.txt', b'new mode 644', b'index 0000000..76d4bb8 644', b'--- /dev/null', b'+++ b/added.txt', b'@@ -0,0 +1 @@', b'+add', b'diff --git a/changed.txt b/changed.txt', b'index bf84e48..1be2436 644', b'--- a/changed.txt', b'+++ b/changed.txt', b'@@ -1,2 +1,2 @@', b' unchanged', b'-removed', b'+added', b'diff --git a/removed.txt /dev/null', b'deleted mode 644', b'index 2c3f0b3..0000000', b'--- a/removed.txt', b'+++ /dev/null', b'@@ -1 +0,0 @@', b'-removed', ], f.getvalue().splitlines())
def test_delete(self): b = Blob.from_string(b'b') self.assertEqual([ TreeChange(b'git:a', ('a', None), True, (True, False), (b'TREE_ROOT', None), ('a', None), ('file', None), (False, None), False) ], self.transform([('remove', (b'a', stat.S_IFREG | 0o644, b), (None, None, None))]))
def test_rename_no_changes(self): a = Blob.from_string(b'a') self.assertEqual([ TreeChange(b'git:old', ('old', 'a'), False, (True, True), (b'TREE_ROOT', b'TREE_ROOT'), ('old', 'a'), ('file', 'file'), (False, False), False) ], self.transform([('rename', (b'old', stat.S_IFREG | 0o644, a), (b'a', stat.S_IFREG | 0o644, a))]))
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 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 test_object_diff_bin_blob(self): f = BytesIO() # Prepare two slightly different PNG headers b1 = Blob.from_string( b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" b"\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x04\x00\x00\x00\x05\x04\x8b" ) b2 = Blob.from_string( b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52" b"\x00\x00\x01\xd5\x00\x00\x00\x9f\x08\x03\x00\x00\x00\x98\xd3\xb3" ) store = MemoryObjectStore() store.add_objects([(b1, None), (b2, None)]) write_object_diff(f, store, (b'foo.png', 0o644, b1.id), (b'bar.png', 0o644, b2.id)) self.assertEqual([ b'diff --git a/foo.png b/bar.png', b'index f73e47d..06364b7 644', b'Binary files a/foo.png and b/bar.png differ' ], f.getvalue().splitlines())
def test_added_unknown_file(self): self.build_tree(['a']) t = Tree() self.expectDelta([((None, b''), (None, stat.S_IFDIR), (None, t.id))]) a = Blob.from_string(b'contents of a\n') t = Tree() t.add(b"a", stat.S_IFREG | 0o644, a.id) self.expectDelta([((None, b''), (None, stat.S_IFDIR), (None, t.id)), ((None, b'a'), (None, stat.S_IFREG | 0o644), (None, a.id))], [b'a'], want_unversioned=True)
def test_blob_diff(self): f = BytesIO() write_blob_diff( f, (b"foo.txt", 0o644, Blob.from_string(b"old\nsame\n")), (b"bar.txt", 0o644, Blob.from_string(b"new\nsame\n")), ) self.assertEqual( [ b"diff --git a/foo.txt b/bar.txt", b"index 3b0f961..a116b51 644", b"--- a/foo.txt", b"+++ b/bar.txt", b"@@ -1,2 +1,2 @@", b"-old", b"+new", b" same", ], f.getvalue().splitlines(), )
def test_missing_added_file(self): self.build_tree(['a']) self.wt.add(['a']) os.unlink('a') a = Blob.from_string(b'contents of a\n') t = Tree() t.add(b"a", 0, ZERO_SHA) self.expectDelta([('add', (None, None, None), (b'', stat.S_IFDIR, t.id)), ('add', (None, None, None), (b'a', 0, ZERO_SHA))], [])
def makeRepo(self, tree_contents): repo = GitRepo(self.repository_path) blobs = [(Blob.from_string(contents), filename) for (filename, contents) in tree_contents] repo.object_store.add_objects(blobs) root_id = dulwich.index.commit_tree( repo.object_store, [(filename, b.id, stat.S_IFREG | 0644) for (b, filename) in blobs]) repo.do_commit(committer='Joe Foo <*****@*****.**>', message=u'<The commit message>', tree=root_id)
def test_submodule_not_checked_out(self): a = Blob.from_string(b'irrelevant\n') with self.wt.lock_tree_write(): (index, index_path) = self.wt._lookup_index(b'a') index[b'a'] = IndexEntry(0, 0, 0, 0, S_IFGITLINK, 0, 0, 0, a.id, 0) self.wt._index_dirty = True os.mkdir(self.wt.abspath('a')) t = Tree() t.add(b"a", S_IFGITLINK, a.id) self.store.add_object(t) self.expectDelta([], tree_id=t.id)
def create_repo(design, initialize): full_path = os.path.join(settings.GIT_ROOT, design.repo_path) os.makedirs(full_path) repo = Repo.init_bare(full_path) if initialize: blob = Blob.from_string( str("%s Git-a-thing design repository\n" % design.name)) tree = Tree() tree.add("README", 0100644, blob.id) do_commit(repo, tree, [blob], "Initialize repository", settings.GITATHING_COMMITER)
def test_submodule(self): self.build_tree(['a/']) a = Blob.from_string(b'irrelevant\n') with self.wt.lock_tree_write(): (index, index_path) = self.wt._lookup_index(b'a') index[b'a'] = IndexEntry(0, 0, 0, 0, S_IFGITLINK, 0, 0, 0, a.id, 0) self.wt._index_dirty = True t = Tree() t.add(b"a", S_IFGITLINK, a.id) self.store.add_object(t) self.expectDelta([], tree_id=t.id)
def create_commit(marker=None): blob = Blob.from_string(b'The blob content ' + marker) tree = Tree() tree.add(b"thefile " + marker, 0o100644, blob.id) cmt = Commit() cmt.tree = tree.id cmt.author = cmt.committer = b"John Doe <*****@*****.**>" cmt.message = marker tz = parse_timezone(b'-0200')[0] cmt.commit_time = cmt.author_time = int(time.time()) cmt.commit_timezone = cmt.author_timezone = tz return cmt, tree, blob
def test_submodule(self): self.subtree = self.make_branch_and_tree('a', format="git") a = Blob.from_string(b'irrelevant\n') self.build_tree_contents([('a/.git/HEAD', a.id)]) with self.wt.lock_tree_write(): (index, index_path) = self.wt._lookup_index(b'a') index[b'a'] = IndexEntry(0, 0, 0, 0, S_IFGITLINK, 0, 0, 0, a.id, 0) self.wt._index_dirty = True t = Tree() t.add(b"a", S_IFGITLINK, a.id) self.store.add_object(t) self.expectDelta([], tree_id=t.id)
def test_simple(self): store = MemoryObjectStore() b1 = Blob.from_string(b"somedata") store.add_object(b1) t1 = Tree() t1.add(b"somename", 0o100644, b1.id) store.add_object(t1) stream = b''.join(tar_stream(store, t1, 10)) out = BytesIO(stream) tf = tarfile.TarFile(fileobj=out) self.addCleanup(tf.close) self.assertEqual(["somename"], tf.getnames())
def test_object_diff_blob(self): f = BytesIO() b1 = Blob.from_string(b"old\nsame\n") b2 = Blob.from_string(b"new\nsame\n") store = MemoryObjectStore() store.add_objects([(b1, None), (b2, None)]) write_object_diff(f, store, (b"foo.txt", 0o644, b1.id), (b"bar.txt", 0o644, b2.id)) self.assertEqual( [ b"diff --git a/foo.txt b/bar.txt", b"index 3b0f961..a116b51 644", b"--- a/foo.txt", b"+++ b/bar.txt", b"@@ -1,2 +1,2 @@", b"-old", b"+new", b" same", ], f.getvalue().splitlines(), )
def _save_files(self, parent_commit, files, commit_message): tree = self._get_tree(parent_commit) blobs = [] for file_path, contents in files.items(): blob = Blob.from_string(contents) tree.add(file_path, FILE_MODE, blob.id) blobs.append(blob) commit = self._create_commit() commit.parents = [parent_commit] commit.tree = tree.id commit.message = commit_message or 'Saving multiple files' self._update_store(commit, tree, *blobs) return commit
def add_blob(self, gc, name, contents): b = Blob.from_string(contents) t = Tree() t.add(name.encode('utf-8'), 0o644 | stat.S_IFREG, b.id) c = Commit() c.tree = t.id c.committer = c.author = b'Somebody <*****@*****.**>' c.commit_time = c.author_time = 800000 c.commit_timezone = c.author_timezone = 0 c.message = b'do something' gc.repo.object_store.add_objects([(b, None), (t, None), (c, None)]) gc.repo[gc.ref] = c.id return b.id.decode('ascii')
def test_object_diff_bin_blob_force(self): f = BytesIO() # Prepare two slightly different PNG headers b1 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" b"\x00\x00\x00\x0d\x49\x48\x44\x52" b"\x00\x00\x01\xd5\x00\x00\x00\x9f" b"\x08\x04\x00\x00\x00\x05\x04\x8b") b2 = Blob.from_string(b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a" b"\x00\x00\x00\x0d\x49\x48\x44\x52" b"\x00\x00\x01\xd5\x00\x00\x00\x9f" b"\x08\x03\x00\x00\x00\x98\xd3\xb3") store = MemoryObjectStore() store.add_objects([(b1, None), (b2, None)]) write_object_diff( f, store, (b"foo.png", 0o644, b1.id), (b"bar.png", 0o644, b2.id), diff_binary=True, ) self.assertEqual( [ b"diff --git a/foo.png b/bar.png", b"index f73e47d..06364b7 644", b"--- a/foo.png", b"+++ b/bar.png", b"@@ -1,4 +1,4 @@", b" \x89PNG", b" \x1a", b" \x00\x00\x00", b"-IHDR\x00\x00\x01\xd5\x00\x00\x00" b"\x9f\x08\x04\x00\x00\x00\x05\x04\x8b", b"\\ No newline at end of file", b"+IHDR\x00\x00\x01\xd5\x00\x00\x00\x9f" b"\x08\x03\x00\x00\x00\x98\xd3\xb3", b"\\ No newline at end of file", ], f.getvalue().splitlines(), )
def test_object_diff_add_blob(self): f = BytesIO() store = MemoryObjectStore() b2 = Blob.from_string(b"new\nsame\n") store.add_object(b2) write_object_diff(f, store, (None, None, None), (b"bar.txt", 0o644, b2.id)) self.assertEqual([ b'diff --git /dev/null b/bar.txt', b'new mode 644', b'index 0000000..a116b51 644', b'--- /dev/null', b'+++ b/bar.txt', b'@@ -1,0 +1,2 @@', b'+new', b'+same' ], f.getvalue().splitlines())
def test_object_diff_remove_blob(self): f = BytesIO() b1 = Blob.from_string(b"new\nsame\n") store = MemoryObjectStore() store.add_object(b1) write_object_diff(f, store, (b"bar.txt", 0o644, b1.id), (None, None, None)) self.assertEqual([ b'diff --git a/bar.txt /dev/null', b'deleted mode 644', b'index a116b51..0000000', b'--- a/bar.txt', b'+++ /dev/null', b'@@ -1,2 +1,0 @@', b'-new', b'-same' ], f.getvalue().splitlines())