aboutsummaryrefslogtreecommitdiffstats
path: root/update.py
blob: 80334f5a0b7c6be0ab5f78bcf5098b25b6ab6018 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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.")