commit 5177d942e477507a94369207d15feef325652e5b
Author: clerie <git@clerie.de>
Date:   Fri Jul 21 21:46:03 2023 +0200

    Init repository

diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..69f94c6
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,27 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1688679045,
+        "narHash": "sha256-t3xGEfYIwhaLTPU8FLtN/pLPytNeDwbLI6a7XFFBlGo=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "3c7487575d9445185249a159046cc02ff364bff8",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..3dab73f
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,37 @@
+{
+  inputs = {
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+  };
+  outputs = { self, nixpkgs, ... }: {
+    packages.x86_64-linux = let
+      pkgs = import nixpkgs { system = "x86_64-linux"; };
+    in {
+      update-from-hydra = pkgs.python3Packages.buildPythonPackage rec {
+        pname = "update-from-hydra";
+        version = "0.0.1";
+
+        src = ./.;
+
+        format = "pyproject";
+
+        buildInputs = [ pkgs.python3Packages.hatchling ];
+        propagatedBuildInputs = [ pkgs.python3Packages.requests ];
+      };
+      default = self.packages.x86_64-linux.update-from-hydra;
+    };
+
+    apps.x86_64-linux = {
+      update-from-hydra = {
+        type = "app";
+        program = self.packages.x86_64-linux.update-from-hydra + "/bin/update-from-hydra";
+      };
+      default = self.apps.x86_64-linux.update-from-hydra;
+    };
+
+    hydraJobs = {
+      inherit (self)
+        packages;
+    };
+  };
+}
+
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..b062086
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,23 @@
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[project]
+name = "update-from-hydra"
+version = "0.0.1"
+authors = [
+  { name="clerie", email="hallo@clerie.de" },
+]
+description = ""
+requires-python = ">=3.7"
+classifiers = [
+    "Programming Language :: Python :: 3",
+    "Operating System :: OS Independent",
+]
+dependencies = [
+  "requests"
+]
+
+
+[project.scripts]
+update-from-hydra = "update_from_hydra:cli"
diff --git a/update_from_hydra.py b/update_from_hydra.py
new file mode 100644
index 0000000..2808df6
--- /dev/null
+++ b/update_from_hydra.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+
+import argparse
+import hashlib
+from pathlib import Path
+import requests
+import subprocess
+import sys
+
+def get_hydra_store_path(url):
+    """
+    Accepts an url to a hydra build.
+    Can be:
+    https://hydra.clerie.de/job/nixfiles/nixfiles/iso/latest-finished
+    Or:
+    https://hydra.clerie.de/build/917
+    """
+
+    r = requests.get(url, headers={"Accept": "application/json"})
+    r.raise_for_status()
+
+    return Path(r.json()["buildoutputs"]["out"]["path"])
+
+
+def cli():
+    parser = argparse.ArgumentParser(
+        prog="update-from-hydra",
+        description="Fetch the latest build of a Hydra job and set it as a specified symlink",
+    )
+    parser.add_argument("hydra_url")
+    parser.add_argument("update_path")
+    parser.add_argument("cache_store_uri")
+    args = parser.parse_args()
+    hydra_url = args.hydra_url
+    update_path = Path(args.update_path).absolute()
+    cache_store_uri = args.cache_store_uri
+
+    print("Update url:", hydra_url)
+    print("Path to update:", update_path)
+
+    current_store_path = None
+
+    if update_path.exists():
+        if not update_path.is_symlink():
+            print("Path to update is not a symlink")
+            exit(1)
+
+        current_store_path = update_path.readlink()
+        print("Current store path:", current_store_path)
+    else:
+        print("No current store path, update path does not exist")
+
+    print("Look up Hydra build metadata")
+    hydra_store_path = get_hydra_store_path(hydra_url)
+    print("Store path in hydra:", hydra_store_path)
+
+    if current_store_path == hydra_store_path:
+        print("Current store path is up to date")
+        exit()
+
+    print("Downloading new store paths")
+    subprocess.run(["nix", "copy", "--from", cache_store_uri, hydra_store_path])
+    print("Finished downloading")
+
+    print("Updating path to update")
+    update_path.parent.mkdir(parents=True, exist_ok=True)
+    tmp_update_path = update_path.parent / ( update_path.name + ".new")
+    print("Creating temporary symlink:", tmp_update_path)
+    tmp_update_path.symlink_to(hydra_store_path)
+    print("Rename symlink to:", update_path)
+    tmp_update_path.rename(update_path)
+
+    print("Adding to gcroot")
+    try:
+        gcroots_dir = Path("/nix/var/nix/gcroots/update-from-hydra")
+        update_dir_hash = hashlib.sha256(bytes(update_path)).hexdigest()
+        gcroots_dir.mkdir(parents=True, exist_ok=True)
+        gcroots_symlink = gcroots_dir / update_dir_hash
+        tmp_gcroots_symlink = gcroots_dir / (update_dir_hash + ".new")
+        print("Creating temporary symlink:", tmp_gcroots_symlink)
+        tmp_gcroots_symlink.symlink_to(update_path)
+        print("Rename symlink to:", gcroots_symlink)
+        tmp_gcroots_symlink.rename(gcroots_symlink)
+    except PermissionError:
+        print("Unable to create garbage collector root") 
+
+
+if __name__ == "__main__":
+    cli()