From 64f4695932ff4d27967cf4f0e854e40371dbcc90 Mon Sep 17 00:00:00 2001 From: sommerfeld Date: Thu, 17 Sep 2026 15:05:36 +0100 Subject: Fetch Rust crates from the static archive server --- justfile | 5 +++++ nix/fetch-crate.nix | 17 +++++++++++++++++ nix/flake.nix | 21 ++++++++++++++++++++- tests/test_crate_fetchurl.py | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 nix/fetch-crate.nix create mode 100644 tests/test_crate_fetchurl.py diff --git a/justfile b/justfile index 6d2c2e9..7267729 100644 --- a/justfile +++ b/justfile @@ -99,6 +99,11 @@ arch-news-read: # Refresh package releases and Nix flake inputs, then re-activate the profile. nix-update: _nix-release-update _nix-flake-update nix-switch +# Fetch a locked Rust crate and repeat the download without using its cached output. +nix-crate-check: + nix build --no-link ./nix#checks.x86_64-linux.crate-download + nix build --no-link --rebuild ./nix#checks.x86_64-linux.crate-download + _nix-release-update: @bash "{{ justfile_directory() }}/nix/update-releases.sh" diff --git a/nix/fetch-crate.nix b/nix/fetch-crate.nix new file mode 100644 index 0000000..733d83a --- /dev/null +++ b/nix/fetch-crate.nix @@ -0,0 +1,17 @@ +fetchurl: attrs: +let + crate = builtins.match "https://crates[.]io/api/v1/crates/([^/]+)/([^/]+)/download" ( + attrs.url or "" + ); +in +fetchurl ( + attrs + // ( + if crate == null then + { } + else + { + url = "https://static.crates.io/crates/${builtins.elemAt crate 0}/${builtins.elemAt crate 0}-${builtins.elemAt crate 1}.crate"; + } + ) +) diff --git a/nix/flake.nix b/nix/flake.nix index b140bf0..33dbe42 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -44,7 +44,11 @@ # Expose external flake packages so common.nix can list them next to # nixpkgs packages without threading inputs into every module. (final: prev: { - tuicr = tuicr.packages.${system}.default; + tuicr = + (final.callPackage tuicr.inputs.naersk { + fetchurl = import ./fetch-crate.nix final.fetchurl; + }).buildPackage + tuicr; aibox = aibox.packages.${system}.default; claude-release = prev.claude-code.overrideAttrs { version = releases.claude.version; @@ -257,6 +261,21 @@ }; in { + checks.${system}.crate-download = + let + lock = builtins.fromTOML (builtins.readFile "${tuicr}/Cargo.lock"); + crate = builtins.head ( + builtins.filter ( + package: (package.source or "") == "registry+https://github.com/rust-lang/crates.io-index" + ) lock.package + ); + in + import ./fetch-crate.nix pkgs.fetchurl { + name = "crate-download-check-${crate.name}-${crate.version}"; + url = "https://crates.io/api/v1/crates/${crate.name}/${crate.version}/download"; + sha256 = crate.checksum; + }; + devShells.${system}.default = pkgs.mkShellNoCC { packages = with pkgs; [ basedpyright diff --git a/tests/test_crate_fetchurl.py b/tests/test_crate_fetchurl.py new file mode 100644 index 0000000..b4619eb --- /dev/null +++ b/tests/test_crate_fetchurl.py @@ -0,0 +1,41 @@ +import json +import subprocess +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] + + +class CrateFetchTests(unittest.TestCase): + def evaluate(self, attrs): + expression = ( + f"let fetch = import {ROOT}/nix/fetch-crate.nix (args: args); " + f"in fetch (builtins.fromJSON {json.dumps(json.dumps(attrs))})" + ) + return json.loads( + subprocess.check_output( + ["nix", "eval", "--impure", "--json", "--expr", expression], text=True + ) + ) + + def test_crate_uses_static_archive_and_keeps_hash(self): + attrs = { + "name": "download-hashbrown-0.16.1", + "url": "https://crates.io/api/v1/crates/hashbrown/0.16.1/download", + "sha256": "locked-checksum", + } + self.assertEqual( + self.evaluate(attrs), + { + **attrs, + "url": "https://static.crates.io/crates/hashbrown/hashbrown-0.16.1.crate", + }, + ) + + def test_other_downloads_are_unchanged(self): + attrs = {"url": "https://example.org/source.tar.gz", "hash": "unchanged"} + self.assertEqual(self.evaluate(attrs), attrs) + + def test_url_lists_are_unchanged(self): + attrs = {"urls": ["https://example.org/source.tar.gz"], "hash": "unchanged"} + self.assertEqual(self.evaluate(attrs), attrs) -- cgit v1.3.1