import SimpleHTTPServer import SocketServer import os.path import re import time import os import shutil from io import BytesIO from gitdb.base import IStream import git import gitdb import binascii try: shutil.rmtree('tempdir') except: pass shutil.copytree('.git', 'tempdir') os.chdir('tempdir') state = 0 state_2_time = None tree_objid = None def object_id_by_path(path): object_pat = re.compile('^/objects/([0-9a-f]{2})/([0-9a-f]*)') m = object_pat.match(path) if m == None: return None return m.group(1) + m.group(2) class myHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): def do_forward(self): print ' forwarding' self.send_response(301) # downgrade smart to dumb protocol path = self.path.split('?')[0] # important: append dummy suffix to make git treat this as an # "insane redirect scheme" and not cache the redirect locally. dummy_suffix = '?dummy=dummy' new_path = '%s%s%s'%('http://localhost:8001', path, dummy_suffix) self.send_header('Location', new_path) self.end_headers() def do_error(self): print ' sending error' self.send_response(500, 'temporary error, please try again') self.end_headers() def do_GET(self): global state, state_2_time, tree_objid objid = object_id_by_path(self.path) print self.path if state == 0: if objid != None: # fetching the commit state = 1 self.do_forward() return if state == 1: if objid != None: # fetching the tree print 'got tree object id: ' + objid tree_objid = objid state_2_time = time.time() state = 2 self.do_error() return self.do_forward() return if state == 2: if state_2_time + 1 < time.time(): print '### ADVANCING TO STATE 3' repo = git.Repo('.') cm_orig = repo.heads.master.commit tree = cm_orig.tree tree.cache.add_unchecked(binascii.unhexlify(tree_objid), 16384, 'boring_subdir') tree.cache.set_done() sio = BytesIO() git.objects.fun.tree_to_stream(tree._cache, sio.write) sio.seek(0) istream = repo.odb.store(IStream(gitdb.typ.str_tree_type, len(sio.getvalue()), sio)) tree.binsha = istream.binsha print tree new_cm = git.Commit.create_from_tree(repo, tree, 'newest commit', parent_commits=[cm_orig], head=True) print new_cm os.system('git update-server-info') print '### GIT COMMIT CREATED' state = 3 else: print 'not advancing' self.do_error() return # Code starting now should only run on second clone attempt. # Mix the two repos: Objects and metainfo that exist in our repo are served from # our repo, objects we don't have come from the remote repo. path = self.translate_path(self.path) if os.path.isfile(path) and not path.startswith('/objects/info/packs'): print ' sending file' f = self.send_head() if f: try: self.copyfile(f, self.wfile) finally: f.close() else: self.do_forward() PORT = 8000 SocketServer.TCPServer.allow_reuse_address = True handler = SocketServer.TCPServer(("", PORT), myHandler) print "serving at port 8000" handler.serve_forever()