From 9b2604da818c23e56efc271bbed07aa06fff0d86 Mon Sep 17 00:00:00 2001 From: atagen Date: Fri, 29 May 2026 00:25:36 +1000 Subject: [PATCH] delegate pin management to tack --- .tack/default.nix | 302 +++++++++++++++++++++++++++++++++++++++++++ .tack/pins.lock.json | 32 +++++ .tack/pins.toml | 41 ++++++ flake.lock | 105 +-------------- flake.nix | 21 +-- meat.nu | 167 +----------------------- nix/default.nix | 4 +- nix/module.nix | 4 + 8 files changed, 402 insertions(+), 274 deletions(-) create mode 100644 .tack/default.nix create mode 100644 .tack/pins.lock.json create mode 100644 .tack/pins.toml mode change 100644 => 100755 meat.nu diff --git a/.tack/default.nix b/.tack/default.nix new file mode 100644 index 0000000..d8e6485 --- /dev/null +++ b/.tack/default.nix @@ -0,0 +1,302 @@ +# SPDX-License-Identifier: EUPL-1.2 +# tack-managed resolver. delete this line to take ownership; tack will leave it alone afterwards. + +let + inherit (builtins) + attrNames + attrValues + concatMap + elemAt + filter + foldl' + fromJSON + head + intersectAttrs + isList + isString + listToAttrs + mapAttrs + match + pathExists + readFile + substring + tail + trace + ; + + call = + { + overrides ? { }, + }: + let + pins = fromTOML (readFile ./pins.toml); + lock = fromJSON (readFile ./pins.lock.json); + all_follow_raw = pins.all_follow or { }; + + # flatten `target = [aliases]` rows alongside `alias = "target"` rows + all_follow = foldl' ( + acc: key: + let + val = all_follow_raw.${key}; + in + if isList val then + acc + // { + ${key} = key; + } + // listToAttrs ( + map (a: { + name = a; + value = key; + }) val + ) + else if isString val then + acc // { ${key} = val; } + else + acc + ) { } (attrNames all_follow_raw); + + # a path node's stored path is absolute, or relative to this resolver dir + fetchPin = + name: + let + node = lock.${name}; + in + if (node.type or "") == "path" && substring 0 1 node.path != "/" then + fetchTree (node // { path = ./. + ("/" + node.path); }) + else + fetchTree node; + + fetchFixed = + name: entry: + let + raw = derivation { + inherit name; + inherit (entry) url; + builder = "builtin:fetchurl"; + system = "builtin"; + outputHash = entry.sha256; + outputHashAlgo = "sha256"; + outputHashMode = "flat"; + }; + unpacked = derivation { + inherit name; + builder = "builtin:unpack-channel"; + system = "builtin"; + src = raw; + channelName = name; + }; + in + if (entry.unpack or "file") == "tarball" then unpacked.outPath + "/" + name else raw.outPath; + + resolveSpec = upLock: spec: if isList spec then walkPath upLock upLock.root spec else spec; + + walkPath = + upLock: nodeName: path: + if path == [ ] then + nodeName + else + walkPath upLock (resolveSpec upLock upLock.nodes.${nodeName}.inputs.${head path}) (tail path); + + followsFor = + pin: + let + rules = removeAttrs all_follow (pin.exclude_follow or [ ]); + in + { + level = (pin.follows or { }) // rules; + deep = rules; + }; + + resolveFollows = mapAttrs ( + _: target: self.${target} or (throw "tack: follows target '${target}' is not a pin") + ); + + # follows key is `flake:name`, `tack:name`, or bare `name` + # project onto one side, rekeyed to bare names + followsForSide = + side: follows: + listToAttrs ( + concatMap ( + key: + let + m = match "(flake|tack):(.*)" key; + in + if m == null then + [ + { + name = key; + value = follows.${key}; + } + ] + else if head m == side then + [ + { + name = elemAt m 1; + value = follows.${key}; + } + ] + else + [ ] + ) (attrNames follows) + ); + + mkCallerInputs = + upLock: nodeName: rawInputs: levelFollows: deepFollows: + let + resolved = resolveFollows levelFollows; + in + mapAttrs ( + n: _decl: + resolved.${n} or ( + if upLock != null then + let + ref = + (upLock.nodes.${nodeName}.inputs or { }).${n} + or (throw "tack: input '${n}' declared but not in flake.lock node '${nodeName}'"); + childName = resolveSpec upLock ref; + childNode = upLock.nodes.${childName}; + childSrc = fetchTree childNode.locked; + in + if childNode.flake or true then evalTransitive upLock childName childSrc deepFollows else childSrc + else + throw "tack: no flake.lock; cannot resolve input '${n}'" + ) + ) rawInputs; + + mkFlakeResult = + sourceInfo: flakeDir: callerInputs: outputs: + outputs + // sourceInfo + // { + outPath = flakeDir; + inputs = callerInputs; + inherit outputs sourceInfo; + _type = "flake"; + }; + + evalFlake = + sourceInfo: flakeDir: upLock: nodeName: levelFollows: deepFollows: + let + raw = import (flakeDir + "/flake.nix"); + + tackPinsPath = flakeDir + "/.tack/pins.toml"; + hasTack = pathExists tackPinsPath; + upPins = if hasTack then fromTOML (readFile tackPinsPath) else { }; + + # project follows onto each side, keep only names that side has + # bare follow reaches both; `flake:`/`tack:` reaches just one + tackOverrides = resolveFollows ( + intersectAttrs (upPins.inputs or { }) (followsForSide "tack" levelFollows) + ); + flakeLevel = intersectAttrs (raw.inputs or { }) (followsForSide "flake" levelFollows); + + # deep follows pass down raw, so each descendant re-projects per side + callerInputs = mkCallerInputs upLock nodeName (raw.inputs or { }) flakeLevel deepFollows; + + # upstream declares its outputs forward tackOverrides; a closed `{ self }:` + # would throw on the extra kwarg, so forward only when declared + supportsOverrides = (upPins.tack or { }).recomposable or false; + + extraArgs = if supportsOverrides && tackOverrides != { } then { inherit tackOverrides; } else { }; + + outputs = raw.outputs (callerInputs // extraArgs // { self = result; }); + + result = + let + base = mkFlakeResult sourceInfo flakeDir callerInputs outputs; + in + if hasTack && tackOverrides != { } && !supportsOverrides then + trace "tack: ${flakeDir}: not marked recomposable (set [tack] recomposable = true); overrides will not reach upstream" base + else + base; + in + result; + + evalTransitive = + upLock: nodeName: sourceInfo: follows: + evalFlake sourceInfo sourceInfo.outPath upLock nodeName follows follows; + + evalTopFlake = + sourceInfo: pin: + let + flakeDir = sourceInfo.outPath + (if pin ? dir then "/" + pin.dir else ""); + upLockPath = flakeDir + "/flake.lock"; + upLock = if pathExists upLockPath then fromJSON (readFile upLockPath) else null; + rootNode = if upLock != null then upLock.root else null; + f = followsFor pin; + in + evalFlake sourceInfo flakeDir upLock rootNode f.level f.deep; + + evalFetch = + sourceInfo: pin: subdir: + let + path = sourceInfo.outPath + subdir; + tackPinsPath = path + "/.tack/pins.toml"; + hasTack = pathExists tackPinsPath; + upPins = if hasTack then fromTOML (readFile tackPinsPath) else { }; + f = followsFor pin; + # a fetch drill-in is tack-only + tackOverrides = resolveFollows ( + intersectAttrs (upPins.inputs or { }) (followsForSide "tack" f.level) + ); + in + # a fetch pin is a source tree (path); hand back resolved inputs only when + # there are overrides to push into the upstream's .tack + if hasTack && tackOverrides != { } then + let + upstream = import (path + "/.tack"); + in + # old resolvers return a plain attrset, not a callable functor + if upstream ? __functor then + (upstream { overrides = tackOverrides; }) // { outPath = path; } + else + trace "tack: ${path}: upstream .tack predates override support; overrides will not reach it" path + else + path; + + loadPin = + name: pin: + let + pinType = pin.type or (if pin.flake or true then "flake" else "fetch"); + subdir = if pin ? dir then "/" + pin.dir else ""; + in + if pinType == "fixed" then + fetchFixed name lock.${name} + else + let + sourceInfo = fetchPin name; + in + if pinType == "flake" then evalTopFlake sourceInfo pin else evalFetch sourceInfo pin subdir; + + declared = pins.inputs or { }; + + # undeclared lock entries are auto-dedup synthetics only when referenced as + # [all_follow] targets; stale locks from hand-edits are ignored (tack rm to clean) + autoTargets = listToAttrs ( + map (target: { + name = target; + value = true; + }) (attrValues all_follow) + ); + autoNames = filter (n: !(declared ? ${n}) && autoTargets ? ${n}) (attrNames lock); + autoPin = + name: + let + sourceInfo = fetchPin name; + in + if pathExists (sourceInfo.outPath + "/flake.nix") then evalTopFlake sourceInfo { } else sourceInfo; + + self = + (mapAttrs loadPin declared) + // listToAttrs ( + map (name: { + inherit name; + value = autoPin name; + }) autoNames + ) + // overrides; + in + self // { __functor = _: call; }; +in +call { } diff --git a/.tack/pins.lock.json b/.tack/pins.lock.json new file mode 100644 index 0000000..ad54866 --- /dev/null +++ b/.tack/pins.lock.json @@ -0,0 +1,32 @@ +{ + "nix-systems": { + "type": "github", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "lastModified": 1689347949 + }, + "nixpkgs": { + "type": "tarball", + "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1011620.cbb5cf358f50/nixexprs.tar.xz", + "narHash": "sha256-d86UGSjwACWRttincQzeiAEZYVPtP3kODhr9hYZD4e8=", + "lastModified": 1780787167 + }, + "tack": { + "type": "github", + "owner": "manic-systems", + "repo": "tack", + "rev": "0bc8dcb07dbd85d5d8d889c89accc9b228a6e4cc", + "narHash": "sha256-/GrnjZK71UdLFtugaXkShE8dWpvGxJyOHpj073v+pXU=", + "lastModified": 1780970897 + }, + "unf": { + "type": "git", + "url": "https://git.atagen.co/atagen/unf", + "ref": "HEAD", + "rev": "4f5ab30ee524f09126b09f42f249c0aba756459d", + "narHash": "sha256-ztzeJVOQDhQtE0z9DwtSWL+OyoWKZrAD4gzRRvUP9ug=", + "lastModified": 1779596435 + } +} diff --git a/.tack/pins.toml b/.tack/pins.toml new file mode 100644 index 0000000..b73f2ba --- /dev/null +++ b/.tack/pins.toml @@ -0,0 +1,41 @@ +# tack pins +# edit by hand or with tack add / rm / alias +# nix reads pins.lock.json +# this file drives tack update + +# shorturl schemes +# scheme rest expands rest into {path} +[shorturls] +# gh = "github:{path}" + +# all_follow maps input names to the top-level pin they follow +# opt out per-input with exclude_follow +[all_follow] +# nixpkgs = "nixpkgs" +# nixpkgs = ["nixpkgs-stable", "nixpkgs-unstable"] + +[tack] +recomposable = true + +# inputs. fields +# url required, shorturl ok, ?rev= pins an exact commit +# type flake (default), fetch, or fixed +# flake legacy false means type = "fetch" +# follows { child = "pin" } override map +# exclude_follow all_follow names to skip +# dir subdir holding flake.nix +# submodules fetch git submodules +# unpack fixed-only tarball or file +[inputs] + +[inputs.nixpkgs] +url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz" + +[inputs.nix-systems] +url = "github:nix-systems/default-linux" + +[inputs.unf] +url = "git+https://git.atagen.co/atagen/unf" + +[inputs.tack] +url = "github:manic-systems/tack/next" diff --git a/flake.lock b/flake.lock index 863dc62..5999137 100644 --- a/flake.lock +++ b/flake.lock @@ -1,109 +1,6 @@ { "nodes": { - "ndg": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1779030999, - "narHash": "sha256-PLR0pNxIN3JPs/rSVnXTIPXzkPLaGAdt/wjPq7+k1PE=", - "owner": "feel-co", - "repo": "ndg", - "rev": "b363612b524436520c85100192ec2bdab9a675c0", - "type": "github" - }, - "original": { - "owner": "feel-co", - "repo": "ndg", - "type": "github" - } - }, - "nix-systems": { - "locked": { - "lastModified": 1689347949, - "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", - "owner": "nix-systems", - "repo": "default-linux", - "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default-linux", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1778869304, - "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1775036866, - "narHash": "sha256-ByAX1LkhCwZ94+KnFAmnJSMAvui7kgCxjHgUHsWAbfI=", - "rev": "6201e203d09599479a3b3450ed24fa81537ebc4e", - "type": "tarball", - "url": "https://releases.nixos.org/nixos/unstable/nixos-26.05pre972949.6201e203d095/nixexprs.tar.xz?lastModified=1775036866&rev=6201e203d09599479a3b3450ed24fa81537ebc4e" - }, - "original": { - "type": "tarball", - "url": "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1778869304, - "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nix-systems": "nix-systems", - "nixpkgs": "nixpkgs", - "unf": "unf" - } - }, - "unf": { - "inputs": { - "ndg": "ndg", - "nixpkgs": "nixpkgs_3" - }, - "locked": { - "lastModified": 1760178630, - "narHash": "sha256-oxRMTQtzIO1yFRhY++Ss8+ea1cTH40bD/+FAE+m5NFk=", - "ref": "refs/heads/main", - "rev": "8a6aa536039f1b207888b1369c5cabf0b131e07b", - "revCount": 5, - "type": "git", - "url": "https://git.atagen.co/atagen/unf" - }, - "original": { - "type": "git", - "url": "https://git.atagen.co/atagen/unf" - } - } + "root": {} }, "root": "root", "version": 7 diff --git a/flake.nix b/flake.nix index a3cb7c8..10fd057 100644 --- a/flake.nix +++ b/flake.nix @@ -1,20 +1,22 @@ { - inputs = { - nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; - nix-systems.url = "github:nix-systems/default-linux"; - unf.url = "git+https://git.atagen.co/atagen/unf"; - }; outputs = - inputs: - with inputs; + { self, ... }@args: let + inputs = import ./.tack { overrides = args.tackOverrides or { }; }; + inherit (inputs) + nixpkgs + nix-systems + tack + unf + ; version = builtins.toString self.lastModified; forEachSystem = function: nixpkgs.lib.genAttrs (import nix-systems) ( system: function nixpkgs.legacyPackages.${system} system ); + tackFor = system: tack.packages.${system}.default; in { devShells = forEachSystem ( @@ -28,9 +30,10 @@ ); packages = forEachSystem ( - pkgs: _: { + pkgs: system: { default = pkgs.callPackage ./nix/default.nix { inherit version; + tack = tackFor system; }; docs = pkgs.callPackage unf.lib.pak-chooie { inherit self; @@ -55,9 +58,11 @@ in { imports = [ ./nix/module.nix ]; + programs.meat.tack = lib.mkDefault (tackFor pkgs.stdenv.hostPlatform.system); programs.meat.package = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override { differ = cfg.differ; monitor = cfg.monitor; + tack = cfg.tack; }; }; diff --git a/meat.nu b/meat.nu old mode 100644 new mode 100755 index a03a4bc..cacf97a --- a/meat.nu +++ b/meat.nu @@ -121,86 +121,14 @@ def cmd-trade [] { } } -def pins-path [] { $"($env.MEATS)/pins/pins.toml" } -def lock-path [] { $"($env.MEATS)/pins/pins.lock.json" } - -def load-pins [] { - let p = pins-path - if not ($p | path exists) { error make { msg: $"no pins file at ($p)" } } - open --raw $p | from toml -} +def lock-path [] { $"($env.MEATS)/.tack/pins.lock.json" } def load-lock [] { let p = lock-path if ($p | path exists) { open --raw $p | from json } else { {} } } -# Sort keys alphabetically and write atomically. -def write-lock [lock: record] { - let p = lock-path - let sorted = $lock | columns | sort | reduce -f {} { |k, acc| $acc | insert $k ($lock | get $k) } - let tmp = $"($p).tmp" - $sorted | to json --indent 2 | save -f $tmp - ^mv $tmp $p -} - -# scheme:rest → expansion via {path} template, or pass-through. -def expand-shorturl [url: string, shorturls: record] { - let parts = $url | split row ":" -n 2 - if (($parts | length) < 2) { return $url } - let scheme = $parts | get 0 - if not ($scheme in ($shorturls | columns)) { return $url } - ($shorturls | get $scheme) | str replace --regex '\{path\}' ($parts | get 1) -} - -# Decompose to {git_url, ref?} for cheap ls-remote queries (used by `look`). -def parse-git-target [url: string] { - if ($url | str starts-with "github:") { - let body = $url | str substring 7.. - let path_query = $body | split row "?" -n 2 - let segs = ($path_query | get 0) | split row "/" - let owner = $segs | get 0 - let repo = $segs | get 1 - let ref = if (($segs | length) > 2) { $segs | skip 2 | str join "/" } else { null } - return { git_url: $"https://github.com/($owner)/($repo).git", ref: $ref } - } - if ($url | str starts-with "git+") { - let stripped = $url | str substring 4.. - let parts = $stripped | split row "?" -n 2 - let base = $parts | get 0 - let ref = if (($parts | length) > 1) { - ($parts | get 1) | split row "&" | each { |kv| - let kvp = $kv | split row "=" -n 2 - { k: ($kvp | get 0), v: ($kvp | get 1?) } - } | where k == "ref" | get -o 0 | get -o v - } else { null } - return { git_url: $base, ref: $ref } - } - error make { msg: $"unsupported url scheme for ls-remote: ($url)" } -} - -# Cheap "is upstream ahead?" check via git ls-remote. Returns the rev string. -def ls-remote-head [url: string] { - let tgt = parse-git-target $url - let target_ref = if ($tgt.ref? | is-not-empty) { $"refs/heads/($tgt.ref)" } else { "HEAD" } - let r = ^git ls-remote $tgt.git_url $target_ref | complete - if $r.exit_code != 0 { error make { msg: $"ls-remote failed: ($r.stderr)" } } - let first = $r.stdout | str trim | lines | get -o 0 - if ($first | is-empty) { error make { msg: "no refs returned" } } - $first | split row "\t" | get 0 -} - -# Real prefetch — caches in /nix/store and returns the full locked attrset. -# Output JSON: { hash: SRI, locked: {...}, original: {...}, storePath: PATH } -# --refresh bypasses the ref→rev cache (otherwise stale within tarball-ttl). -def prefetch-pin [url: string] { - let r = ^nix flake prefetch --refresh --json $url | complete - if $r.exit_code != 0 { error make { msg: $"prefetch failed for ($url): ($r.stderr)" } } - let j = $r.stdout | from json - $j.locked | insert narHash $j.hash -} - -# Fetch one locked input into the store, mirroring lib/inputs.nix's +# Fetch one locked input into the store, mirroring the tack resolver's # `builtins.fetchTree lock.`. Returns the name on failure, else null. def warm-pin [name: string, node: record] { let tmp = ^mktemp -t "meat-pin.XXXXXX.json" | str trim @@ -228,97 +156,14 @@ def warm-pins [] { def cmd-fresh [...names: string] { with-frame { meat-print "HUNTING FRESH MEATS.." - let pins = load-pins - let shorturls = $pins.shorturls? | default {} - let inputs = $pins.inputs - let lock = load-lock - - let requested = if ($names | is-empty) { $inputs | columns } else { $names } - - # Report unknown names up front and keep only real targets. - let targets = $requested | each { |name| - if not ($name in ($inputs | columns)) { - meat-print $"NO MEAT CALLED ($name | str upcase).." - null - } else { $name } - } | compact - - # Prefetch every target in parallel — this is the network-bound work. - # No lock writes happen here; results are collected and applied below. - let results = $targets | par-each { |name| - let old_rev = ($lock | get -o $name) | default {} | get -o rev - try { - let pin = $inputs | get $name - let expanded = expand-shorturl $pin.url $shorturls - let entry = prefetch-pin $expanded - { name: $name, ok: true, entry: $entry, old_rev: $old_rev, new_rev: $entry.rev } - } catch { |e| - { name: $name, ok: false, err: $e.msg } - } - } - - # Apply results sequentially in target order so the lock file is never - # written concurrently and reporting stays deterministic. - mut lock = $lock - for name in $targets { - let r = $results | where name == $name | first - meat-print $"PROCESSING ($name | str upcase).." - if not $r.ok { - meat-print $" NO FIND ($name | str upcase): ($r.err)" - continue - } - if $r.old_rev == $r.new_rev { - meat-print $" ($name | str upcase) STILL FRESH" - continue - } - $lock = $lock | upsert $name $r.entry - write-lock $lock - let from = if ($r.old_rev | is-empty) { "NEW" } else { $r.old_rev | str substring 0..8 } - meat-print $" ($name | str upcase): ($from) -> ($r.new_rev | str substring 0..8)" - } + do { cd $env.MEATS; ^$env.TACK update ...$names } } - print "" } -def cmd-look [] { +def cmd-look [...names: string] { with-frame { meat-print "LOOK FOR NEW MEATS.." - let pins = load-pins - let shorturls = $pins.shorturls? | default {} - let inputs = $pins.inputs - let lock = load-lock - - let rows = $inputs | transpose name pin - - # Query every upstream head in parallel; no printing happens here. - let results = $rows | par-each { |row| - let old_rev = ($lock | get -o $row.name) | default {} | get -o rev - try { - let expanded = expand-shorturl $row.pin.url $shorturls - let new_rev = ls-remote-head $expanded - { name: $row.name, ok: true, stale: ($old_rev != $new_rev), old_rev: $old_rev, new_rev: $new_rev } - } catch { - { name: $row.name, ok: false } - } - } - - # Report in input order so output is deterministic and never races. - mut stale = [] - for row in $rows { - let r = $results | where name == $row.name | first - if not $r.ok { - meat-print $" NO FIND ($row.name | str upcase).." - continue - } - if $r.stale { - let from = if ($r.old_rev | is-empty) { "NEW" } else { $r.old_rev | str substring 0..8 } - meat-print $" ($row.name | str upcase): ($from) -> ($r.new_rev | str substring 0..8)" - $stale = ($stale | append $row.name) - } - } - if ($stale | is-empty) { - meat-print "NO MEAT FRESHER" - } + do { cd $env.MEATS; ^$env.TACK look ...$names } } } @@ -429,7 +274,7 @@ def main [...args: string] { "poke" => { cmd-poke ...$rest } "gut" => { cmd-gut ...$rest } "trade" => { cmd-trade } - "look" => { cmd-look } + "look" => { cmd-look ...$rest } "fresh" => { cmd-fresh ...$rest } "hunt" => { cmd-hunt ...$rest } "ritual" => { cmd-ritual } diff --git a/nix/default.nix b/nix/default.nix index 4b5d5ff..fc7a3ae 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -5,6 +5,7 @@ nushell, makeBinaryWrapper, version, + tack, differ ? pkgs.dix, monitor ? pkgs.nix-output-monitor, ... @@ -26,7 +27,8 @@ stdenvNoCC.mkDerivation { makeBinaryWrapper ${nushell}/bin/nu $out/bin/meat \ --add-flags "$out/share/meat/meat.nu" \ --set DIFFER ${lib.getExe differ} \ - --set MONITOR ${lib.getExe monitor} + --set MONITOR ${lib.getExe monitor} \ + --set TACK ${lib.getExe tack} runHook postInstall ''; } diff --git a/nix/module.nix b/nix/module.nix index b2d6079..68be629 100644 --- a/nix/module.nix +++ b/nix/module.nix @@ -29,6 +29,10 @@ in description = "nix monitoring tool to use"; default = pkgs.nix-output-monitor; }; + tack = mkOption { + type = types.package; + description = "tack pin manager"; + }; }; config = lib.mkIf cfg.enable { environment.sessionVariables.MEATS = cfg.flake;