|
@@ -0,0 +1,178 @@
|
|
|
+#!/usr/bin/env python
|
|
|
+# -*- encoding: UTF-8 -*-
|
|
|
+
|
|
|
+# Import from the Standard Library
|
|
|
+from os import F_OK, access, mkdir
|
|
|
+from pprint import pprint
|
|
|
+from shutil import rmtree
|
|
|
+from subprocess import call
|
|
|
+from time import time
|
|
|
+
|
|
|
+# Import from dulwich
|
|
|
+from dulwich.repo import Repo
|
|
|
+from dulwich.objects import Blob, Tree, Commit, parse_timezone
|
|
|
+
|
|
|
+
|
|
|
+DIRNAME = "myrepo"
|
|
|
+AUTHOR = "Your Name <your.email@example.com>"
|
|
|
+TZ = parse_timezone('-200')
|
|
|
+ENCODING = "UTF-8"
|
|
|
+
|
|
|
+
|
|
|
+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_tree(repo):
|
|
|
+ """Return the last known tree.
|
|
|
+ """
|
|
|
+ commit_id = repo.head()
|
|
|
+ commit = repo.commit(commit_id)
|
|
|
+ tree_id = commit.tree
|
|
|
+ return repo.tree(tree_id)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def update_master(repo, commit_id):
|
|
|
+ repo.refs['refs/heads/master'] = commit_id
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def initial_commit(repo):
|
|
|
+ # Add file content
|
|
|
+ blob = Blob.from_string("My file content\n")
|
|
|
+ # Add file
|
|
|
+ tree = Tree()
|
|
|
+ tree.add(0100644, "spam", blob.id)
|
|
|
+ # Set commit
|
|
|
+ commit = make_commit(repo, tree.id, "Initial commit")
|
|
|
+ # Initial commit
|
|
|
+ object_store = repo.object_store
|
|
|
+ object_store.add_object(blob)
|
|
|
+ object_store.add_object(tree)
|
|
|
+ object_store.add_object(commit)
|
|
|
+ # Update master
|
|
|
+ update_master(repo, commit.id)
|
|
|
+ # Set the master branch as the default
|
|
|
+ repo.refs['HEAD'] = 'ref: refs/heads/master'
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def test_change(repo):
|
|
|
+ tree = make_tree(repo)
|
|
|
+ # Change a file
|
|
|
+ spam = Blob.from_string("My new file content\n")
|
|
|
+ tree.add(0100644, "spam", spam.id)
|
|
|
+ # Set commit
|
|
|
+ commit = make_commit(repo, tree.id, "Change spam")
|
|
|
+ # Second commit
|
|
|
+ object_store = repo.object_store
|
|
|
+ object_store.add_object(spam)
|
|
|
+ object_store.add_object(tree)
|
|
|
+ object_store.add_object(commit)
|
|
|
+ # Update master
|
|
|
+ update_master(repo, commit.id)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def test_add(repo):
|
|
|
+ tree = make_tree(repo)
|
|
|
+ # Add another file
|
|
|
+ ham = Blob.from_string("Another\nmultiline\nfile\n")
|
|
|
+ tree.add(0100644, "ham", ham.id)
|
|
|
+ # Set commit
|
|
|
+ commit = make_commit(repo, tree.id, "Add ham")
|
|
|
+ # Second commit
|
|
|
+ object_store = repo.object_store
|
|
|
+ object_store.add_object(ham)
|
|
|
+ object_store.add_object(tree)
|
|
|
+ object_store.add_object(commit)
|
|
|
+ # Update master
|
|
|
+ update_master(repo, commit.id)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def test_remove(repo):
|
|
|
+ tree = make_tree(repo)
|
|
|
+ # Remove a file
|
|
|
+ del tree["ham"]
|
|
|
+ # Set commit
|
|
|
+ commit = make_commit(repo, tree.id, 'Remove "ham"')
|
|
|
+ # Third commit
|
|
|
+ # No blob change, just tree operation
|
|
|
+ object_store = repo.object_store
|
|
|
+ object_store.add_object(tree)
|
|
|
+ object_store.add_object(commit)
|
|
|
+ # Update master
|
|
|
+ update_master(repo, commit.id)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def test_rename(repo):
|
|
|
+ tree = make_tree(repo)
|
|
|
+ # Rename a file
|
|
|
+ tree["eggs"] = tree["spam"]
|
|
|
+ del tree["spam"]
|
|
|
+ # Set commit
|
|
|
+ commit = make_commit(repo, tree.id, 'Rename "spam" to "eggs"')
|
|
|
+ # Fourth commit
|
|
|
+ # No blob change, just tree operation
|
|
|
+ object_store = repo.object_store
|
|
|
+ object_store.add_object(tree)
|
|
|
+ object_store.add_object(commit)
|
|
|
+ # Update master
|
|
|
+ update_master(repo, commit.id)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def test_history(repo):
|
|
|
+ pprint(repo.revision_history(repo.head()))
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def test_file(repo):
|
|
|
+ tree = make_tree(repo)
|
|
|
+ print "entries", tree.entries()
|
|
|
+ mode, blob_id = tree["eggs"]
|
|
|
+ blob = repo.get_blob(blob_id)
|
|
|
+ print "eggs", repr(blob.data)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ # Creating the repository
|
|
|
+ if access(DIRNAME, F_OK):
|
|
|
+ rmtree(DIRNAME)
|
|
|
+ mkdir(DIRNAME)
|
|
|
+ repo = Repo.init(DIRNAME)
|
|
|
+ initial_commit(repo)
|
|
|
+ test_change(repo)
|
|
|
+ test_add(repo)
|
|
|
+ test_remove(repo)
|
|
|
+ test_rename(repo)
|
|
|
+ last_commit_id = repo.head()
|
|
|
+ call(['git', 'gc'], cwd=DIRNAME)
|
|
|
+ # Re-load the repo
|
|
|
+ del repo
|
|
|
+ repo = Repo(DIRNAME)
|
|
|
+ # XXX the ref was removed and dulwich doesn't know where to read it
|
|
|
+ update_master(repo, last_commit_id)
|
|
|
+ assert last_commit_id == repo.head()
|
|
|
+ test_history(repo)
|
|
|
+ test_file(repo)
|