115 lines
2.5 KiB
Python
115 lines
2.5 KiB
Python
import os
|
|
import subprocess
|
|
import tempfile
|
|
import hashlib
|
|
from datetime import datetime
|
|
|
|
|
|
# ----------------------------
|
|
# utility: run command
|
|
# ----------------------------
|
|
def run(cmd, cwd="/"):
|
|
process = subprocess.Popen(
|
|
cmd,
|
|
shell=True,
|
|
cwd=cwd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True
|
|
)
|
|
|
|
out = []
|
|
for line in process.stdout:
|
|
out.append(line)
|
|
|
|
process.wait()
|
|
return "".join(out), process.returncode
|
|
|
|
|
|
# ----------------------------
|
|
# git (Forgejo primary)
|
|
# ----------------------------
|
|
def snapshot_git(repo_url):
|
|
workdir = tempfile.mkdtemp(prefix="fester-snap-git-")
|
|
|
|
run(f"git clone --depth 1 {repo_url} {workdir}")
|
|
|
|
return workdir
|
|
|
|
|
|
# ----------------------------
|
|
# hg adapter (snapshot only)
|
|
# ----------------------------
|
|
def snapshot_hg(repo_url):
|
|
workdir = tempfile.mkdtemp(prefix="fester-snap-hg-")
|
|
|
|
run(f"hg clone {repo_url} {workdir}")
|
|
|
|
return workdir
|
|
|
|
|
|
# ----------------------------
|
|
# svn adapter (export only)
|
|
# ----------------------------
|
|
def snapshot_svn(repo_url):
|
|
workdir = tempfile.mkdtemp(prefix="fester-snap-svn-")
|
|
|
|
run(f"svn checkout {repo_url} {workdir}")
|
|
|
|
return workdir
|
|
|
|
|
|
# ----------------------------
|
|
# cvs adapter (legacy dump)
|
|
# ----------------------------
|
|
def snapshot_cvs(repo_url):
|
|
workdir = tempfile.mkdtemp(prefix="fester-snap-cvs-")
|
|
|
|
# best-effort export only
|
|
run(f"cvs export -d {workdir} {repo_url}")
|
|
|
|
return workdir
|
|
|
|
|
|
# ----------------------------
|
|
# unified entry point
|
|
# ----------------------------
|
|
def create_snapshot(source):
|
|
kind = source["type"]
|
|
url = source["url"]
|
|
|
|
if kind == "git":
|
|
path = snapshot_git(url)
|
|
elif kind == "hg":
|
|
path = snapshot_hg(url)
|
|
elif kind == "svn":
|
|
path = snapshot_svn(url)
|
|
elif kind == "cvs":
|
|
path = snapshot_cvs(url)
|
|
else:
|
|
raise Exception(f"Unsupported VCS type: {kind}")
|
|
|
|
return fingerprint(path)
|
|
|
|
|
|
# ----------------------------
|
|
# deterministic fingerprint
|
|
# ----------------------------
|
|
def fingerprint(path):
|
|
sha = hashlib.sha256()
|
|
|
|
for root, dirs, files in os.walk(path):
|
|
for f in sorted(files):
|
|
fp = os.path.join(root, f)
|
|
try:
|
|
with open(fp, "rb") as fh:
|
|
sha.update(fh.read())
|
|
except:
|
|
pass
|
|
|
|
return {
|
|
"path": path,
|
|
"hash": sha.hexdigest(),
|
|
"timestamp": datetime.utcnow().isoformat() + "Z"
|
|
}
|