From bd639314967d964f1116ddb757986d0b00e79328 Mon Sep 17 00:00:00 2001 From: Matěj Cepl Date: Wed, 20 Jul 2022 18:10:52 +0200 Subject: Generate actual content of commits. Should work even with binary files. --- osc_fast_export.py | 56 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/osc_fast_export.py b/osc_fast_export.py index 2bfa4d6..0042100 100755 --- a/osc_fast_export.py +++ b/osc_fast_export.py @@ -4,12 +4,18 @@ import collections import configparser from datetime import datetime +import logging +import os.path import pathlib import subprocess +import sys from typing import List import xml.etree.ElementTree as ET +logging.basicConfig(format="%(levelname)s:%(funcName)s:%(message)s", level=logging.INFO) +log = logging.getLogger("osc_fast_export") + authorsfile = pathlib.Path(".git", "authorsfile.txt") # For reading section-less config files @@ -41,8 +47,9 @@ def osc_log() -> List[LogEntry]: log_str = subprocess.run( ["osc", "log", "--xml"], check=True, text=True, stdout=subprocess.PIPE ).stdout - except subprocess.CalledProcessError: - raise + except subprocess.CalledProcessError as exc: + raise RuntimeError(f"Cannot collect log of the package!") from exc + tree = ET.fromstring(log_str) log_list = [ LogEntry( @@ -58,27 +65,56 @@ def osc_log() -> List[LogEntry]: return log_list -def export_data(dt: str) -> str: - return f"data {len(dt)}\n{dt}" +def checkout_revision(rev: int): + NULL = open(os.devnull, "wb") + try: + subprocess.check_call( + ["osc", "up", "-r", f"{rev}"], stdout=NULL, stderr=subprocess.PIPE + ) + subprocess.check_call(["osc", "clean"], stdout=NULL, stderr=subprocess.PIPE) + except subprocess.CalledProcessError as exc: + raise RuntimeError(f"Cannot checkout revision {rev}!") from exc def print_export(entry: LogEntry) -> int: mark = entry.rev author = authors.get(entry.author, "") - date = int(datetime.timestamp(entry.date)) + checkout_revision(entry.rev) print("commit refs/heads/master") print(f"mark :{mark}") if entry.md5: print(f"original-oid {entry.md5}") - print(f"committer {author} {date} +0000") - print(export_data(entry.msg)) + print(f"committer {author} {entry.date:%s} +0000") + print(f"data {len(entry.msg)}\n{entry.msg}") if last_mark: print(f"from :{last_mark}") - # The following is dummy, needs to be replaced by actual content of each commit. + + # Create actual content of the commit + # It is easier just to wipe out everything and include files again. print("deleteall") - print("M 644 inline tralala") - print(export_data("tralalala")) + for dirpath, dirnames, filenames in os.walk("."): + # TODO are osc notes (aka osc comment) a thing? + dirpath = os.path.relpath(dirpath, ".") + if dirpath.startswith(".osc"): + continue + # It seems git-fast-export doesn't export directories at all + # and git-fast-import just creates them when needed. + # if dirpath != '.': + # # create directory + # print(f'M 040000 inline {dirpath}') + for fn in filenames: + fname = os.path.relpath(os.path.join(dirpath, fn), ".") + log.debug("dirpath = %s, fname = %s", dirpath, fname) + fstat = f"{os.stat(fname).st_mode:o}" + print(f"M {fstat} inline {fname}") + with open(fname, "rb") as inf: + dt = inf.read() + print(f"data {len(dt)}") + sys.stdout.flush() + with os.fdopen(sys.stdout.fileno(), "wb", closefd=False) as stdout: + stdout.write(dt) + stdout.flush() print("") return mark -- cgit