diff options
-rwxr-xr-x | update.py | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/update.py b/update.py new file mode 100755 index 0000000..80334f5 --- /dev/null +++ b/update.py @@ -0,0 +1,96 @@ +#!/usr/bin/python3 +import sys, os, subprocess, argparse + +class GitCommand: + def __getattr__(self, name): + def call(*args, get_stderr = False): + cmd = ["git", name.replace('_', '-')] + list(args) + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT if get_stderr else None) + return output.decode('utf-8').strip('\n') + return call + + def branches(self, *args): + b = self.branch(*args).split('\n') + b = map(lambda s: s[2:], b) + return list(b) + +git = GitCommand() + +def is_all_zero(str): + return len(str.replace('0', '')) == 0 + +class Repo: + def __init__(self, local, mirrors): + '''<local> is the directory containing the repository locally, <mirrors> a list of remote repositories''' + self.local = local + self.mirrors = mirrors + +# This is old code, that may be useful again if we decide to care about racy pushes loosing commits. +# def pull(self, slavenr): +# slave = self.slaves[slavenr] +# slavename = "slave-"+str(slavenr) +# # make sure we have the remote +# try: +# git.remote("add", slavename, slave, get_stderr=True) +# except subprocess.CalledProcessError: # the remote already exists +# git.remote("set-url", slavename, slave) +# # get all the changes +# git.fetch(slavename, get_stderr=True) +# # merge them... or hope so... +# branches = git.branches("-r") +# for branch in filter(lambda s: s.startswith(slavename+"/"), branches): +# local = branch[len(slavename+"/"):] +# print(local, branch) + + def update_mirror_ref(self, ref, mirror): + '''Update <ref> on <mirror> to the local state. If <newsha> is all-zero, the ref should be deleted.''' + git.push('--force', self.mirrors[mirror], ref) + + def update_ref(self, newsha, ref, source): + '''Update the <ref> to <newsha> everywhere. <source> is None if this update comes from the local repository, + or the name of a mirror. If <newsha> is all-zero, the ref should be deleted.''' + os.chdir(self.local) + if source is None: + # We already have the latest version locally. Update all the mirrors. + for mirror in self.mirrors: + self.update_mirror_ref(ref, mirror) + else: + raise Exception("Help, what should I do?") + +# for now, configuration is hard-coded here... + +repos = { + 'sync-test': Repo('/home/git/repositories/test.git', {'github': 'git@github.com:RalfJung/sync-test.git'}), +} + +def find_repo_by_directory(dir): + for (name, repo) in repos.items(): + if dir == repo.local: + return name + return None + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Keep git repositories in sync') + parser.add_argument("--hook", + action="store_true", dest="hook", + help="Act as git hook: Auto-detect the repository based on the working directoy, and fetch information from stdin") + parser.add_argument("-r", "--repository", + dest="repository", + help="The name of the repository to act on") + args = parser.parse_args() + + reponame = args.repository + if reponame is None and args.hook: + reponame = find_repo_by_directory(os.getcwd()) + if reponame is None: + raise Exception("Unable to detect repository, please use --repository.") + + # now sync this repository + repo = repos[reponame] + if args.hook: + # parse the information we get from stdin + for line in sys.stdin: + (oldsha, newsha, ref) = line.split() + repo.update_ref(newsha, ref, source=None) + else: + raise Exception("I am unsure what to do here.") |