mirror of
https://github.com/daylinmorgan/oizys.git
synced 2025-02-02 11:04:17 -06:00
add utils subcmds
This commit is contained in:
parent
a0ac1b4520
commit
133ddc761f
5 changed files with 160 additions and 25 deletions
|
@ -1,7 +1,7 @@
|
|||
## nix begat oizys
|
||||
import std/[os, osproc, sequtils, strformat, strutils, tables]
|
||||
import hwylterm, hwylterm/[hwylcli]
|
||||
import oizys/[context, github, nix, logging]
|
||||
import oizys/[context, github, nix, logging, utils]
|
||||
|
||||
proc checkExes() =
|
||||
if findExe("nix") == "":
|
||||
|
@ -37,6 +37,7 @@ hwylCli:
|
|||
- m
|
||||
preSub:
|
||||
setupLoggers()
|
||||
echo "ORIGINAL UPDATE CONTEXT"
|
||||
updateContext(host, flake, verbose, resetCache)
|
||||
|
||||
subcommands:
|
||||
|
@ -74,11 +75,6 @@ hwylCli:
|
|||
|
||||
[ci]
|
||||
... "builtin ci"
|
||||
# BUG: current behavior adds this block twice...
|
||||
# when really I want it to only happen in the lowest "subcommand"
|
||||
# needs to be fixed in hwylterm
|
||||
preSub:
|
||||
updateContext(host, flake, verbose, resetCache)
|
||||
subcommands:
|
||||
[update]
|
||||
... "build current and updated hosts"
|
||||
|
@ -162,3 +158,32 @@ hwylCli:
|
|||
updateRepo()
|
||||
nixosRebuild(NixosRebuildSubcmd.switch)
|
||||
|
||||
[utils]
|
||||
... """
|
||||
less common utils operations
|
||||
|
||||
some snippets I've reimplemented in nim so that nix isn't as annoying
|
||||
"""
|
||||
subcommands:
|
||||
[hash]
|
||||
... "collect build hash from failure"
|
||||
positionals:
|
||||
installable string
|
||||
run:
|
||||
stdout.write getBuildHash(installable)
|
||||
|
||||
[narinfo]
|
||||
... """
|
||||
check active caches for nix derivation
|
||||
|
||||
by default will use [yellow]nix config show[/] to determine
|
||||
the binary cache urls
|
||||
"""
|
||||
positionals:
|
||||
installables seq[string]
|
||||
flags:
|
||||
cache:
|
||||
? "url of nix binary cache, can be repeated"
|
||||
T seq[string]
|
||||
run:
|
||||
checkForCache(installables, cache)
|
||||
|
|
|
@ -7,8 +7,14 @@ import hwylterm
|
|||
import hwylterm/spin/spinners # todo: remove after hwylterm update
|
||||
|
||||
|
||||
func addArgs*(cmd: var string, args: varargs[string]) =
|
||||
func addArgs*(cmd: string, args: varargs[string]): string =
|
||||
## append to string for command
|
||||
result = cmd & " " & args.join(" ")
|
||||
|
||||
func addArgs*(cmd: var string, args: varargs[string]): string {.discardable.} =
|
||||
## append to string for command
|
||||
cmd &= " " & args.join(" ")
|
||||
result = cmd
|
||||
|
||||
# deprecate in favor of above?
|
||||
func addArg*(cmd: var string, arg: string ) =
|
||||
|
@ -50,32 +56,39 @@ proc runCmdCapt*(
|
|||
result.stderr.add line & '\n'
|
||||
result.exitCode = peekExitCode(p)
|
||||
if result.exitCode != -1:
|
||||
if CaptStdout in capture:
|
||||
result.stdout.add outstrm.readAll()
|
||||
if CaptStderr in capture:
|
||||
result.stderr.add errstrm.readAll()
|
||||
break
|
||||
|
||||
close p
|
||||
|
||||
proc formatStdoutStderr(stdout: string, stderr: string): BbString =
|
||||
proc formatSubprocessError*(s: string): BbString =
|
||||
for line in s.splitLines():
|
||||
result.add bb("[red]->[/] " & line & "\n")
|
||||
|
||||
proc formatStdoutStderr*(stdout: string, stderr: string): BbString =
|
||||
template add(stream: string) =
|
||||
if stream.strip() != "":
|
||||
result.add astToStr(stream).bb("bold") & ":\n"
|
||||
for line in stream.splitlines():
|
||||
result.add bb("[red]->[/] " & line & "\n")
|
||||
result.add formatSubprocessError(stream)
|
||||
add(stdout)
|
||||
add(stderr)
|
||||
|
||||
|
||||
proc runCmdCaptWithSpinner*(
|
||||
cmd: string,
|
||||
msg: BbString | string = bb"",
|
||||
capture: set[CaptureGrp] = {CaptStdout}
|
||||
capture: set[CaptureGrp] = {CaptStdout},
|
||||
check: bool = true
|
||||
): tuple[output, err: string] =
|
||||
var
|
||||
output, err: string
|
||||
code: int
|
||||
with(Dots2, msg):
|
||||
(output, err, code) = runCmdCapt(cmd, capture)
|
||||
if code != 0:
|
||||
if check and code != 0:
|
||||
stderr.write($formatStdoutStderr(output,err))
|
||||
error fmt"{cmd} had non zero exit"
|
||||
quit code
|
||||
|
|
|
@ -3,11 +3,12 @@ import std/[
|
|||
enumerate, os, sequtils, sets, strformat,
|
||||
strutils, sugar, logging, tables, times
|
||||
]
|
||||
export tables
|
||||
import hwylterm, hwylterm/logging, jsony
|
||||
|
||||
import ./[context, exec]
|
||||
|
||||
proc nixCommand(cmd: string, nom: bool = false): string =
|
||||
proc nixCommand*(cmd: string, nom: bool = false): string =
|
||||
if nom:
|
||||
if findExe("nom") == "":
|
||||
fatalQuit "--nom requires nix-output-monitor is installed"
|
||||
|
@ -53,13 +54,13 @@ proc nixosRebuild*(subcmd: NixosRebuildSubcmd, args: openArray[string] = [], rem
|
|||
|
||||
type
|
||||
Derivation = object
|
||||
storePath, hash, name: string
|
||||
storePath*, hash*, name*: string
|
||||
|
||||
DryRunOutput = object
|
||||
toBuild: seq[Derivation]
|
||||
toFetch: seq[Derivation]
|
||||
|
||||
func toDerivation(pkg: string): Derivation =
|
||||
func toDerivation*(pkg: string): Derivation =
|
||||
let path = pkg.strip()
|
||||
let s = path.split("-", 1)
|
||||
result.storePath = path
|
||||
|
@ -108,7 +109,7 @@ proc parseDryRunOutput(err: string): DryRunOutput =
|
|||
result.toBuild.sort(cmpDrv)
|
||||
result.toFetch.sort(cmpDrv)
|
||||
|
||||
proc trunc(s: string, limit: int): string =
|
||||
proc trunc*(s: string, limit: int): string =
|
||||
if s.len <= limit:
|
||||
s
|
||||
else:
|
||||
|
@ -143,22 +144,30 @@ proc toBuildNixosConfiguration(): seq[string] =
|
|||
|
||||
type
|
||||
DerivationOutput = object
|
||||
path: string
|
||||
path*: string
|
||||
# hashAlgo: string
|
||||
# hash: string
|
||||
NixDerivation = object
|
||||
inputDrvs: Table[string, JsonNode]
|
||||
name: string
|
||||
outputs: Table[string, DerivationOutput]
|
||||
inputDrvs*: Table[string, JsonNode]
|
||||
name*: string
|
||||
outputs*: Table[string, DerivationOutput]
|
||||
|
||||
proc evaluateDerivations(drvs: seq[string]): Table[string, NixDerivation] =
|
||||
# here a results var would be nice...
|
||||
proc narHash*(s: string): string =
|
||||
## get hash from nix store path
|
||||
if not s.startsWith("/nix/store/") and s.len >= 44:
|
||||
fatalQuit "failed to extract narHash from: " & s
|
||||
let ss = s.split("-")
|
||||
result = ss[0].split("/")[^1]
|
||||
|
||||
proc evaluateDerivations(drvs: openArray[string]): Table[string, NixDerivation] =
|
||||
var cmd = "nix derivation show -r"
|
||||
cmd.addArgs drvs
|
||||
let (output, _) =
|
||||
runCmdCaptWithSpinner(cmd, "evaluating derivations")
|
||||
fromJson(output, Table[string, NixDerivation])
|
||||
|
||||
proc nixDerivationShow(drvs: seq[string]): Table[string, NixDerivation] =
|
||||
proc nixDerivationShow*(drvs: openArray[string]): Table[string, NixDerivation] =
|
||||
var cmd = "nix derivation show"
|
||||
cmd.addArgs drvs
|
||||
let (output, _ ) =
|
||||
|
|
89
pkgs/oizys/src/oizys/utils.nim
Normal file
89
pkgs/oizys/src/oizys/utils.nim
Normal file
|
@ -0,0 +1,89 @@
|
|||
import std/[strformat, strutils, osproc, sugar, httpclient]
|
||||
import hwylterm
|
||||
import ./[nix, exec,logging]
|
||||
|
||||
|
||||
# TODO: refactor runCmdCaptWithSpinner so it works in getBuildHash
|
||||
proc checkBuild(installable: string): tuple[stdout: string, stderr: string] =
|
||||
var
|
||||
output, err: string
|
||||
code: int
|
||||
let cmd = nixCommand("build").addArgs(installable)
|
||||
with(Dots2, bbfmt"attempt to build: [b]{installable}"):
|
||||
(output, err, code) = runCmdCapt(cmd, capture = {CaptStdout, CaptStderr})
|
||||
if code == 0:
|
||||
fatalQuit fmt"{cmd} had zero exit"
|
||||
result = (output, err)
|
||||
|
||||
proc getBuildHash*(installable: string): string =
|
||||
let (output, err) = checkBuild(installable)
|
||||
for line in err.splitLines():
|
||||
if line.strip().startsWith("got: "):
|
||||
let s = line.split("got:")
|
||||
result = s[1].strip()
|
||||
if result == "":
|
||||
stderr.write formatStdoutStderr(output, err) & "\n"
|
||||
fatalQuit "failed to find update hash from above output"
|
||||
|
||||
proc getCaches(): seq[string] =
|
||||
## use nix to get the current cache urls
|
||||
debug "determing caches to check"
|
||||
let (output, code) = execCmdEx("nix config show")
|
||||
if code != 0:
|
||||
echo formatSubprocessError(output)
|
||||
fatalQuit "error running `nix config show`"
|
||||
|
||||
for line in output.splitLines():
|
||||
if line.startsWith("substituters ="):
|
||||
let s = line.split("=")[1].strip()
|
||||
for u in s.split():
|
||||
result.add u
|
||||
|
||||
if result.len == 0:
|
||||
echo formatSubprocessError(output)
|
||||
fatalQuit "error running `nix config show`"
|
||||
|
||||
|
||||
|
||||
|
||||
proc hasNarinfo*(cache: string, path: string): bool =
|
||||
debug fmt"checking {cache} for {path}"
|
||||
let
|
||||
hash = narHash(path)
|
||||
url = cache & "/" & hash & ".narinfo"
|
||||
try:
|
||||
let client = newHttpClient()
|
||||
result = client.head(url).code == Http200
|
||||
except:
|
||||
result = false
|
||||
|
||||
proc prettyDerivation(path: string): BbString =
|
||||
let drv = path.toDerivation()
|
||||
const maxLen = 40
|
||||
result.add drv.name.trunc(maxLen).alignLeft(maxLen)
|
||||
result.add " "
|
||||
result.add drv.hash.bb("faint")
|
||||
|
||||
proc checkForCache*(installables: seq[string], caches: seq[string]) =
|
||||
let caches =
|
||||
if caches.len > 0: caches
|
||||
else: getCaches()
|
||||
let drvs = nixDerivationShow(installables)
|
||||
# outputs['outs'] might blow up
|
||||
let outs = collect:
|
||||
for name, drv in drvs:
|
||||
{name: drv.outputs["out"].path}
|
||||
|
||||
for name, path in outs:
|
||||
var found = false
|
||||
for cache in caches:
|
||||
if hasNarinfo(cache, path):
|
||||
found = true
|
||||
info prettyDerivation(path)
|
||||
info fmt"exists in {cache}"
|
||||
break
|
||||
|
||||
if not found:
|
||||
info fmt"failed to find:"
|
||||
info prettyDerivation(path)
|
||||
|
1
todo.md
1
todo.md
|
@ -4,7 +4,6 @@
|
|||
|
||||
Could make an `oizys check` command:
|
||||
|
||||
- `utils hash` given some flake-url or path attempt to build and extract "got: <hash>" string
|
||||
- `check lock` could encapsulate any diagnostic code I want to run that does things like check for too many "inputs".
|
||||
essentially getting the same output as this `jq < flake.lock '.nodes | keys[] | select(contains("_"))`
|
||||
- `utils cache <path>` check for the narinfo in my cache given some nix store path
|
||||
|
|
Loading…
Reference in a new issue