| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 | # -*- coding: utf-8 -*-import collectionsimport datetimeimport tempfileimport subprocessimport reimport tarfileGitRef = collections.namedtuple(    "VersionRef",    ["name", "commit", "source", "is_remote", "refname", "creatordate",],)def get_all_refs(gitroot):    cmd = (        "git",        "for-each-ref",        "--format",        "%(objectname)\t%(refname)\t%(creatordate:iso)",        "refs",    )    output = subprocess.check_output(cmd, cwd=gitroot).decode()    for line in output.splitlines():        is_remote = False        fields = line.strip().split("\t")        if len(fields) != 3:            continue        commit = fields[0]        refname = fields[1]        creatordate = datetime.datetime.strptime(            fields[2], "%Y-%m-%d %H:%M:%S %z"        )        # Parse refname        matchobj = re.match(            r"^refs/(heads|tags|remotes/[^/]+)/(\S+)$", refname        )        if not matchobj:            continue        source = matchobj.group(1)        name = matchobj.group(2)        if source.startswith("remotes/"):            is_remote = True        yield GitRef(name, commit, source, is_remote, refname, creatordate)def get_refs(    gitroot, tag_whitelist, branch_whitelist, remote_whitelist, files=()):    for ref in get_all_refs(gitroot):        if ref.source == "tags":            if tag_whitelist is None or not re.match(tag_whitelist, ref.name):                continue        elif ref.source == "heads":            if branch_whitelist is None or not re.match(                branch_whitelist, ref.name            ):                continue        elif ref.is_remote and remote_whitelist is not None:            remote_name = ref.source.partition("/")[2]            if not re.match(remote_whitelist, remote_name):                continue            if branch_whitelist is None or not re.match(                branch_whitelist, ref.name            ):                continue        else:            continue        if not all(            file_exists(gitroot, ref.name, filename) for filename in files        ):            continue        yield refdef file_exists(gitroot, refname, filename):    cmd = (        "git",        "cat-file",        "-e",        "{}:{}".format(refname, filename),    )    proc = subprocess.run(cmd, cwd=gitroot, capture_output=True)    return proc.returncode == 0def copy_tree(src, dst, reference, sourcepath="."):    with tempfile.SpooledTemporaryFile() as fp:        cmd = (            "git",            "archive",            "--format",            "tar",            reference.commit,            "--",            sourcepath,        )        subprocess.check_call(cmd, stdout=fp)        fp.seek(0)        with tarfile.TarFile(fileobj=fp) as tarfp:            tarfp.extractall(dst)
 |