#!/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 " 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)