#!/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", path) log.debug("difference is: %s", 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__': 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)