deno per package cache derivations + hashes

This commit is contained in:
EatThePooh 2025-08-02 14:14:41 +07:00
parent 9c18a0c924
commit f459ec8b78
9 changed files with 203 additions and 133 deletions

View file

@ -1,24 +1,25 @@
{ pkgs, system }:
let
denoShelf = import ./deno {
inherit pkgs system;
# collective hash of all (relevant) deno sources
# mapped to resulting shared deno cache hash
knownDenoHashes = {
"2JQI9Ie/fkl5Ltr22BGJynF9tFc=" =
"sha256-7csbrTbGd6J4a0Gkj9ndKhNxv90KeOHjr7DDNal3L4Q=";
};
};
shelfSetup = pkgs.writeShellScript "setup-shelf" ''
export DENO_DIR=$PWD/.deno_cache
rm -rf $DENO_DIR
cp -r ${denoShelf.cache} $DENO_DIR
chmod -R u+w "$DENO_DIR"
{ pkgs, system, lib }:
let
denoScrollsDir = ./deno;
# TODO: add other interpreters
'';
mkScroll = subDir: lib.readDenoScroll {
inherit pkgs system subDir;
scrollsDir = denoScrollsDir;
};
scrolls = builtins.map mkScroll [
"hjq"
"uses-hjq"
];
shelfSetup =
lib.collectDenoCaches {
inherit pkgs;
denoCacheDrvs = builtins.map (s: s.env) scrolls;
};
in
{
setupScript = shelfSetup;
scrolls = builtins.map (s: s.meta) scrolls;
}

View file

@ -1,103 +0,0 @@
{ pkgs, system, knownDenoHashes }:
let
target =
let
arch = builtins.head (builtins.split "-" system);
os = builtins.elemAt (builtins.split "-" system) 1;
vendor = if os == "darwin" then "apple" else "unknown";
sys = if os == "darwin" then "darwin" else "linux-gnu";
in "${arch}-${vendor}-${sys}";
# currently unused, needed for deno compile
denort = pkgs.fetchzip {
url = "https://dl.deno.land/release/v${pkgs.deno.version}/denort-${target}.zip";
hash = "sha256-ukIk8K2CE+N+3eFs++RPiGZlhhRRVk1gjhdt77/s+4o=";
};
scrollsDir = ./.;
lib = pkgs.lib;
packageDirs = [ "./hjq" "./uses-hjq" ];
# hash only dependency-relevant files (lock files and configs)
hashDependencyFiles = dir:
let
entries = builtins.readDir dir;
# Only process directories and dependency-relevant files
relevantEntry = name: type:
if type == "directory"
then hashDependencyFiles (dir + "/${name}")
else if (lib.hasSuffix ".lock" name ||
lib.hasSuffix ".json" name ||
lib.hasSuffix ".jsonc" name)
then builtins.readFile (dir + "/${name}")
else null;
contentMap = lib.filterAttrs (_: v: v != null)
(builtins.mapAttrs relevantEntry entries);
in builtins.toJSON contentMap;
sourceContentHash = builtins.convertHash {
hash = "sha1:${builtins.hashString "sha1" (hashDependencyFiles scrollsDir)}";
toHashFormat = "base64";
};
# we assume that same lock+config files yield same deno caches here
# however, jsons need to be sorted and some sqlite files deleted
# jsr gentlemen specifically require their package metadata
# to have multiple timestamps, so they can fuck off
outputHash = knownDenoHashes.${sourceContentHash} or lib.fakeSha256;
unifiedCache = pkgs.stdenv.mkDerivation {
name = "deno-scrolls-cache";
src = scrollsDir;
nativeBuildInputs = [ pkgs.deno pkgs.jq ];
dontPatchShebangs = true;
buildPhase = ''
export DENO_DIR=$out
${lib.concatStringsSep "\n" (map (pkg:
let config = import (scrollsDir + "/${pkg}/scroll.nix");
in ''
echo "Caching ${pkg}..."
cd ${pkg}
${config.cache-command}
cd ..
''
) packageDirs)}
echo 'Go fuck yourself, SQLite!'
find $out -name "*-wal" -delete
find $out -name "*-shm" -delete
echo 'Go fuck yourself, JSON!'
find $out/npm -name "*.json" -type f 2>/dev/null | while read -r file; do
if ${pkgs.jq}/bin/jq empty "$file" 2>/dev/null; then
${pkgs.jq}/bin/jq -S . "$file" > "$file.tmp" && mv "$file.tmp" "$file"
fi
done
echo 'sourceContentHash: ${sourceContentHash}'
echo ""
echo "add me to knownHashes if you see a fake sha256 error ^"
echo "DON'T USE JSR DEPS UNLESS YOU MAKE THEM REPRODUCIBLE SOMEHOW"
echo ""
'';
installPhase = "true";
outputHashMode = "recursive";
outputHashAlgo = "sha256";
# this is basically FOD on steroids cause it
# deliberately breaks on relevant source changes
inherit outputHash;
};
in
{
cache = unifiedCache;
}

