File indexing completed on 2024-05-19 15:24:57

0001 #!/usr/bin/env python3
0002 
0003 import os
0004 import yaml
0005 import shlex
0006 import pathlib
0007 import argparse
0008 import subprocess
0009 from collections import namedtuple
0010 
0011 CiData = namedtuple("CiData", ["entries", "variables", "default", "args"])
0012 
0013 
0014 def list_jobs(data: CiData):
0015     for name in sorted(data.entries.keys()):
0016         print(name)
0017 
0018 
0019 def write_script(file, steps, name):
0020     file.write(r"echo -e '\x1b[1m%s\x1b[m'" % name)
0021     file.write("\n")
0022     for step in steps:
0023         file.write(step + "\n")
0024 
0025 
0026 def exec_cmd(cmd_args):
0027     print(" ".join(map(shlex.quote, cmd_args)))
0028     subprocess.call(cmd_args)
0029 
0030 
0031 def run_job(data: CiData):
0032     job_data = data.default
0033     job_data.update(data.entries[data.args.job])
0034 
0035     image = job_data["image"]
0036 
0037     git_recursive = data.variables.get("GIT_SUBMODULE_STRATEGY") == "recursive"
0038 
0039     parent_dir = data.args.work_path
0040     job_filename = data.args.job.replace(":", "_").replace("/", "_")
0041     work_dir = parent_dir / job_filename
0042 
0043     if data.args.local_files:
0044         work_dir = data.args.clone_url
0045     elif not work_dir.exists():
0046         parent_dir.mkdir(parents=True, exist_ok=True)
0047         git_args = [data.args.clone_url, job_filename, "-b", data.args.branch]
0048         if git_recursive:
0049             git_args.append("--recursive")
0050         exec_cmd(["git", "-C", str(parent_dir), "clone"] + git_args)
0051     else:
0052         exec_cmd(["git", "-C", str(work_dir), "pull"])
0053         if git_recursive:
0054             exec_cmd(["git", "-C", str(work_dir), "submodule", "update"])
0055 
0056     script_filename = parent_dir / (job_filename + ".sh")
0057     with open(script_filename, "w") as script_file:
0058         scripts = ["before_script", "script", "after_script"]
0059         script_file.write("#!/usr/bin/env bash\nset -ex\ncd /ci\n")
0060         for script in scripts:
0061             write_script(script_file, job_data.get(script, []), script)
0062     script_filename.chmod(0o755)
0063 
0064     script_wrapper_filename = parent_dir / "ci_wrapper.sh"
0065     with open(script_wrapper_filename, "w") as script_file:
0066         script_file.write("#!/usr/bin/env bash\ncd /ci\n/ci.sh || bash")
0067     script_wrapper_filename.chmod(0o755)
0068 
0069     docker_vars = ["-e", "DISPLAY"]
0070     for item in data.variables.items():
0071         docker_vars.append("-e")
0072         docker_vars.append("%s=%s" % item)
0073 
0074     if data.args.privileged:
0075         docker_vars.append("--privileged")
0076 
0077     exec_cmd([
0078         "docker",
0079         "run", "-it",
0080         "-v", "%s:/ci" % work_dir,
0081         "-v", "%s:/ci.sh" % script_filename,
0082         "-v", "%s:/ci_wrapper.sh" % script_wrapper_filename,
0083         "-v" "/tmp/.X11-unix",
0084         ] + docker_vars + [
0085         image,
0086         "bash", "-c", "/ci_wrapper.sh"
0087     ])
0088 
0089 
0090 def main():
0091     root = pathlib.Path(__file__).parent.parent
0092     file = root / ".gitlab-ci.yml"
0093 
0094     parser = argparse.ArgumentParser()
0095     parser.add_argument("--input-file", "-i", default=file, type=pathlib.Path)
0096 
0097     sub = parser.add_subparsers()
0098     sub.add_parser("list-jobs", aliases=["list", "ls"]).set_defaults(action=list_jobs)
0099 
0100     sub_run = sub.add_parser("run")
0101     sub_run.set_defaults(action=run_job)
0102     sub_run.add_argument("job")
0103     sub_run.add_argument("--local-files", action="store_true", help="Use the directory from --clone-url as is instead of cloning from git")
0104     sub_run.add_argument("--privileged", action="store_true")
0105     sub_run.add_argument("--clone-url", default=str(root)) # default="https://gitlab.com/mattbas/glaxnimate.git")
0106     sub_run.add_argument("--work-path", default=pathlib.Path("/tmp/glaxnimate_ci"), type=pathlib.Path)
0107     sub_run.add_argument("--branch", "-b", default="master")
0108 
0109     ns = parser.parse_args()
0110 
0111     with open(ns.input_file) as infile:
0112         doc = yaml.load(infile.read(), Loader=yaml.FullLoader)
0113 
0114     default = doc.pop("default", {})
0115     variables = doc.pop("variables", {})
0116 
0117     ns.action(CiData(doc, variables, default, ns))
0118 
0119 
0120 if __name__ == "__main__":
0121     main()