import argparse import json import os import subprocess GET_INPUTS_CMD = [ "nix-instantiate", "--eval", "--json", # This parser is stupid, better provide it with pre-eaten stuff "--expr", "builtins.fromJSON (builtins.toJSON (import ./flake.nix).inputs)", ] def process_flake(flake: str) -> None: # get full path if not os.path.isfile(flake): raise FileNotFoundError(f"Flake not found: {flake}") dir = os.path.dirname(flake) # import dependencies p = subprocess.run(GET_INPUTS_CMD, cwd=dir, stdout=subprocess.PIPE) deps = json.loads(p.stdout) p.check_returncode() # for each dependency for dep_name, dep in deps.items(): dep_url = dep["url"] # if not local path, continue if not ( dep_url.startswith("path:") or dep_url.startswith("git+file:") ): continue if dep.get("flake", True): # get flake file corresponding dep_path = dep_url.split(":")[1] if not dep_path.startswith("/"): dep_path = os.path.join(dir, dep_path) dep_path = os.path.normpath(dep_path) dep_flake = os.path.join(dep_path, "flake.nix") # call this function with the flake file process_flake(dep_flake) # update lockfile cmd = [ "nix", "--extra-experimental-features", "nix-command", "--extra-experimental-features", "flakes", "flake", "update", dep_name, ] p = subprocess.run(cmd, cwd=dir) p.check_returncode() if __name__ == "__main__": parser = argparse.ArgumentParser( description="Recursively update lockfiles " "of flakes located on the system" ) parser.add_argument("flake", help="Starting flake", default="flake.nix") args = parser.parse_args() process_flake(args.flake)