View file

@ -1,15 +1,26 @@
{
"version": "4",
"version": "5",
"specifiers": {
"npm:@types/node@*": "22.13.4",
"npm:hjson@^3.2.2": "3.2.2",
"npm:jq-web@~0.6.2": "0.6.2"
},
"npm": {
"@types/node@22.13.4": {
"integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
"dependencies": [
"undici-types"
]
},
"hjson@3.2.2": {
"integrity": "sha512-MkUeB0cTIlppeSsndgESkfFD21T2nXPRaBStLtf3cAYA2bVEFdXlodZB0TukwZiobPD1Ksax5DK4RTZeaXCI3Q=="
"integrity": "sha512-MkUeB0cTIlppeSsndgESkfFD21T2nXPRaBStLtf3cAYA2bVEFdXlodZB0TukwZiobPD1Ksax5DK4RTZeaXCI3Q==",
"bin": true
},
"jq-web@0.6.2": {
"integrity": "sha512-+7XvjBYwTx4vP5PYkf6Q6orubO/v+UgMU6By1GritrmShr9QpT3UKa4ANzXWQfhdqtBnQYXsm7ZNbdIHT6tYpQ=="
},
"undici-types@6.20.0": {
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
}
},
"workspace": {

View file

@ -8,7 +8,7 @@
format = "HJSON";
react = "push";
};
jq_filter = {
jqFilter = {
format = "string";
react = "push";
};
@ -20,6 +20,13 @@
react = "push";
};
};
cache-command = "deno cache --reload main.ts";
build = {
hashFiles = [ ./deno.json ./deno.lock ];
cacheCommand = "deno cache --frozen main.ts";
knownHashes = {
"sha1-gSeoE0sSj+dFQ7SUoyaQV0X/KJE=" =
"sha256-0ZfdWVfShbhgAoSse9vEpFPRh5XTTVjgxGMmezwon9I=";
};
};
}

View file

@ -1,15 +1,26 @@
{
"version": "4",
"version": "5",
"specifiers": {
"npm:@types/node@*": "22.13.4",
"npm:hjson@^3.2.2": "3.2.2",
"npm:jq-web@~0.6.2": "0.6.2"
},
"npm": {
"@types/node@22.13.4": {
"integrity": "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==",
"dependencies": [
"undici-types"
]
},
"hjson@3.2.2": {
"integrity": "sha512-MkUeB0cTIlppeSsndgESkfFD21T2nXPRaBStLtf3cAYA2bVEFdXlodZB0TukwZiobPD1Ksax5DK4RTZeaXCI3Q=="
"integrity": "sha512-MkUeB0cTIlppeSsndgESkfFD21T2nXPRaBStLtf3cAYA2bVEFdXlodZB0TukwZiobPD1Ksax5DK4RTZeaXCI3Q==",
"bin": true
},
"jq-web@0.6.2": {
"integrity": "sha512-+7XvjBYwTx4vP5PYkf6Q6orubO/v+UgMU6By1GritrmShr9QpT3UKa4ANzXWQfhdqtBnQYXsm7ZNbdIHT6tYpQ=="
},
"undici-types@6.20.0": {
"integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
}
}
}

View file

@ -1,3 +1,32 @@
{
cache-command = "deno cache -I --reload main.ts";
name = "uses-hjq";
description = "A test scroll that mimicks hjq's behavior";
inputs = {
stdin = {
format = "HJSON";
react = "push";
};
jqFilter = {
format = "string";
react = "push";
};
};
outputs = {
stdout = {
format = "HJSON";
react = "push";
};
};
build = {
hashFiles = [ ./deno.json ./deno.lock ];
cacheCommand = "deno cache --frozen main.ts";
knownHashes = {
"sha1-uO43Rt1F6+Ud1wk2p9LQhfP180M=" =
"sha256-x/Fvn/l3J7C0D7AftlbRk7iuc6o9qPakdnHb72TSxec=";
} ;
};
}