diff --git a/hosts/comfy-station/default.nix b/hosts/comfy-station/default.nix index db89514..7fb9e37 100644 --- a/hosts/comfy-station/default.nix +++ b/hosts/comfy-station/default.nix @@ -27,6 +27,7 @@ self.nixosModules.firefox self.nixosModules.kdeconnect self.nixosModules.ntsync + self.nixosModules.follow-hive-nixpkgs ]; }; } diff --git a/hosts/monolith/default.nix b/hosts/monolith/default.nix index 194eab4..39c2fde 100644 --- a/hosts/monolith/default.nix +++ b/hosts/monolith/default.nix @@ -34,6 +34,7 @@ self.nixosModules.spotify-shortcuts self.nixosModules.ntsync self.nixosModules.spicetify + self.nixosModules.follow-hive-nixpkgs ]; }; } diff --git a/modules/tools/follow-hive-nixpkgs/.envrc b/modules/tools/follow-hive-nixpkgs/.envrc new file mode 100644 index 0000000..9006677 --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/.envrc @@ -0,0 +1 @@ +use flake ../../#follow-hive-nixpkgs --show-trace diff --git a/modules/tools/follow-hive-nixpkgs/_derivation.nix b/modules/tools/follow-hive-nixpkgs/_derivation.nix new file mode 100644 index 0000000..74483c7 --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/_derivation.nix @@ -0,0 +1,8 @@ +{python3Packages}: +with python3Packages; + buildPythonApplication { + name = "follow-hive-nixpkgs"; + pyproject = true; + build-system = [setuptools]; + src = ./.; + } diff --git a/modules/tools/follow-hive-nixpkgs/_shell.nix b/modules/tools/follow-hive-nixpkgs/_shell.nix new file mode 100644 index 0000000..5212a4a --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/_shell.nix @@ -0,0 +1,15 @@ +{pkgs ? import {}}: let + drv = pkgs.callPackage ./_derivation.nix {}; +in + pkgs.mkShell { + packages = [ + pkgs.pyright + pkgs.black + ]; + + inputsFrom = [drv]; + + shellHook = '' + export PYTHONPATH="$PYTHONPATH:$(pwd)" + ''; + } diff --git a/modules/tools/follow-hive-nixpkgs/default.nix b/modules/tools/follow-hive-nixpkgs/default.nix new file mode 100644 index 0000000..bd9e871 --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/default.nix @@ -0,0 +1,26 @@ +{self, ...}: { + flake.overlays.follow-hive-nixpkgs = final: prev: { + follow-hive-nixpkgs = final.callPackage ./_derivation.nix {}; + }; + + perSystem = {pkgs, ...}: { + packages.follow-hive-nixpkgs = pkgs.callPackage ./_derivation.nix {}; + devShells.follow-hive-nixpkgs = import ./_shell.nix {inherit pkgs;}; + }; + + flake.nixosModules.follow-hive-nixpkgs-overlay = { + nixpkgs.overlays = [ + self.overlays.follow-hive-nixpkgs + ]; + }; + + flake.nixosModules.follow-hive-nixpkgs = {pkgs, ...}: { + imports = [ + self.nixosModules.follow-hive-nixpkgs-overlay + ]; + + environment.systemPackages = [ + pkgs.follow-hive-nixpkgs + ]; + }; +} diff --git a/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/__init__.py b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/app/__init__.py b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/app/__init__.py new file mode 100644 index 0000000..0cba551 --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/app/__init__.py @@ -0,0 +1,5 @@ +from follow_hive_nixpkgs.app import app + + +def main(): + app.main() diff --git a/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/app/app.py b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/app/app.py new file mode 100644 index 0000000..329978c --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/app/app.py @@ -0,0 +1,30 @@ +from follow_hive_nixpkgs.config import Config +from follow_hive_nixpkgs.lock import loadNixpkgs, writeNixpkgs +from pathlib import Path +import json + + +def dry_run(c: Config): + s = loadNixpkgs(c.source_lock, c.source_nixpkgs) + t = loadNixpkgs(c.target_lock, "nixpkgs") + + print( + f"Would change {c.target_lock} from:\n{json.dumps(t, indent=2)} to:\n{json.dumps(s, indent=2)}\nWith values from {c.source_lock}" + ) + + +def main(): + c = Config.load( + [ + Path.home() / ".config/follow-hive-nixpkgs/config.json", + Path("/etc/follow-hive-nixpkgs/config.json"), + ] + ) + + print(c) + + if c.dry: + dry_run(c) + else: + s = loadNixpkgs(c.source_lock, c.source_nixpkgs) + writeNixpkgs(s, c.target_lock) diff --git a/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/config.py b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/config.py new file mode 100644 index 0000000..6616b73 --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/config.py @@ -0,0 +1,76 @@ +from dataclasses import dataclass +from pathlib import Path +from typing import Self +import argparse +import sys +import json + + +@dataclass +class Config: + source_lock: Path = Path.home() / ".hive/flake.lock" + source_nixpkgs: str = "nixpkgs-unstable" + target_lock: Path = Path.cwd() / "flake.lock" + dry: bool = False + + @classmethod + def load(cls, paths: list[Path]) -> Self: + c = cls() + + args = cls.argparse() + + c.dry = args.dry + + # Target lock can only be set via args + if args.target_lock: + c.target_lock = Path(args.target_lock) + + # We do not need to read config files. + if args.source_lock: + c.source_lock = Path(args.source_lock) + return c + + # Check if source_lock is set somewhere + for p in paths: + if not p.exists(): + continue + + with p.open(mode="r") as f: + cfg = json.load(f) + c.source_lock = Path(cfg["source_lock"]) + c.source_nixpkgs = cfg["source_nixpkgs"] + break + + return c + + @staticmethod + def argparse() -> argparse.Namespace: + args = argparse.ArgumentParser() + args.add_argument( + "--source_lock", + type=Path, + default=None, + required=False, + help="The flake.lock file to read nixpkgs from.", + ) + args.add_argument( + "--source_nixpkgs", + type=Path, + default=None, + required=False, + help="The nixpkgs in flake.lock to use.", + ) + args.add_argument( + "--target_lock", + type=Path, + default=None, + required=False, + help="The flake.lock file to write nixpkgs to. Use CWD/flake.lock if unset", + ) + args.add_argument( + "--dry", + action="store_true", + help="Only show what would be done.", + ) + + return args.parse_args(sys.argv[1:]) diff --git a/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/lock.py b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/lock.py new file mode 100644 index 0000000..f40ec38 --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/follow_hive_nixpkgs/lock.py @@ -0,0 +1,34 @@ +import json +from pathlib import Path +import sys + + +def loadNixpkgs(source: Path, nixpkgs: str) -> dict: + if not source.exists(): + print(f"{source} does not exist.") + sys.exit(1) + + with source.open(mode="r") as f: + src = json.load(f) + if nixpkgs not in src["nodes"]: + print(f"There is no {nixpkgs} entry in {source}") + sys.exit(1) + return src["nodes"][nixpkgs] + + +def writeNixpkgs(nixpkgs: dict, target: Path): + if not target.exists(): + print(f"{target} does not exist.") + sys.exit(1) + + with target.open(mode="r+") as f: + tgt = json.load(f) + if "nixpkgs" not in tgt["nodes"]: + print(f"There is no nixpkgs entry in {target}") + sys.exit(1) + + tgt["nodes"]["nixpkgs"] = nixpkgs + + f.seek(0) + json.dump(tgt, f, indent=2) + f.truncate() diff --git a/modules/tools/follow-hive-nixpkgs/setup.py b/modules/tools/follow-hive-nixpkgs/setup.py new file mode 100644 index 0000000..ab7632f --- /dev/null +++ b/modules/tools/follow-hive-nixpkgs/setup.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +from setuptools import setup, find_packages + +setup( + name="follow_hive_nixpkgs", + version="1.0", + packages=find_packages(), + entry_points={ + "console_scripts": [ + "follow-hive-nixpkgs=follow_hive_nixpkgs.app:main", + ], + }, +)