hackport-0.9.0.0: cabal/scripts/release/download-artifacts-from-pipeline.py
#!/usr/bin/env python3
from pathlib import Path
import argparse
import json
import logging
import subprocess
import gitlab
import os
logging.basicConfig(level=logging.INFO)
def strip_prefix(s, prefix):
if s.startswith(prefix):
return s[len(prefix):]
else:
return None
def job_triple(job_name):
bindists = {
"build-linux-alpine: [i386, alpine3_12, 9.0.2]": "i386-linux-alpine3_12",
"build-linux-alpine: [x86_64, alpine3_12]": "x86_64-linux-alpine3_12",
"build-linux: [aarch64, aarch64-linux, deb10]": "aarch64-linux-deb10",
"build-linux: [aarch64, aarch64-linux, deb11]": "aarch64-linux-deb11",
"build-linux: [i386, x86_64-linux, deb9]": "i386-linux-deb9",
"build-linux: [x86_64, x86_64-linux, centos7]": "x86_64-linux-centos7",
"build-linux: [x86_64, x86_64-linux, deb10]": "x86_64-linux-deb10",
"build-linux: [x86_64, x86_64-linux, deb11]": "x86_64-linux-deb11",
"build-linux: [x86_64, x86_64-linux, deb9]": "x86_64-linux-deb9",
"build-linux: [x86_64, x86_64-linux, fedora33]": "x86_64-linux-fedora33",
"build-linux: [x86_64, x86_64-linux, rocky8]": "x86_64-linux-rocky8",
"build-linux: [x86_64, x86_64-linux, ubuntu18_04]": "x86_64-linux-ubuntu18_04",
"build-linux: [x86_64, x86_64-linux, ubuntu20_04]": "x86_64-linux-ubuntu20_04",
"build-x86_64-windows": "x86_64-windows",
"build-aarch64-darwin": "aarch64-darwin",
"build-x86_64-darwin": "x86_64-darwin",
}
if job_name in bindists:
return bindists[job_name]
else:
return None
class UnhandledJobException(Exception):
# Raised when there is a release job in the pipeline but we don"t explicitly handle it.
def __init__(self, name):
self.message = f"{name} is a release job but not downloaded"
super().__init__(self.message)
def fetch_artifacts(release: str, pipeline_id: int,
dest_dir: Path, gl: gitlab.Gitlab):
dest_dir.mkdir(exist_ok=True)
# Write the pipeline id into output directory
with open(f"{dest_dir}/metadata.json", "w") as out: json.dump({ "pipeline_id": pipeline_id }, out)
proj = gl.projects.get("haskell/cabal")
pipeline = proj.pipelines.get(pipeline_id)
tmpdir = Path("fetch-gitlab")
tmpdir.mkdir(exist_ok=True)
for pipeline_job in pipeline.jobs.list(all=True):
if len(pipeline_job.artifacts) == 0:
logging.info(f"job {pipeline_job.name} ({pipeline_job.id}) has no artifacts")
continue
job = proj.jobs.get(pipeline_job.id)
triple = job_triple(job.name)
if triple is None:
if job.name.startswith("build"):
raise(UnhandledJobException(job.name))
logging.info(f"ignoring {job.name}")
continue
try:
destdir = tmpdir / job.name
zip_name = Path(f"{tmpdir}/{job.name}.zip")
if not zip_name.exists() or zip_name.stat().st_size == 0:
logging.info(f"downloading archive {zip_name} for job {job.name} (job {job.id})...")
with open(zip_name, "wb") as f:
job.artifacts(streamed=True, action=f.write)
if zip_name.stat().st_size == 0:
logging.info(f"artifact archive for job {job.name} (job {job.id}) is empty")
continue
subprocess.run(["unzip", "-bo", zip_name, "-d", destdir])
if job.name == "build-x86_64-windows":
bindist_files = list(destdir.glob("out/cabal-install*.zip"))
bindist = bindist_files[0]
dest = dest_dir / bindist.name
final_destination = Path("../../release") / Path(bindist.name)
bindist.rename(final_destination)
logging.info(f"Extracted {job.name} to {final_destination}")
else:
bindist_files = list(destdir.glob("out/cabal-install*.tar.xz"))
logging.info(f"bindist_files: {bindist_files}")
bindist = bindist_files[0]
logging.info(f"Bindist: {bindist}")
dest = dest_dir / bindist.name
final_destination = Path("../../release") / Path(bindist.name)
bindist.rename(final_destination)
except Exception as e:
logging.error(f"Error fetching job {job.name}: \"{e}\"")
pass
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--pipeline", "-p", required=True, type=int, help="pipeline id")
parser.add_argument("--release", "-r", required=True, type=str, help="release name")
parser.add_argument("--output", "-o", type=Path, default=Path.cwd(), help="output directory")
parser.add_argument("--profile", "-P", default="haskell",
help="python-gitlab.cfg profile name")
args = parser.parse_args()
gl = gitlab.Gitlab.from_config(args.profile)
fetch_artifacts(args.release, args.pipeline,
dest_dir=args.output, gl=gl)
if __name__ == "__main__":
main()