aboutsummaryrefslogtreecommitdiff
path: root/check-git-repos.py
blob: 4b1d975c5d706dc2ac75c8f78e73bb85b5479d16 (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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#!/usr/bin/python
from subprocess import check_output, STDOUT, CalledProcessError
import os
import time
import argparse
import logging
import stat

# Root location of git repos
GITROOT = "/srv/repositories"
# Export filename
EXPORT_FILE = "git-daemon-export-ok"

logging.basicConfig()
log = logging.getLogger('check-git-repos')


def run_command(cmd, dir):
    log.debug("executing %s in %s", cmd, dir)
    try:
        out = check_output(cmd, stderr=STDOUT,
                           cwd=dir)
    except CalledProcessError as e:
        return e.returncode, e.output
    return 0, out


def update_server_info(path):
    return run_command(["git", "update-server-info"], path)


def get_file_refs(path):
    filerefs = {}
    with open(os.path.join(path, "info/refs")) as f:
        for line in f:
            if line:
                data = line.split()
                filerefs[data[1]] = data[0]
    return filerefs


def get_git_refs(path):
    ret, out = run_command(["git", "show-ref", "-d"], path)
    lines = out.split("\n")
    gitrefs = {}
    for line in lines:
        if line:
            data = line.split()
            gitrefs[data[1]] = data[0]
    return gitrefs


def perms_check(file):
    st_mode = os.stat(file).st_mode
    mode = stat.S_IFREG | stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | \
        stat.S_IROTH
    if st_mode != mode:
        log.warn("Permissions wrong for file %s, changing %s=>%s", file,
                 oct(st_mode), oct(mode))
        os.chmod(file, mode)


def get_repos():
    paths = []
    for root, dirs, files in os.walk(GITROOT, followlinks=True):
        if root.endswith(".git/info"):
            if "refs" in files:
                log.debug("found refs file %s", root+"/refs")
                repo_path = os.path.dirname(root)
                repo_name = os.path.basename(os.path.normpath(repo_path))
                if repo_name != "gitolite-admin.git":
                    paths.append(repo_path)
    return paths


def check_ref_status(path):
    filerefs = get_file_refs(path)
    gitrefs = get_git_refs(path)
    diff = set(filerefs.items()) ^ set(gitrefs.items())
    if len(diff) > 0:
        log.warn("%s refs file out of date, diff: %s", path, diff)
        ret, out = update_server_info(path)
        if ret != 0 or out != "":
            log.error("error processing %s, exited %i", path, ret)
            log.error(out)


def check_export_file(path):
    if not os.path.exists(os.path.join(path, EXPORT_FILE)):
        log.warn("%s not found in %s", EXPORT_FILE, path)


def process(paths):
    for path in paths:
        refsfile = os.path.join(path, "info/refs")
        perms_check(refsfile)
        perms_check(path+"/objects/info/packs")
        # check_export_file(path)
        check_ref_status(path)


if __name__ == '__main__':
    oldumask = os.umask(0022)
    parser = argparse.ArgumentParser(
        description='Check git repositories')
    parser.add_argument('--log', default='WARN',
                        choices=('WARN', 'INFO', 'DEBUG'),
                        help='Logging level to use. Default=%(default)s')
    args = parser.parse_args()
    log.setLevel(getattr(logging, args.log))
    pathlist = get_repos()
    process(pathlist)
    os.umask(oldumask)