#!/usr/bin/python # dul-daemon - Simple git-daemon a like # Copyright (C) 2008 John Carr # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; version 2 # of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301, USA. import os, sys, tempfile, struct from dulwich.server import Backend, TCPGitServer from dulwich.repo import Repo from dulwich.pack import PackData, Pack import sha from dulwich.pack import write_pack_object class PackWriteWrapper(object): def __init__(self, write): self.writefn = write self.sha = sha.sha() def write(self, blob): self.sha.update(blob) self.writefn(blob) def tell(self): pass @property def digest(self): return self.sha.digest() class GitBackend(Backend): def __init__(self, gitdir=None): self.gitdir = gitdir if not self.gitdir: self.gitdir = tempfile.mkdtemp() Repo.create(self.gitdir) self.repo = Repo(self.gitdir) def get_refs(self): refs = [] if self.repo.head(): refs.append(('HEAD', self.repo.head())) for ref, sha in self.repo.heads().items(): refs.append(('refs/heads/'+ref,sha)) return refs def has_revision(self, sha): return self.repo.get_object(sha) != None def apply_pack(self, refs, read): # store the incoming pack in the repository fd, name = tempfile.mkstemp(suffix='.pack', prefix='', dir=self.repo.pack_dir()) os.write(fd, read()) os.close(fd) # strip '.pack' off our filename basename = name[:-5] # generate an index for it pd = PackData(name) pd.create_index_v2(basename+".idx") for oldsha, sha, ref in refs: if ref == "0" * 40: self.repo.remove_ref(ref) else: self.repo.set_ref(ref, sha) print "pack applied" def generate_pack(self, want, have, write, progress): progress("dul-daemon says what\n") sha_queue = [] commits_to_send = want[:] for sha in commits_to_send: sha_queue.append((1,sha)) c = self.repo.commit(sha) for p in c.parents(): commits_to_send.append(p) progress("counting objects: %d\r" % len(sha_queue)) progress("counting objects: %d, done.\n" % len(sha_queue)) w = PackWriteWrapper(write) w.write("PACK") w.write(struct.pack(">L", 2)) w.write(struct.pack(">L", len(sha_queue))) for type, sha in sha_queue: obj = self.repo.get_object(sha) write_pack_object(w, type, object) # send sha1 of pack write(w.digest()) if __name__ == "__main__": gitdir = None if len(sys.argv) > 1: gitdir = sys.argv[1] backend = GitBackend(gitdir) server = TCPGitServer(backend, ('localhost', 9418)) server.serve_forever()