From 544a49200066b87cbf5c83336fb573e2fb5256d9 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Sun, 10 Mar 2024 21:27:45 +0100 Subject: [PATCH] wip: dependency-tracked build triggering --- buildbot_nix/__init__.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/buildbot_nix/__init__.py b/buildbot_nix/__init__.py index a2d8775..371f95b 100644 --- a/buildbot_nix/__init__.py +++ b/buildbot_nix/__init__.py @@ -60,11 +60,13 @@ class BuildTrigger(Trigger): builds_scheduler: str, skipped_builds_scheduler: str, jobs: list[dict[str, Any]], + drv_info: dict[str, Any], **kwargs: Any, ) -> None: if "name" not in kwargs: kwargs["name"] = "trigger" self.jobs = jobs + self.drv_info = drv_info self.config = None self.builds_scheduler = builds_scheduler self.skipped_builds_scheduler = skipped_builds_scheduler @@ -87,6 +89,25 @@ class BuildTrigger(Trigger): build_props = self.build.getProperties() source = f"nix-eval-lix" + all_deps = dict() + for drv, info in self.drv_info.items(): + all_deps[drv] = set(info.get("inputDrvs").keys()) + def closure_of(key, deps): + r = set() + r.add(key) + while True: + more = set(r) + more.update(*( deps[k] for k in r )) + if r == more: + break + r = more + r.remove(key) + return r + job_set = set(( drv for drv in ( job.get("drvPath") for job in self.jobs ) if drv )) + all_deps = { k: list(closure_of(k, all_deps).intersection(job_set)) for k in job_set } + + build_props.setProperty("sched_state", all_deps, source, True) + triggered_schedulers = [] for job in self.jobs: attr = job.get("attr", "eval-error") @@ -178,6 +199,24 @@ class NixEvalCommand(buildstep.ShellMixin, steps.BuildStep): if not system or system in self.supported_systems: # report eval errors filtered_jobs.append(job) + drv_show_log: Log = yield self.getLog("stdio") + drv_show_log.addStdout(f"getting derivation infos\n") + cmd = yield self.makeRemoteShellCommand( + stdioLogName=None, + collectStdout=True, + command=( + ["nix", "derivation", "show", "--recursive"] + + [ drv for drv in (job.get("drvPath") for job in filtered_jobs) if drv ] + ), + ) + yield self.runCommand(cmd) + drv_show_log.addStdout(f"done\n") + try: + drv_info = json.loads(cmd.stdout) + except json.JSONDecodeError as e: + msg = f"Failed to parse `nix derivation show` output for {cmd.command}" + raise BuildbotNixError(msg) from e + self.build.addStepsAfterCurrentStep( [ BuildTrigger( @@ -185,6 +224,7 @@ class NixEvalCommand(buildstep.ShellMixin, steps.BuildStep): skipped_builds_scheduler=f"lix-nix-skipped-build", name="build flake", jobs=filtered_jobs, + drv_info=drv_info, ), ], )