2 import sys, os, subprocess, argparse
5 def __getattr__(self, name):
6 def call(*args, get_stderr = False):
7 cmd = ["git", name.replace('_', '-')] + list(args)
8 output = subprocess.check_output(cmd, stderr=subprocess.STDOUT if get_stderr else None)
9 return output.decode('utf-8').strip('\n')
12 def branches(self, *args):
13 b = self.branch(*args).split('\n')
14 b = map(lambda s: s[2:], b)
20 return len(str.replace('0', '')) == 0
23 def __init__(self, local, mirrors):
24 '''<local> is the directory containing the repository locally, <mirrors> a list of remote repositories'''
26 self.mirrors = mirrors
28 # This is old code, that may be useful again if we decide to care about racy pushes loosing commits.
29 # def pull(self, slavenr):
30 # slave = self.slaves[slavenr]
31 # slavename = "slave-"+str(slavenr)
32 # # make sure we have the remote
34 # git.remote("add", slavename, slave, get_stderr=True)
35 # except subprocess.CalledProcessError: # the remote already exists
36 # git.remote("set-url", slavename, slave)
37 # # get all the changes
38 # git.fetch(slavename, get_stderr=True)
39 # # merge them... or hope so...
40 # branches = git.branches("-r")
41 # for branch in filter(lambda s: s.startswith(slavename+"/"), branches):
42 # local = branch[len(slavename+"/"):]
43 # print(local, branch)
45 def update_mirror_ref(self, ref, mirror):
46 '''Update <ref> on <mirror> to the local state. If <newsha> is all-zero, the ref should be deleted.'''
47 git.push('--force', self.mirrors[mirror], ref)
49 def update_ref(self, newsha, ref, source):
50 '''Update the <ref> to <newsha> everywhere. <source> is None if this update comes from the local repository,
51 or the name of a mirror. If <newsha> is all-zero, the ref should be deleted.'''
54 # We already have the latest version locally. Update all the mirrors.
55 for mirror in self.mirrors:
56 self.update_mirror_ref(ref, mirror)
58 raise Exception("Help, what should I do?")
60 # for now, configuration is hard-coded here...
63 'sync-test': Repo('/home/git/repositories/test.git', {'github': 'git@github.com:RalfJung/sync-test.git'}),
66 def find_repo_by_directory(dir):
67 for (name, repo) in repos.items():
72 if __name__ == "__main__":
73 parser = argparse.ArgumentParser(description='Keep git repositories in sync')
74 parser.add_argument("--hook",
75 action="store_true", dest="hook",
76 help="Act as git hook: Auto-detect the repository based on the working directoy, and fetch information from stdin")
77 parser.add_argument("-r", "--repository",
79 help="The name of the repository to act on")
80 args = parser.parse_args()
82 reponame = args.repository
83 if reponame is None and args.hook:
84 reponame = find_repo_by_directory(os.getcwd())
86 raise Exception("Unable to detect repository, please use --repository.")
88 # now sync this repository
89 repo = repos[reponame]
91 # parse the information we get from stdin
92 for line in sys.stdin:
93 (oldsha, newsha, ref) = line.split()
94 repo.update_ref(newsha, ref, source=None)
96 raise Exception("I am unsure what to do here.")