284 lines
7.7 KiB
Text
Executable file
284 lines
7.7 KiB
Text
Executable file
#!/usr/bin/env nu
|
|
|
|
const HEADER = "
|
|
----- MEAT ----------------------------------------
|
|
"
|
|
|
|
const FOOTER = "
|
|
---------------------------------------------------
|
|
"
|
|
|
|
const HELP_TEXT = "
|
|
YUM - CONSUME DELICIOUS MEATS
|
|
COOK - ONLY PREPARE MEATS
|
|
POKE - TASTE SUSPICIOUS MEATS
|
|
GUT - CLEAN MEAT STORES
|
|
FRESH - HUNT FRESH MEATS
|
|
LOOK - LOOK FOR FRESHER MEATS
|
|
HUNT - HUNT FOR MEATS IN NIXPKGS
|
|
RITUAL - PERFORM RITUAL THEN CONSUME
|
|
TRADE - SEND MEATS FAR AWAY
|
|
..-A - ..ALL MEATS"
|
|
|
|
def meat-print [text: string] {
|
|
print $"\n \t($text)\n"
|
|
}
|
|
|
|
def with-frame [body: closure] {
|
|
print -n $HEADER
|
|
do $body
|
|
print -n $FOOTER
|
|
}
|
|
|
|
def hn []: nothing -> string {
|
|
^hostname | str trim
|
|
}
|
|
|
|
def system-attr []: nothing -> string {
|
|
$"nixosConfigurations.(hn).config.system.build.toplevel"
|
|
}
|
|
|
|
def nix-conf-attr []: nothing -> string {
|
|
$"nixosConfigurations.(hn).config.environment.etc.\"nix/nix.conf\""
|
|
}
|
|
|
|
def nix-build-nom [out: string, build_args: list<string>] {
|
|
if ($env.MONITOR? | is-empty) {
|
|
^nix-build --out-link $out ...$build_args
|
|
} else {
|
|
^nix-build --log-format internal-json --out-link $out ...$build_args out+err>| ^$env.MONITOR --json
|
|
}
|
|
# Piping to MONITOR masks nix-build's exit code, so detect failure by the
|
|
# absence of the out-link.
|
|
if not ($out | path exists) {
|
|
error make { msg: "nix-build produced no output" }
|
|
}
|
|
}
|
|
|
|
def differ-step [build: string] {
|
|
if ($env.DIFFER? | is-empty) {
|
|
meat-print " (no DIFFER set; skipping diff)"
|
|
} else {
|
|
^$env.DIFFER /nix/var/nix/profiles/system $build
|
|
}
|
|
}
|
|
|
|
def activate [build_path: string] {
|
|
^sudo $nu.current-exe -c $"nix-env --set -p /nix/var/nix/profiles/system ($build_path); ($build_path)/bin/switch-to-configuration switch"
|
|
}
|
|
|
|
def do-build [extras: list<string> = []] {
|
|
let tmpdir = ^mktemp -d -t "meat-build.XXXXXX" | str trim
|
|
let build = $"($tmpdir)/build"
|
|
warm-pins
|
|
let start = date now
|
|
let drv = ^nix-instantiate $"($env.MEATS)/entry.nix" -A (system-attr) ...$extras | lines | last | str trim
|
|
meat-print $"MASTICATION TAKING ((date now) - $start)"
|
|
nix-build-nom $build [$drv]
|
|
differ-step $build
|
|
activate $build
|
|
try { rm $build }
|
|
}
|
|
|
|
def cmd-help [] {
|
|
print -n $"($HEADER)($HELP_TEXT)($FOOTER)\n"
|
|
}
|
|
|
|
def cmd-yum [...args: string] {
|
|
with-frame {
|
|
meat-print "CONSUMING DELICIOUS MEATS.."
|
|
try { do-build $args } catch { print "FAILED TO CONSUME MEATS." }
|
|
}
|
|
}
|
|
|
|
def cmd-cook [...args: string] {
|
|
with-frame {
|
|
meat-print "PREPARING DELICIOUS MEATS.."
|
|
warm-pins
|
|
try { ^nix-build --no-out-link $"($env.MEATS)/entry.nix" -A (system-attr) ...$args }
|
|
}
|
|
}
|
|
|
|
def cmd-poke [...args: string] {
|
|
with-frame {
|
|
meat-print "PREPARING SUSPICIOUS MEATS.."
|
|
warm-pins
|
|
try { ^nix-build --no-out-link --show-trace $"($env.MEATS)/entry.nix" -A (system-attr) ...$args }
|
|
}
|
|
}
|
|
|
|
def cmd-gut [...args: string] {
|
|
with-frame {
|
|
meat-print "CLEANING MEAT STORES.."
|
|
try { ^nh clean all ...$args }
|
|
}
|
|
}
|
|
|
|
def cmd-trade [] {
|
|
with-frame {
|
|
meat-print "TRADING FOREIGN MEATS.."
|
|
meat-print "tbd"
|
|
}
|
|
}
|
|
|
|
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 { {} }
|
|
}
|
|
|
|
# Fetch one locked input into the store, mirroring the tack resolver's
|
|
# `builtins.fetchTree lock.<name>`. Returns the name on failure, else null.
|
|
def warm-pin [name: string, node: record] {
|
|
let tmp = ^mktemp -t "meat-pin.XXXXXX.json" | str trim
|
|
$node | to json | save -f $tmp
|
|
let expr = $"\(builtins.fetchTree \(builtins.fromJSON \(builtins.readFile \"($tmp)\"\)\)\).outPath"
|
|
let r = ^nix eval --impure --raw --expr $expr | complete
|
|
try { rm $tmp }
|
|
if $r.exit_code != 0 { $name } else { null }
|
|
}
|
|
|
|
# Pre-fetch every locked input in parallel so the serial fetchTree calls
|
|
# during evaluation become cache hits. Warming is idempotent and non-fatal:
|
|
# anything that fails here is simply re-fetched by the build itself.
|
|
def warm-pins [] {
|
|
let lock = load-lock
|
|
let names = $lock | columns
|
|
if ($names | is-empty) { return }
|
|
meat-print "GATHERING MEATS.."
|
|
let failed = $names | par-each { |name| warm-pin $name ($lock | get $name) } | compact
|
|
for name in $failed {
|
|
meat-print $" COULDN'T GATHER ($name | str upcase) \(BUILD WILL RETRY\)"
|
|
}
|
|
}
|
|
|
|
def cmd-fresh [...names: string] {
|
|
with-frame {
|
|
meat-print "HUNTING FRESH MEATS.."
|
|
do { cd $env.MEATS; ^$env.TACK update ...$names }
|
|
}
|
|
}
|
|
|
|
def cmd-look [...names: string] {
|
|
with-frame {
|
|
meat-print "LOOK FOR NEW MEATS.."
|
|
do { cd $env.MEATS; ^$env.TACK look ...$names }
|
|
}
|
|
}
|
|
|
|
def truncate-desc [s: string, n: int]: nothing -> string {
|
|
if (($s | str length) > $n) {
|
|
($s | str substring 0..$n) + ".."
|
|
} else {
|
|
$s
|
|
}
|
|
}
|
|
|
|
def cmd-hunt [...query: string] {
|
|
with-frame {
|
|
if ($query | is-empty) {
|
|
meat-print "WHAT MEAT YOU SEEK?"
|
|
return
|
|
}
|
|
let q = $query | str join " "
|
|
meat-print $"HUNTING FOR ($q | str upcase).."
|
|
let body = {
|
|
from: 0,
|
|
size: 20,
|
|
sort: [{ _score: "desc", package_attr_name: "desc", package_pversion: "desc" }],
|
|
collapse: { field: "package_attr_name" },
|
|
query: {
|
|
bool: {
|
|
must: [
|
|
{ term: { type: "package" } },
|
|
{ multi_match: {
|
|
type: "cross_fields",
|
|
query: $q,
|
|
fields: ["package_attr_name^9", "package_pname^6", "package_description^1.3", "package_longDescription^1"]
|
|
} }
|
|
]
|
|
}
|
|
}
|
|
}
|
|
try {
|
|
let resp = (
|
|
http post
|
|
--user "aWVSALXpZv"
|
|
--password "X8gPHnzL52wFEekuxsfQ9cSh"
|
|
--content-type "application/json"
|
|
"https://nixos-search-7-1733963800.us-east-1.bonsaisearch.net/nixos-*-unstable-*/_search"
|
|
$body
|
|
)
|
|
let hits = $resp.hits?.hits? | default []
|
|
if ($hits | is-empty) {
|
|
meat-print "NO MEATS FOUND!"
|
|
} else {
|
|
for hit in $hits {
|
|
let src = $hit._source
|
|
let name = $src.package_attr_name? | default "?"
|
|
let ver = $src.package_pversion? | default ""
|
|
let desc = $src.package_description? | default ""
|
|
let ver_str = if ($ver | is-empty) { "" } else { $" \(($ver)\)" }
|
|
print $" \tnixpkgs#($name)($ver_str)"
|
|
if not ($desc | is-empty) {
|
|
print $" \t (truncate-desc $desc 60)"
|
|
}
|
|
}
|
|
}
|
|
} catch { |e|
|
|
meat-print $"HUNT FAILED: ($e.msg)"
|
|
}
|
|
}
|
|
}
|
|
|
|
def cmd-ritual [] {
|
|
with-frame {
|
|
meat-print "PREPARING RITUAL GROUND.."
|
|
let tmpdir = ^mktemp -d -t "meat-chew.XXXXXX" | str trim
|
|
let meats = $env.MEATS
|
|
let nix_conf = $"($tmpdir)/nix.conf"
|
|
let build = $"($tmpdir)/build"
|
|
try {
|
|
warm-pins
|
|
nix-build-nom $nix_conf [$"($meats)/entry.nix" "-A" (nix-conf-attr)]
|
|
meat-print "CONSUMING MEATS.."
|
|
with-env { NIX_USER_CONF_FILES: $nix_conf } {
|
|
nix-build-nom $build [$"($meats)/entry.nix" "-A" (system-attr)]
|
|
}
|
|
^$env.DIFFER /nix/var/nix/profiles/system $build
|
|
activate $build
|
|
try { rm $nix_conf }
|
|
try { rm $build }
|
|
} catch {
|
|
print "FAILED TO CONSUME MEATS."
|
|
}
|
|
}
|
|
}
|
|
|
|
def cmd-shelter [new_closure: string] {
|
|
activate $new_closure
|
|
}
|
|
|
|
def main [...args: string] {
|
|
if ($env.MEATS? | is-empty) {
|
|
meat-print "NO PATH TO RUNESTONE FOUND!"
|
|
cmd-help
|
|
return
|
|
}
|
|
let sub = $args | get 0? | default "" | str downcase
|
|
let rest = $args | skip 1
|
|
match $sub {
|
|
"yum" => { cmd-yum ...$rest }
|
|
"cook" => { cmd-cook ...$rest }
|
|
"poke" => { cmd-poke ...$rest }
|
|
"gut" => { cmd-gut ...$rest }
|
|
"trade" => { cmd-trade }
|
|
"look" => { cmd-look ...$rest }
|
|
"fresh" => { cmd-fresh ...$rest }
|
|
"hunt" => { cmd-hunt ...$rest }
|
|
"ritual" => { cmd-ritual }
|
|
"shelter" => { cmd-shelter $rest }
|
|
_ => { cmd-help }
|
|
}
|
|
}
|