#!/usr/bin/env python3 # Copyright 2005-2015 Linus Torvalds and others # Copyright 2015, 2019, 2021 Codethink Limited # # Based on git's contrib/fast-import/import-zips.py; modified for Lorry. # zip archive frontend for git-fast-import # # For example: # # mkdir project; cd project; git init # python import-zips.py *.zip # git log --stat import-zips import calendar import os.path import struct import subprocess import sys from zipfile import ZipFile branch_name = "master" branch_ref = "refs/heads/%s" % branch_name committer_name = "Lorry Zip Importer" committer_email = "lorry-zip-importer@lorry" # File header 'extra' field tags EXT_TAG_UNIX0 = 0x000D # PKWARE Unix, aka Unix type 0 EXT_TAG_TIME = 0x5455 # Extended Timestamp EXT_TIME_FLAG_MTIME = 1 # mtime present (and first) EXT_TAG_UNIX1 = 0x5855 # Info-ZIP Unix type 1 # Iterate over fields within a file header 'extra' block def zip_extra_fields(extra): pos = 0 while len(extra) >= pos + 4: tag, size = struct.unpack("= 1 and data[0] & EXT_TIME_FLAG_MTIME: format = "= min_len: return struct.unpack(format, data[:min_len])[0] # Timestamps in the main header are in local time, but the time # zone offset is unspecified. We choose to interpret them as UTC. return calendar.timegm(info.date_time + (0, 0, 0)) def export(zipfile, fast_import): def printlines(list): for str in list: fast_import.write(str.encode("utf-8") + b"\n") commit_time = 0 next_mark = 1 common_prefix = None mark = dict() zip = ZipFile(zipfile, "r") for name in zip.namelist(): if name.endswith("/"): continue info = zip.getinfo(name) commit_time = max(commit_time, zip_info_mtime(info)) if common_prefix is None: common_prefix = name[: name.rfind("/") + 1] else: while not name.startswith(common_prefix): last_slash = common_prefix[:-1].rfind("/") + 1 common_prefix = common_prefix[:last_slash] mark[name] = ":" + str(next_mark) next_mark += 1 printlines(("blob", "mark " + mark[name], "data " + str(info.file_size))) fast_import.write(zip.read(name) + b"\n") committer = committer_name + " <" + committer_email + "> %d +0000" % commit_time zipfile_basename = os.path.basename(zipfile) printlines( ( "commit " + branch_ref, "committer " + committer, "data <...") sys.exit(1) with subprocess.Popen( "git fast-import --quiet", shell=True, stdin=subprocess.PIPE ) as import_proc: for zipfile in sys.argv[1:]: export(zipfile, import_proc.stdin) import_proc.stdin.close() if import_proc.wait() != 0: sys.exit(1) main()