mirror of
https://github.com/daylinmorgan/oizys.git
synced 2024-12-22 01:50:44 -06:00
oizys nim wip
This commit is contained in:
parent
d1b7c652d2
commit
8fe319e525
21 changed files with 1035 additions and 39 deletions
103
flake.lock
103
flake.lock
|
@ -20,11 +20,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724273991,
|
||||
"narHash": "sha256-+aUSOXKGpS5CRm1oTitgNAr05ThQNbKIXalZHl3nC6Y=",
|
||||
"lastModified": 1724781866,
|
||||
"narHash": "sha256-ItgACCJCwn8Rx7p8hJBpnU9eCtrdmkg4AbqMZL/rXlY=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "aquamarine",
|
||||
"rev": "9a3161ad4c78dc420d1cbb3aae638222608c7de4",
|
||||
"rev": "7cc3d3179c06caf3769afb3eb0c69aa55676c96a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -323,11 +323,11 @@
|
|||
"xdph": "xdph"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724701003,
|
||||
"narHash": "sha256-kTceEi5B4t2u5oG3bKnGgZkHxFTsvYAUiAmyYA/6Y3o=",
|
||||
"lastModified": 1724850433,
|
||||
"narHash": "sha256-WSjYdnlg6Qq0xrjCgL/WJ7a+kEWQtQmYrw0TV4ykppY=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "eb42adc4c090918ad6be9fcb24066da8cdfd9bd0",
|
||||
"revCount": 5145,
|
||||
"rev": "98e99cd03df5b4421f72f2a3f2d7de53f8261f1f",
|
||||
"revCount": 5152,
|
||||
"submodules": true,
|
||||
"type": "git",
|
||||
"url": "https://github.com/hyprwm/Hyprland/"
|
||||
|
@ -504,11 +504,11 @@
|
|||
"lix": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1724714224,
|
||||
"narHash": "sha256-Fn72c2ycgYERAdwWEPmIUhuOmgOwuvZhTNdqOuiR0uw=",
|
||||
"rev": "0dc486a5bf218870aafd5552586ab4330881647e",
|
||||
"lastModified": 1724863402,
|
||||
"narHash": "sha256-2xrZAo4m0SNklS71RCfWzNXu79OAZMrHNpe6RGOh4OY=",
|
||||
"rev": "422550fd68a5877534b1ca577fc3c7d89b6706dd",
|
||||
"type": "tarball",
|
||||
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/0dc486a5bf218870aafd5552586ab4330881647e.tar.gz?rev=0dc486a5bf218870aafd5552586ab4330881647e"
|
||||
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/422550fd68a5877534b1ca577fc3c7d89b6706dd.tar.gz?rev=422550fd68a5877534b1ca577fc3c7d89b6706dd"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
|
@ -538,11 +538,29 @@
|
|||
"url": "https://git.lix.systems/lix-project/nixos-module/archive/main.tar.gz"
|
||||
}
|
||||
},
|
||||
"nim2nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724878933,
|
||||
"narHash": "sha256-VP0+Lal3jJJqDH1EzQX73rP9Ue8ZTIyAErJvDz6PQSg=",
|
||||
"owner": "daylinmorgan",
|
||||
"repo": "nim2nix",
|
||||
"rev": "5153c772e4c6a4f5645efa85ce536fe1c5063ebb",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "daylinmorgan",
|
||||
"repo": "nim2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-eval-jobs": {
|
||||
"inputs": {
|
||||
"flake-parts": "flake-parts",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": "nixpkgs_5",
|
||||
"nixpkgs": "nixpkgs_6",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
},
|
||||
"locked": {
|
||||
|
@ -630,7 +648,7 @@
|
|||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
"nixpkgs": "nixpkgs_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724664098,
|
||||
|
@ -682,14 +700,14 @@
|
|||
"flake-compat": "flake-compat_2",
|
||||
"lib-aggregate": "lib-aggregate",
|
||||
"nix-eval-jobs": "nix-eval-jobs",
|
||||
"nixpkgs": "nixpkgs_6"
|
||||
"nixpkgs": "nixpkgs_7"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724746994,
|
||||
"narHash": "sha256-krOFIWrWMW44GBpjjKKo4dcM6oPXI9YpFj+Wqf2PwxU=",
|
||||
"lastModified": 1724858360,
|
||||
"narHash": "sha256-Z78j0lWk4j8U5jC34S2ON37I5Z4r9yJt1orN4PBIra0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs-wayland",
|
||||
"rev": "f42d86203af2967f81c50cf4f0722c013bc22170",
|
||||
"rev": "4fad2594f6dc0c0ac3b58272b7060b51d460b607",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -715,6 +733,22 @@
|
|||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1724479785,
|
||||
"narHash": "sha256-pP3Azj5d6M5nmG68Fu4JqZmdGt4S4vqI5f8te+E/FTw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d0e1602ddde669d5beb01aec49d71a51937ed7be",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1724316499,
|
||||
"narHash": "sha256-Qb9MhKBUTCfWg/wqqaxt89Xfi6qTD3XpTzQ9eXi3JmE=",
|
||||
|
@ -730,13 +764,13 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"nixpkgs_5": {
|
||||
"locked": {
|
||||
"lastModified": 1724395761,
|
||||
"narHash": "sha256-zRkDV/nbrnp3Y8oCADf5ETl1sDrdmAW6/bBVJ8EbIdQ=",
|
||||
"lastModified": 1724748588,
|
||||
"narHash": "sha256-NlpGA4+AIf1dKNq76ps90rxowlFXUsV9x7vK/mN37JM=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ae815cee91b417be55d43781eb4b73ae1ecc396c",
|
||||
"rev": "a6292e34000dc93d43bccf78338770c1c5ec8a99",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -746,7 +780,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_5": {
|
||||
"nixpkgs_6": {
|
||||
"locked": {
|
||||
"lastModified": 1723221148,
|
||||
"narHash": "sha256-7pjpeQlZUNQ4eeVntytU3jkw9dFK3k1Htgk2iuXjaD8=",
|
||||
|
@ -762,7 +796,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_6": {
|
||||
"nixpkgs_7": {
|
||||
"locked": {
|
||||
"lastModified": 1724479785,
|
||||
"narHash": "sha256-pP3Azj5d6M5nmG68Fu4JqZmdGt4S4vqI5f8te+E/FTw=",
|
||||
|
@ -809,11 +843,11 @@
|
|||
"rust-overlay": "rust-overlay"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724759134,
|
||||
"narHash": "sha256-E4nBGiBGkdB1e01rGLAEiDhM5cKMnVbRPUXwXf3CjaU=",
|
||||
"lastModified": 1724859070,
|
||||
"narHash": "sha256-/jeh/OJm5+gmg+dQxpWetL9jgjk+zGe7uCRLvbNvukA=",
|
||||
"owner": "roc-lang",
|
||||
"repo": "roc",
|
||||
"rev": "7811d8876865dc9927d707edb8fd8a426a595a0e",
|
||||
"rev": "479feca39618a58770db68b44072be1f29df8d84",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -830,9 +864,10 @@
|
|||
"hyprman": "hyprman",
|
||||
"lix": "lix",
|
||||
"lix-module": "lix-module",
|
||||
"nim2nix": "nim2nix",
|
||||
"nix-index-database": "nix-index-database",
|
||||
"nixos-wsl": "nixos-wsl",
|
||||
"nixpkgs": "nixpkgs_4",
|
||||
"nixpkgs": "nixpkgs_5",
|
||||
"nixpkgs-wayland": "nixpkgs-wayland",
|
||||
"pixi": "pixi",
|
||||
"roc": "roc",
|
||||
|
@ -1040,11 +1075,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723841055,
|
||||
"narHash": "sha256-ykjmNEXFJ4lrW1LeB4dVsNlPKlNB0VWNnOTp1sLbOqQ=",
|
||||
"lastModified": 1724782685,
|
||||
"narHash": "sha256-/gzaaWVqXbnj78pNC7cOW/MDZidO127v9QRpAyBgczU=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "eca60579ef577ad45aa1a371f006697ddc2611d6",
|
||||
"revCount": 5,
|
||||
"rev": "5289c14095ec7fe0676a0dd3c3084ead095da1a5",
|
||||
"revCount": 6,
|
||||
"type": "git",
|
||||
"url": "https://git.dayl.in/daylin/utils.git"
|
||||
},
|
||||
|
@ -1092,11 +1127,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1724718400,
|
||||
"narHash": "sha256-i83icUP6218jkNLBiHj2JyhKrVbgkU2mOGFvpFjw0WM=",
|
||||
"lastModified": 1724847079,
|
||||
"narHash": "sha256-bbcvuJqmjShg6Uet6CptnxkuPBRL2drQmvnaXi832Xk=",
|
||||
"owner": "mitchellh",
|
||||
"repo": "zig-overlay",
|
||||
"rev": "20a8e0316531f825284ef15fe20b4f9848fbb4e4",
|
||||
"rev": "ce690c0c732a9627a9736f145d1739d56d4905c4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
zig-overlay.url = "github:mitchellh/zig-overlay";
|
||||
zls.url = "github:zigtools/zls";
|
||||
|
||||
nim2nix.url = "github:daylinmorgan/nim2nix";
|
||||
pixi.url = "github:daylinmorgan/pixi-flake";
|
||||
f1multiviewer.url = "github:daylinmorgan/f1multiviewer-flake";
|
||||
tsm.url = "github:daylinmorgan/tsm?dir=nix";
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
nix-ld = enabled // {
|
||||
overkill = enabled;
|
||||
};
|
||||
languages = "misc|nim|node|nushell|python|roc|tex|zig" |> listify;
|
||||
# languages = "misc|nim|node|nushell|python|roc|tex|zig" |> listify;
|
||||
languages = "misc|nim|node|nushell|python|roc|tex" |> listify;
|
||||
}
|
||||
// (
|
||||
''
|
||||
|
|
|
@ -9,7 +9,10 @@ let
|
|||
inherit (import ./generators.nix { inherit lib self inputs; }) mkIso mkSystem;
|
||||
#supportedSystems = ["x86_64-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin"];
|
||||
supportedSystems = [ "x86_64-linux" ];
|
||||
forAllSystems = f: genAttrs supportedSystems (system: f (import nixpkgs { inherit system; }));
|
||||
forAllSystems = f: genAttrs supportedSystems (system: f (import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [inputs.nim2nix.overlays.default];
|
||||
}));
|
||||
|
||||
inheritFlakePkgs =
|
||||
pkgs: flakes:
|
||||
|
@ -27,6 +30,7 @@ let
|
|||
pkgs:
|
||||
rec {
|
||||
default = oizys-cli;
|
||||
oizys-nim = pkgs.callPackage ../pkgs/oizys-nim { };
|
||||
oizys-cli = pkgs.callPackage ../pkgs/oizys { };
|
||||
iso = mkIso.config.system.build.isoImage;
|
||||
roc = (pkgsFromSystem pkgs.system "roc").full;
|
||||
|
@ -39,10 +43,11 @@ let
|
|||
);
|
||||
|
||||
devShells = forAllSystems (pkgs: {
|
||||
default = pkgs.mkShell {
|
||||
oizys = pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
git
|
||||
deadnix
|
||||
openssl
|
||||
nim
|
||||
nimble
|
||||
];
|
||||
};
|
||||
});
|
||||
|
|
1
pkgs/oizys-nim/.envrc
Normal file
1
pkgs/oizys-nim/.envrc
Normal file
|
@ -0,0 +1 @@
|
|||
use flake "../..#oizys"
|
9
pkgs/oizys-nim/.gitignore
vendored
Normal file
9
pkgs/oizys-nim/.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
nimbledeps
|
||||
nimble.paths
|
||||
nimble.develop
|
||||
|
||||
# binaries
|
||||
oizys*
|
||||
!src/oizys
|
||||
!src/oizys.nim*
|
||||
oizys.out
|
8
pkgs/oizys-nim/config.nims
Normal file
8
pkgs/oizys-nim/config.nims
Normal file
|
@ -0,0 +1,8 @@
|
|||
task build, "build oizys":
|
||||
selfExec "c -o:oizys src/oizys.nim"
|
||||
|
||||
# begin Nimble config (version 2)
|
||||
--noNimblePath
|
||||
when withDir(thisDir(), system.fileExists("nimble.paths")):
|
||||
include "nimble.paths"
|
||||
# end Nimble config
|
12
pkgs/oizys-nim/default.nix
Normal file
12
pkgs/oizys-nim/default.nix
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
lib,
|
||||
openssl,
|
||||
buildNimblePackage,
|
||||
}:
|
||||
buildNimblePackage {
|
||||
name = "oizys";
|
||||
verions = "unstable";
|
||||
src = lib.cleanSource ./.;
|
||||
nativeBuildInputs = [ openssl ];
|
||||
nimbleDepsHash = "sha256-Eheeve4MbB3v1oVj0mB36Mv2Q3vJGLEbbShds1af23g=";
|
||||
}
|
36
pkgs/oizys-nim/nimble.lock
Normal file
36
pkgs/oizys-nim/nimble.lock
Normal file
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"version": 2,
|
||||
"packages": {
|
||||
"bbansi": {
|
||||
"version": "0.1.1",
|
||||
"vcsRevision": "9a85d9ed028f06f1ed1ee6851480a51408a6004e",
|
||||
"url": "https://github.com/daylinmorgan/bbansi",
|
||||
"downloadMethod": "git",
|
||||
"dependencies": [],
|
||||
"checksums": {
|
||||
"sha1": "b338433f9a7a1b788b7583674c2b14096ced29ee"
|
||||
}
|
||||
},
|
||||
"cligen": {
|
||||
"version": "1.7.0",
|
||||
"vcsRevision": "4193f802796f15559c81c6dd56724d6f20345917",
|
||||
"url": "https://github.com/c-blake/cligen.git",
|
||||
"downloadMethod": "git",
|
||||
"dependencies": [],
|
||||
"checksums": {
|
||||
"sha1": "300bd7fdb6e48d2d98e34ed0661206b50331e99c"
|
||||
}
|
||||
},
|
||||
"jsony": {
|
||||
"version": "1.1.5",
|
||||
"vcsRevision": "ea811bec7fa50f5abd3088ba94cda74285e93f18",
|
||||
"url": "https://github.com/treeform/jsony",
|
||||
"downloadMethod": "git",
|
||||
"dependencies": [],
|
||||
"checksums": {
|
||||
"sha1": "6aeb83e7481ca8686396a568096054bc668294df"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tasks": {}
|
||||
}
|
16
pkgs/oizys-nim/oizys.nimble
Normal file
16
pkgs/oizys-nim/oizys.nimble
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Package
|
||||
|
||||
version = "0.1.0"
|
||||
author = "Daylin Morgan"
|
||||
description = "nix begat oizys"
|
||||
license = "MIT"
|
||||
srcDir = "src"
|
||||
bin = @["oizys"]
|
||||
|
||||
|
||||
# Dependencies
|
||||
|
||||
requires "nim >= 2.0.8"
|
||||
requires "cligen"
|
||||
requires "jsony"
|
||||
requires "https://github.com/daylinmorgan/bbansi#9a85d9e"
|
128
pkgs/oizys-nim/src/oizys.nim
Normal file
128
pkgs/oizys-nim/src/oizys.nim
Normal file
|
@ -0,0 +1,128 @@
|
|||
## nix begat oizys
|
||||
import std/[os, tables, sequtils, strformat,]
|
||||
|
||||
import cligen, bbansi
|
||||
import oizys/[context, github, nix, overlay, logging]
|
||||
|
||||
|
||||
addHandler(
|
||||
newFancyConsoleLogger(
|
||||
levelThreshold=lvlAll,
|
||||
useStderr = true,
|
||||
fmtPrefix = $bb"[b magenta]oizys"
|
||||
)
|
||||
)
|
||||
|
||||
overlay:
|
||||
proc pre(
|
||||
flake: string = "",
|
||||
host: seq[string] = @[],
|
||||
debug: bool = false,
|
||||
resetCache: bool = false,
|
||||
rest: seq[string],
|
||||
) =
|
||||
if not debug: setLogFilter(lvlInfo)
|
||||
updateContext(host, flake, debug, resetCache)
|
||||
|
||||
proc dry(minimal: bool = false) =
|
||||
## dry run build
|
||||
nixBuildHostDry(minimal, rest)
|
||||
|
||||
proc output(yes: bool = false) =
|
||||
## output
|
||||
echo nixosConfigAttrs().join(" ")
|
||||
|
||||
proc update(yes: bool = false) =
|
||||
## *TBD* update and run nixos-rebuild
|
||||
fatal "not implemented"
|
||||
|
||||
proc build(minimal: bool = false) =
|
||||
## nix build
|
||||
nixBuild(minimal, rest)
|
||||
|
||||
proc cache(name: string = "daylin") =
|
||||
## *TBD* build and push to cachix
|
||||
fatal "not implemented"
|
||||
|
||||
proc osCmd() =
|
||||
## nixos-rebuild
|
||||
if len(rest) == 0: quit "please provide subcmd"
|
||||
let subcmd = rest[0]
|
||||
if subcmd notin nixosSubcmds:
|
||||
error (
|
||||
&"unknown nixos-rebuild subcmd: {subcmd}\nexpected one of: \n" &
|
||||
nixosSubcmds.mapIt(" " & it).join("\n")
|
||||
)
|
||||
quit QuitFailure
|
||||
nixosRebuild(subcmd, rest[1..^1])
|
||||
|
||||
proc ci(`ref`: string = "main") =
|
||||
## *TBD* trigger GHA update flow
|
||||
if rest.len == 0:
|
||||
fatal "expected workflow file name"; quit QuitFailure
|
||||
createDispatch(rest[0], `ref`)
|
||||
|
||||
proc checkExes() =
|
||||
if findExe("nix") == "":
|
||||
quit("oizys requires nix", QuitFailure)
|
||||
|
||||
proc `//`(t1: Table[string, string], t2: Table[string, string]): Table[string, string] =
|
||||
# nix style table merge
|
||||
for k, v in t1.pairs(): result[k] = v
|
||||
for k, v in t2.pairs(): result[k] = v
|
||||
|
||||
proc setupCligen() =
|
||||
let isColor = getEnv("NO_COLOR") == ""
|
||||
if clCfg.useMulti == "":
|
||||
clCfg.useMulti =
|
||||
if isColor:
|
||||
"${doc}\e[1mUsage\e[m:\n $command {SUBCMD} [sub-command options & parameters]\n\n\e[1msubcommands\e[m:\n$subcmds"
|
||||
else:
|
||||
"${doc}Usage:\n $command {SUBCMD} [sub-command options & parameters]\n\nsubcommands:\n$subcmds"
|
||||
if not isColor: return
|
||||
if clCfg.helpAttr.len == 0:
|
||||
clCfg.helpAttr = {"cmd": "\e[1;36m", "clDescrip": "", "clDflVal": "\e[33m",
|
||||
"clOptKeys": "\e[32m", "clValType": "\e[31m", "args": "\e[3m"}.toTable()
|
||||
clCfg.helpAttrOff = {"cmd": "\e[m", "clDescrip": "\e[m", "clDflVal": "\e[m",
|
||||
"clOptKeys": "\e[m", "clValType": "\e[m", "args": "\e[m"}.toTable()
|
||||
# clCfg.use does nothing?
|
||||
clCfg.useHdr = "\e[1mUsage\e[m:\n "
|
||||
|
||||
when isMainModule:
|
||||
checkExes()
|
||||
setupCligen()
|
||||
let (optOpen, optClose) =
|
||||
if getEnv("NO_COLOR") == "": ("\e[1m","\e[m")
|
||||
else: ("","")
|
||||
let
|
||||
usage = &"$command [flags]\n$doc{optOpen}Options{optClose}:\n$options"
|
||||
osUsage = &"$command [subcmd] [flags]\n$doc{optOpen}Options{optClose}:\n$options"
|
||||
|
||||
const
|
||||
sharedHelp = {
|
||||
"flake" : "path/to/flake",
|
||||
"host" : "host(s) to build",
|
||||
"debug" : "enable debug mode",
|
||||
"resetCache" : "set cache timeout to 0"
|
||||
}.toTable()
|
||||
updateHelp = {
|
||||
"yes" : "skip all confirmation prompts"
|
||||
}.toTable() // sharedHelp
|
||||
ciHelp = {
|
||||
"ref" : "git ref/branch/tag to trigger workflow on"
|
||||
}.toTable()
|
||||
cacheHelp = {
|
||||
"name" : "name of cachix binary cache"
|
||||
}.toTable() // sharedHelp
|
||||
|
||||
# setting clCfg.use wasn't working?
|
||||
dispatchMulti(
|
||||
[build, help = sharedHelp, usage = usage],
|
||||
[cache, help = cacheHelp, usage = usage],
|
||||
[ci, help = ciHelp, usage = usage],
|
||||
[dry, help = sharedHelp, usage = usage],
|
||||
[osCmd, help = sharedHelp, usage = osUsage, cmdName = "os"],
|
||||
[output, help = sharedHelp, usage = usage],
|
||||
[update, help = updateHelp, usage = usage],
|
||||
)
|
||||
|
1
pkgs/oizys-nim/src/oizys.nim.cfg
Normal file
1
pkgs/oizys-nim/src/oizys.nim.cfg
Normal file
|
@ -0,0 +1 @@
|
|||
-d:ssl
|
54
pkgs/oizys-nim/src/oizys/context.nim
Normal file
54
pkgs/oizys-nim/src/oizys/context.nim
Normal file
|
@ -0,0 +1,54 @@
|
|||
import std/[logging, os, strformat, strutils]
|
||||
from std/nativesockets import getHostname
|
||||
|
||||
type
|
||||
OizysContext* = object
|
||||
flake, host: string
|
||||
hosts: seq[string]
|
||||
debug: bool
|
||||
ci: bool
|
||||
resetCache: bool
|
||||
|
||||
proc initContext*(): OizysContext =
|
||||
result.hosts = @[getHostname()]
|
||||
result.flake = "github:daylinmorgan/oizys"
|
||||
let localDir = getHomeDir() / "oizys"
|
||||
if localDir.dirExists:
|
||||
result.flake = localDir
|
||||
let envVar = getEnv("OIZYS_DIR")
|
||||
if envVar != "":
|
||||
result.flake = envVar
|
||||
result.ci = getEnv("GITHUB_STEP_SUMMARY") != ""
|
||||
|
||||
var oc = initContext()
|
||||
proc checkPath(s: string): string =
|
||||
## fail if path doesn't exist
|
||||
if not s.dirExists:
|
||||
error fmt"flake path: {s} does not exist"
|
||||
quit()
|
||||
s
|
||||
|
||||
# public api -------------------------------------
|
||||
|
||||
proc updateContext*(
|
||||
host: seq[string],
|
||||
flake: string,
|
||||
debug: bool,
|
||||
resetCache: bool
|
||||
) =
|
||||
oc.debug = debug
|
||||
oc.resetCache = resetCache
|
||||
if host.len > 0:
|
||||
oc.hosts = host
|
||||
if flake != "":
|
||||
oc.flake =
|
||||
if flake.startsWith("github") or flake.startsWith("git+"): flake
|
||||
else: checkPath(flake.normalizedPath().absolutePath())
|
||||
|
||||
proc getHosts*(): seq[string] = return oc.hosts
|
||||
proc getFlake*(): string = return oc.flake
|
||||
proc isDebug*(): bool = return oc.debug
|
||||
proc isResetCache*(): bool = return oc.resetCache
|
||||
proc isCi*(): bool = return oc.ci
|
||||
|
||||
|
43
pkgs/oizys-nim/src/oizys/exec.nim
Normal file
43
pkgs/oizys-nim/src/oizys/exec.nim
Normal file
|
@ -0,0 +1,43 @@
|
|||
import std/[
|
||||
osproc, strformat,
|
||||
strutils, streams, logging
|
||||
]
|
||||
|
||||
import ./spin
|
||||
|
||||
|
||||
func addArgs*(cmd: var string, args: seq[string]) =
|
||||
cmd &= " " & args.join(" ")
|
||||
|
||||
func addArg*(cmd: var string, arg: string) =
|
||||
cmd &= " " & arg
|
||||
|
||||
proc runCmd*(cmd: string): int =
|
||||
debug fmt"running cmd: {cmd}"
|
||||
execCmd cmd
|
||||
|
||||
proc runCmdCapt*(cmd: string): tuple[stdout, stderr: string, exitCode: int] =
|
||||
let args = cmd.splitWhitespace()
|
||||
let p = startProcess(args[0], args = args[1..^1], options = {poUsePath})
|
||||
result = (
|
||||
readAll p.outputStream,
|
||||
readAll p.errorStream,
|
||||
waitForExit p
|
||||
)
|
||||
close p
|
||||
|
||||
proc runCmdCaptWithSpinner*(cmd: string, msg: string = ""): tuple[output, err: string] =
|
||||
debug fmt"running command: {cmd}"
|
||||
withSpinner(msg):
|
||||
let (output, err, code) = runCmdCapt(cmd)
|
||||
if code != 0:
|
||||
stderr.writeLine("stdout\n" & output)
|
||||
stderr.writeLine("stderr\n" & err)
|
||||
error fmt"{cmd} had non zero exit"
|
||||
quit code
|
||||
return (output, err)
|
||||
|
||||
proc quitWithCmd*(cmd: string) =
|
||||
debug cmd
|
||||
quit(execCmd cmd)
|
||||
|
39
pkgs/oizys-nim/src/oizys/github.nim
Normal file
39
pkgs/oizys-nim/src/oizys/github.nim
Normal file
|
@ -0,0 +1,39 @@
|
|||
import std/[httpclient,logging, os, strformat, strutils, json]
|
||||
|
||||
var ghToken = getEnv("GITHUB_TOKEN")
|
||||
|
||||
#[curl -L \
|
||||
-X POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer <YOUR-TOKEN>" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/OWNER/REPO/actions/workflows/WORKFLOW_ID/dispatches \
|
||||
-d '{"ref":"topic-branch","inputs":{"name":"Mona the Octocat","home":"San Francisco, CA"}}'
|
||||
]#
|
||||
|
||||
proc postGhApi(url: string, body: JsonNode) =
|
||||
if ghToken == "": fatal "GITHUB_TOKEN not set"; quit QuitFailure
|
||||
let client = newHttpClient()
|
||||
client.headers = newHttpHeaders({
|
||||
"Accept" : "application/vnd.github+json",
|
||||
"Authorization" : fmt"Bearer {ghToken}",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
})
|
||||
echo $body
|
||||
let response = client.post(url, body = $body)
|
||||
info fmt"Status: {response.status}"
|
||||
|
||||
proc createDispatch*(workflowFileName: string, `ref`: string) =
|
||||
## https://docs.github.com/en/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event
|
||||
var workflow =
|
||||
if workflowFileName.endsWith(".yml") or workflowFileName.endsWith(".yaml"): workflowFileName
|
||||
else: workflowFileName & ".yml"
|
||||
info fmt"creating dispatch event for {workflow}"
|
||||
postGhApi(
|
||||
fmt"https://api.github.com/repos/daylinmorgan/oizys/actions/workflows/{workflow}/dispatches",
|
||||
%*{
|
||||
"ref": `ref`,
|
||||
}
|
||||
)
|
||||
|
||||
|
21
pkgs/oizys-nim/src/oizys/ignored.txt
Normal file
21
pkgs/oizys-nim/src/oizys/ignored.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
ld-library-path
|
||||
builder.pl
|
||||
profile
|
||||
system-path
|
||||
nixos-help
|
||||
nixos-install
|
||||
nixos-version
|
||||
nixos-manual-html
|
||||
nixos-rebuild
|
||||
nixos-configuration-reference-manpage
|
||||
nixos-generate-config
|
||||
nixos-enter
|
||||
nixos-container
|
||||
nixos-build-vms
|
||||
nixos-wsl-version
|
||||
nixos-wsl-welcome-message
|
||||
nixos-wsl-welcome
|
||||
restic-gdrive
|
||||
gitea
|
||||
lock
|
||||
code
|
108
pkgs/oizys-nim/src/oizys/logging.nim
Normal file
108
pkgs/oizys-nim/src/oizys/logging.nim
Normal file
|
@ -0,0 +1,108 @@
|
|||
import std/[logging,strutils]
|
||||
export logging
|
||||
|
||||
import bbansi
|
||||
|
||||
var
|
||||
handlers {.threadvar.}: seq[Logger]
|
||||
|
||||
#[
|
||||
Level* = enum ## \
|
||||
lvlAll, ## All levels active
|
||||
lvlDebug, ## Debug level and above are active
|
||||
lvlInfo, ## Info level and above are active
|
||||
lvlNotice, ## Notice level and above are active
|
||||
lvlWarn, ## Warn level and above are active
|
||||
lvlError, ## Error level and above are active
|
||||
lvlFatal, ## Fatal level and above are active
|
||||
lvlNone ## No levels active; nothing is logged
|
||||
]#
|
||||
|
||||
type
|
||||
FancyConsoleLogger* = ref object of Logger
|
||||
## A logger that writes log messages to the console.
|
||||
##
|
||||
## Create a new ``FancyConsoleLogger`` with the `newFancyConsoleLogger proc
|
||||
## <#newConsoleLogger>`_.
|
||||
##
|
||||
useStderr*: bool ## If true, writes to stderr; otherwise, writes to stdout
|
||||
flushThreshold*: Level ## Only messages that are at or above this
|
||||
## threshold will be flushed immediately
|
||||
fmtPrefix: string
|
||||
fmtSep: string
|
||||
fmtStrs: array[Level, string]
|
||||
|
||||
|
||||
const defaultFlushThreshold = lvlAll
|
||||
|
||||
proc genFmtStr(
|
||||
fmtPrefix, fmtSep, fmtSuffix, levelBb: string,
|
||||
level: Level
|
||||
): string =
|
||||
var parts: seq[string]
|
||||
if fmtPrefix != "": parts.add fmtPrefix
|
||||
parts.add $LevelNames[level].bb(levelBb)
|
||||
return parts.join(fmtSep) & fmtSuffix
|
||||
|
||||
|
||||
proc newFancyConsoleLogger*(
|
||||
levelThreshold = lvlAll,
|
||||
fmtPrefix= "",
|
||||
fmtSep = "|",
|
||||
fmtSuffix ="| ",
|
||||
useStderr = false,
|
||||
flushThreshold = defaultFlushThreshold,
|
||||
debugBb: string = "faint",
|
||||
infoBb: string = "bold",
|
||||
noticeBb: string = "bold",
|
||||
warnBb: string = "bold yellow",
|
||||
errorBb: string = "bold red",
|
||||
fatalBb: string = "bold red"
|
||||
): FancyConsoleLogger =
|
||||
## Creates a new `ColoredConsoleLogger<#ConsoleLogger>`_.
|
||||
new result
|
||||
let fmtStrs: array[Level, string] = [
|
||||
genFmtStr(fmtPrefix,fmtSep, fmtSuffix, "", lvlAll),
|
||||
genFmtStr(fmtPrefix,fmtSep, fmtSuffix, debugBb, lvlDebug),
|
||||
genFmtStr(fmtPrefix,fmtSep, fmtSuffix, infobb, lvlInfo),
|
||||
genFmtStr(fmtPrefix,fmtSep, fmtSuffix, noticeBb, lvlNotice),
|
||||
genFmtStr(fmtPrefix,fmtSep, fmtSuffix, warnBb, lvlWarn),
|
||||
genFmtStr(fmtPrefix,fmtSep, fmtSuffix, errorBb, lvlError),
|
||||
genFmtStr(fmtPrefix,fmtSep, fmtSuffix, fatalBb, lvlFatal),
|
||||
genFmtStr(fmtPrefix, fmtSep, fmtSuffix, "", lvlNone)
|
||||
]
|
||||
result.fmtPrefix = fmtPrefix
|
||||
result.fmtSep = fmtSep
|
||||
result.levelThreshold = levelThreshold
|
||||
result.flushThreshold = flushThreshold
|
||||
result.useStderr = useStderr
|
||||
result.fmtStrs = fmtStrs
|
||||
|
||||
|
||||
method log*(logger: FancyConsoleLogger, level: Level, args: varargs[string, `$`]) {.gcsafe.} =
|
||||
## Logs to the console with the given `FancyConsoleLogger<#ConsoleLogger>`_ only.
|
||||
##
|
||||
## This method ignores the list of registered handlers.
|
||||
##
|
||||
## Whether the message is logged depends on both the ConsoleLogger's
|
||||
## ``levelThreshold`` field and the global log filter set using the
|
||||
## `setLogFilter proc<#setLogFilter,Level>`_.
|
||||
##
|
||||
## **Note:** Only error and fatal messages will cause the output buffer
|
||||
## to be flushed immediately by default. Set ``flushThreshold`` when creating
|
||||
## the logger to change this.
|
||||
|
||||
if level >= logger.levelThreshold:
|
||||
let ln = substituteLog(logger.fmtStrs[level], level, args)
|
||||
when defined(js): {.fatal: "handler does note support JS".}
|
||||
try:
|
||||
let handle =
|
||||
if logger.useStderr: stderr
|
||||
else: stdout
|
||||
writeLine(handle, ln)
|
||||
if level >= logger.flushThreshold: flushFile(handle)
|
||||
except IOError:
|
||||
discard
|
||||
|
||||
proc addHandlers*(handler: Logger) =
|
||||
handlers.add(handler)
|
217
pkgs/oizys-nim/src/oizys/nix.nim
Normal file
217
pkgs/oizys-nim/src/oizys/nix.nim
Normal file
|
@ -0,0 +1,217 @@
|
|||
import std/[
|
||||
algorithm, json,
|
||||
enumerate, os, osproc, sequtils, strformat,
|
||||
strutils, sugar, logging, tables
|
||||
]
|
||||
import bbansi, jsony
|
||||
import ./[context, exec]
|
||||
|
||||
|
||||
proc nixCommand(cmd: string): string =
|
||||
result = "nix"
|
||||
if isResetCache():
|
||||
result.addArg "--narinfo-cache-negative-ttl 0"
|
||||
result.addArg "--log-format multiline"
|
||||
result.addArg cmd
|
||||
|
||||
proc nixosConfigAttrs*(): seq[string] =
|
||||
for host in getHosts():
|
||||
result.add fmt"{getFlake()}#nixosConfigurations.{host}.config.system.build.toplevel"
|
||||
|
||||
const nixosSubcmds* =
|
||||
"""switch boot test build dry-build dry-activate edit
|
||||
repl build-vm build-vm-with-bootloader list-generations""".splitWhitespace()
|
||||
|
||||
proc nixosRebuild*(subcmd: string, rest: seq[string] = @[]) =
|
||||
var cmd = fmt"sudo nixos-rebuild {subcmd} --flake {getFlake()} --log-format multiline"
|
||||
if getHosts().len > 1:
|
||||
error "nixos-rebuild only supports one host"
|
||||
quit QuitFailure
|
||||
cmd.addArgs rest
|
||||
quitWithCmd cmd
|
||||
|
||||
type
|
||||
Derivation = object
|
||||
storePath, hash, name: string
|
||||
|
||||
DryRunOutput = object
|
||||
toBuild: seq[Derivation]
|
||||
toFetch: seq[Derivation]
|
||||
|
||||
func toDerivation(pkg: string): Derivation =
|
||||
let path = pkg.strip()
|
||||
let s = path.split("-", 1)
|
||||
result.storePath = path
|
||||
result.hash = s[0].rsplit("/")[^1]
|
||||
result.name = s[^1].replace(".drv","")
|
||||
|
||||
func toDerivations(lines: seq[string]): seq[Derivation] =
|
||||
for pkg in lines:
|
||||
result.add (toDerivation pkg)
|
||||
|
||||
proc cmpDrv(x, y: Derivation): int =
|
||||
cmp(x.name, y.name)
|
||||
|
||||
proc parseDryRunOutput(err: string): DryRunOutput =
|
||||
let lines = err.strip().splitLines()
|
||||
let theseLines = collect:
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith("these"): i
|
||||
|
||||
case theseLines.len:
|
||||
of 2:
|
||||
let (firstIdx, secondIdx) = (theseLines[0], theseLines[1])
|
||||
result.toBuild = lines[(firstIdx + 1) .. (secondIdx - 1)].toDerivations()
|
||||
result.toFetch = lines[(secondIdx + 1) .. ^1].toDerivations()
|
||||
of 1:
|
||||
let idx = theseLines[0]
|
||||
let line = lines[idx]
|
||||
let drvs = lines[idx .. ^1].toDerivations()
|
||||
if line.contains("built:"):
|
||||
result.toBuild = drvs
|
||||
elif line.contains("will be fetched"):
|
||||
result.toFetch =drvs
|
||||
else:
|
||||
fatal "expected on of the lines to contain built or fetched check the output below"
|
||||
stderr.writeLine err
|
||||
quit()
|
||||
of 0:
|
||||
info "nothing to do";
|
||||
quit(QuitSuccess)
|
||||
else:
|
||||
fatal "unexpected output from nix"
|
||||
stderr.writeLine err
|
||||
quit()
|
||||
|
||||
result.toBuild.sort(cmpDrv)
|
||||
result.toFetch.sort(cmpDrv)
|
||||
|
||||
proc trunc(s: string, limit: int): string =
|
||||
if s.len <= limit:
|
||||
s
|
||||
else:
|
||||
s[0..(limit-4)] & "..."
|
||||
|
||||
proc display(msg: string, drvs: seq[Derivation]) =
|
||||
echo fmt"{msg}: [bold cyan]{drvs.len()}[/]".bb
|
||||
let maxLen = min(max drvs.mapIt(it.name.len), 40)
|
||||
for drv in drvs:
|
||||
echo " ", drv.name.trunc(maxLen).alignLeft(maxLen), " ", drv.hash.bb("faint")
|
||||
|
||||
proc display(output: DryRunOutput) =
|
||||
if isDebug():
|
||||
display("to fetch", output.toFetch)
|
||||
else:
|
||||
echo fmt"to fetch: [bold cyan]{output.toFetch.len()}[/]".bb
|
||||
display("to build", output.toBuild)
|
||||
|
||||
proc toBuildNixosConfiguration(): seq[string] =
|
||||
var cmd = nixCommand("build")
|
||||
cmd.addArg "--dry-run"
|
||||
cmd.addArgs nixosConfigAttrs()
|
||||
let (_, err) = runCmdCaptWithSpinner(cmd, "running dry run build for: " & getHosts().join(" "))
|
||||
let output = parseDryRunOutput err
|
||||
return output.toBuild.mapIt(it.storePath)
|
||||
|
||||
type
|
||||
NixDerivation = object
|
||||
inputDrvs: Table[string, JsonNode]
|
||||
name: string
|
||||
|
||||
proc evaluateDerivations(drvs: seq[string]): Table[string,NixDerivation] =
|
||||
var cmd = "nix derivation show -r"
|
||||
cmd.addArgs drvs
|
||||
let (output, _) =
|
||||
runCmdCaptWithSpinner(cmd, "evaluating derivations")
|
||||
output.fromJson(Table[string,NixDerivation])
|
||||
|
||||
|
||||
# TODO: replace asserts in this proc
|
||||
proc findSystemPaths(drvs: Table[string, NixDerivation]): seq[string] =
|
||||
let hosts = getHosts()
|
||||
let systemDrvs = collect(
|
||||
for k in drvs.keys():
|
||||
if k.split("-",1)[1].startswith("nixos-system-"): k
|
||||
)
|
||||
|
||||
assert len(hosts) == len(systemDrvs)
|
||||
for name in systemDrvs:
|
||||
for drv in drvs[name].inputDrvs.keys():
|
||||
if drv.endsWith("system-path.drv"):
|
||||
result.add drv
|
||||
|
||||
assert len(hosts) == len(result)
|
||||
|
||||
func isIgnored(drv: string): bool =
|
||||
const ignoredPackages = (slurp "ignored.txt").splitLines()
|
||||
drv.split("-", 1)[1].replace(".drv","") in ignoredPackages
|
||||
|
||||
proc systemPathDrvsToBuild(): seq[string] =
|
||||
let toBuild = toBuildNixosConfiguration()
|
||||
let drvs = evaluateDerivations(nixosConfigAttrs())
|
||||
let systemPaths = findSystemPaths(drvs)
|
||||
var inputDrvs: seq[string]
|
||||
for p in systemPaths:
|
||||
inputDrvs &= drvs[p].inputDrvs.keys().toSeq()
|
||||
result = collect(
|
||||
for drv in inputDrvs:
|
||||
if (drv in toBuild) and (not drv.isIgnored()):
|
||||
drv & "^*"
|
||||
)
|
||||
|
||||
func splitDrv(drv: string): tuple[name, hash:string] =
|
||||
let s = drv.split("-", 1)
|
||||
(s[1].replace(".drv^*",""),s[0].split("/")[^1])
|
||||
|
||||
proc writeDervationsToStepSummary(drvs: seq[string]) =
|
||||
let rows = collect(
|
||||
for drv in drvs:
|
||||
let (name,hash) = splitDrv(drv)
|
||||
fmt"| {name} | {hash} |"
|
||||
)
|
||||
let summaryFilePath = getEnv("GITHUB_STEP_SUMMARY")
|
||||
if summaryFilePath == "":
|
||||
fatal "no github step summary found"
|
||||
quit QuitFailure
|
||||
let output = open(summaryFilePath,fmAppend)
|
||||
output.writeLine("| derivation | hash |\n|---|---|")
|
||||
output.writeLine(rows.join("\n"))
|
||||
|
||||
proc nixBuild*(minimal: bool, rest: seq[string]) =
|
||||
var cmd = nixCommand("build")
|
||||
if minimal:
|
||||
debug "populating args with derivations not built/cached"
|
||||
let drvs = systemPathDrvsToBuild()
|
||||
if drvs.len == 0:
|
||||
info "nothing to build"
|
||||
quit "exiting...", QuitSuccess
|
||||
cmd.addArgs drvs
|
||||
cmd.addArg "--no-link"
|
||||
if isCi():
|
||||
writeDervationsToStepSummary drvs
|
||||
cmd.addArgs rest
|
||||
quitWithCmd cmd
|
||||
|
||||
|
||||
proc nixBuildHostDry*(minimal: bool, rest: seq[string]) =
|
||||
var cmd = nixCommand("build")
|
||||
if minimal:
|
||||
debug "populating args with derivations not built/cached"
|
||||
let drvs = systemPathDrvsToBuild()
|
||||
if drvs.len == 0:
|
||||
info "nothing to build"
|
||||
quit "exiting...", QuitSuccess
|
||||
cmd.addArgs drvs
|
||||
cmd.addArg "--no-link"
|
||||
if isCi():
|
||||
writeDervationsToStepSummary drvs
|
||||
else:
|
||||
cmd.addArgs nixosConfigAttrs()
|
||||
cmd.addArg "--dry-run"
|
||||
cmd.addArgs rest
|
||||
let (_, err) =
|
||||
runCmdCaptWithSpinner(cmd, "evaluating derivation for: " & getHosts().join(" "))
|
||||
let output = parseDryRunOutput err
|
||||
display output
|
||||
|
||||
|
64
pkgs/oizys-nim/src/oizys/overlay.nim
Normal file
64
pkgs/oizys-nim/src/oizys/overlay.nim
Normal file
|
@ -0,0 +1,64 @@
|
|||
import std/macros
|
||||
|
||||
type
|
||||
OverlayKind = enum
|
||||
oPre
|
||||
oPost
|
||||
OverlayProc = object
|
||||
node: NimNode
|
||||
kind: OverlayKind
|
||||
|
||||
|
||||
proc applyOverlay(child: NimNode, overlayProc: OverlayProc) =
|
||||
let node = overlayProc.node
|
||||
for p in node.params:
|
||||
if p.kind == nnkIdentDefs:
|
||||
child.params.add copyNimTree(p)
|
||||
case overlayProc.kind:
|
||||
of oPre:
|
||||
let startIdx = if child.body[0].kind == nnkCommentStmt: 1 else: 0
|
||||
for i in countdown(node.body.len()-1, 0):
|
||||
child.body.insert(startIdx, copyNimTree(node.body[i]))
|
||||
of oPost:
|
||||
for stmt in node.body.children():
|
||||
child.body.add copyNimTree(stmt)
|
||||
|
||||
|
||||
macro overlay*(x: untyped): untyped =
|
||||
##[
|
||||
apply pre and post operations to procs:
|
||||
```nim
|
||||
overlay:
|
||||
proc pre(a: bool) =
|
||||
echo "before"
|
||||
proc post(c: bool) =
|
||||
echo "after"
|
||||
proc mine(b: bool) =
|
||||
echo "inside mine"
|
||||
```
|
||||
would result in:
|
||||
```nim
|
||||
proc pre(a: bool; b: bool; c: bool) =
|
||||
echo "before"
|
||||
echo "inside mine"
|
||||
echo "after"
|
||||
```
|
||||
]##
|
||||
result = newStmtList()
|
||||
var overlays: seq[OverlayProc]
|
||||
for child in x.children():
|
||||
case child.kind:
|
||||
of nnkProcDef:
|
||||
case ($child.name):
|
||||
of "pre": overlays.add OverlayProc(node: child, kind: oPre)
|
||||
of "post": overlays.add OverlayProc(node: child, kind: oPost)
|
||||
else: result.add child
|
||||
else: result.add child
|
||||
|
||||
if overlays.len == 0:
|
||||
error "failed to create overlays: didn't find proc pre() or proc post()"
|
||||
|
||||
for i, child in result.pairs():
|
||||
if child.kind == nnkProcDef:
|
||||
for overlay in overlays:
|
||||
applyOverlay(child, overlay)
|
189
pkgs/oizys-nim/src/oizys/spin.nim
Normal file
189
pkgs/oizys-nim/src/oizys/spin.nim
Normal file
|
@ -0,0 +1,189 @@
|
|||
import std/[os, locks, sequtils, terminal]
|
||||
|
||||
# https://github.com/molnarmark/colorize
|
||||
proc reset(): string = "\e[0m"
|
||||
|
||||
# foreground colors
|
||||
proc fgRed*(s: string): string = "\e[31m" & s & reset()
|
||||
proc fgBlack*(s: string): string = "\e[30m" & s & reset()
|
||||
proc fgGreen*(s: string): string = "\e[32m" & s & reset()
|
||||
proc fgYellow*(s: string): string = "\e[33m" & s & reset()
|
||||
proc fgBlue*(s: string): string = "\e[34m" & s & reset()
|
||||
proc fgMagenta*(s: string): string = "\e[35m" & s & reset()
|
||||
proc fgCyan*(s: string): string = "\e[36m" & s & reset()
|
||||
proc fgLightGray*(s: string): string = "\e[37m" & s & reset()
|
||||
proc fgDarkGray*(s: string): string = "\e[90m" & s & reset()
|
||||
proc fgLightRed*(s: string): string = "\e[91m" & s & reset()
|
||||
proc fgLightGreen*(s: string): string = "\e[92m" & s & reset()
|
||||
proc fgLightYellow*(s: string): string = "\e[93m" & s & reset()
|
||||
proc fgLightBlue*(s: string): string = "\e[94m" & s & reset()
|
||||
proc fgLightMagenta*(s: string): string = "\e[95m" & s & reset()
|
||||
proc fgLightCyan*(s: string): string = "\e[96m" & s & reset()
|
||||
proc fgWhite*(s: string): string = "\e[97m" & s & reset()
|
||||
|
||||
# background colors
|
||||
proc bgBlack*(s: string): string = "\e[40m" & s & reset()
|
||||
proc bgRed*(s: string): string = "\e[41m" & s & reset()
|
||||
proc bgGreen*(s: string): string = "\e[42m" & s & reset()
|
||||
proc bgYellow*(s: string): string = "\e[43m" & s & reset()
|
||||
proc bgBlue*(s: string): string = "\e[44m" & s & reset()
|
||||
proc bgMagenta*(s: string): string = "\e[45m" & s & reset()
|
||||
proc bgCyan*(s: string): string = "\e[46m" & s & reset()
|
||||
proc bgLightGray*(s: string): string = "\e[47m" & s & reset()
|
||||
proc bgDarkGray*(s: string): string = "\e[100m" & s & reset()
|
||||
proc bgLightRed*(s: string): string = "\e[101m" & s & reset()
|
||||
proc bgLightGreen*(s: string): string = "\e[102m" & s & reset()
|
||||
proc bgLightYellow*(s: string): string = "\e[103m" & s & reset()
|
||||
proc bgLightBlue*(s: string): string = "\e[104m" & s & reset()
|
||||
proc bgLightMagenta*(s: string): string = "\e[105m" & s & reset()
|
||||
proc bgLightCyan*(s: string): string = "\e[106m" & s & reset()
|
||||
proc bgWhite*(s: string): string = "\e[107m" & s & reset()
|
||||
|
||||
# formatting functions
|
||||
proc bold*(s: string): string = "\e[1m" & s & reset()
|
||||
proc underline*(s: string): string = "\e[4m" & s & reset()
|
||||
proc hidden*(s: string): string = "\e[8m" & s & reset()
|
||||
proc invert*(s: string): string = "\e[7m" & s & reset()
|
||||
|
||||
type
|
||||
SpinnerKind* = enum
|
||||
Dots
|
||||
Spinner* = object
|
||||
interval*: int
|
||||
frames*: seq[string]
|
||||
|
||||
proc makeSpinner*(interval: int, frames: seq[string]): Spinner =
|
||||
Spinner(interval: interval, frames: frames)
|
||||
|
||||
const Spinners*: array[SpinnerKind, Spinner] = [
|
||||
# Dots
|
||||
Spinner(interval: 80, frames: @["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]),
|
||||
]
|
||||
|
||||
|
||||
type
|
||||
Spinny = ref object
|
||||
t: Thread[Spinny]
|
||||
lock: Lock
|
||||
text: string
|
||||
running: bool
|
||||
frames: seq[string]
|
||||
frame: string
|
||||
interval: int
|
||||
customSymbol: bool
|
||||
|
||||
EventKind = enum
|
||||
Stop, StopSuccess, StopError,
|
||||
SymbolChange, TextChange,
|
||||
|
||||
SpinnyEvent = object
|
||||
kind: EventKind
|
||||
payload: string
|
||||
|
||||
var spinnyChannel: Channel[SpinnyEvent]
|
||||
|
||||
proc newSpinny*(text: string, s: Spinner): Spinny =
|
||||
Spinny(
|
||||
text: text,
|
||||
running: true,
|
||||
frames: s.frames,
|
||||
customSymbol: false,
|
||||
interval: s.interval
|
||||
)
|
||||
|
||||
proc newSpinny*(text: string, spinType: SpinnerKind): Spinny =
|
||||
newSpinny(text, Spinners[spinType])
|
||||
|
||||
proc setSymbolColor*(spinny: Spinny, color: proc(x: string): string) =
|
||||
spinny.frames = mapIt(spinny.frames, color(it))
|
||||
|
||||
proc setSymbol*(spinny: Spinny, symbol: string) =
|
||||
spinnyChannel.send(SpinnyEvent(kind: SymbolChange, payload: symbol))
|
||||
|
||||
proc setText*(spinny: Spinny, text: string) =
|
||||
spinnyChannel.send(SpinnyEvent(kind: TextChange, payload: text))
|
||||
|
||||
proc handleEvent(spinny: Spinny, eventData: SpinnyEvent): bool =
|
||||
result = true
|
||||
case eventData.kind
|
||||
of Stop:
|
||||
result = false
|
||||
of SymbolChange:
|
||||
spinny.customSymbol = true
|
||||
spinny.frame = eventData.payload
|
||||
of TextChange:
|
||||
spinny.text = eventData.payload
|
||||
of StopSuccess:
|
||||
spinny.customSymbol = true
|
||||
spinny.frame = "✔".bold.fgGreen
|
||||
spinny.text = eventData.payload.bold.fgGreen
|
||||
of StopError:
|
||||
spinny.customSymbol = true
|
||||
spinny.frame = "✖".bold.fgRed
|
||||
spinny.text = eventData.payload.bold.fgRed
|
||||
|
||||
proc spinnyLoop(spinny: Spinny) {.thread.} =
|
||||
var frameCounter = 0
|
||||
|
||||
while spinny.running:
|
||||
let data = spinnyChannel.tryRecv()
|
||||
if data.dataAvailable:
|
||||
# If we received a Stop event
|
||||
if not spinny.handleEvent(data.msg):
|
||||
spinnyChannel.close()
|
||||
# This is required so we can reopen the same channel more than once
|
||||
# See https://github.com/nim-lang/Nim/issues/6369
|
||||
spinnyChannel = default(typeof(spinnyChannel))
|
||||
# TODO: Do we need spinny.running at all?
|
||||
spinny.running = false
|
||||
break
|
||||
|
||||
stdout.flushFile()
|
||||
if not spinny.customSymbol:
|
||||
spinny.frame = spinny.frames[frameCounter]
|
||||
|
||||
withLock spinny.lock:
|
||||
eraseLine()
|
||||
stdout.write(spinny.frame & " " & spinny.text)
|
||||
stdout.flushFile()
|
||||
|
||||
sleep(spinny.interval)
|
||||
|
||||
if frameCounter >= spinny.frames.len - 1:
|
||||
frameCounter = 0
|
||||
else:
|
||||
frameCounter += 1
|
||||
|
||||
proc start*(spinny: Spinny) =
|
||||
initLock(spinny.lock)
|
||||
spinnyChannel.open()
|
||||
createThread(spinny.t, spinnyLoop, spinny)
|
||||
|
||||
proc stop(spinny: Spinny, kind: EventKind, payload = "") =
|
||||
spinnyChannel.send(SpinnyEvent(kind: kind, payload: payload))
|
||||
spinnyChannel.send(SpinnyEvent(kind: Stop))
|
||||
joinThread(spinny.t)
|
||||
eraseLine stdout
|
||||
flushFile stdout
|
||||
|
||||
|
||||
proc stop*(spinny: Spinny) =
|
||||
spinny.stop(Stop)
|
||||
|
||||
proc success*(spinny: Spinny, msg: string) =
|
||||
spinny.stop(StopSuccess, msg)
|
||||
|
||||
proc error*(spinny: Spinny, msg: string) =
|
||||
spinny.stop(StopError, msg)
|
||||
|
||||
template withSpinner*(msg: string = "", body: untyped): untyped =
|
||||
var spinner {.inject.} = newSpinny(msg, Dots)
|
||||
spinner.setSymbolColor(fgBlue)
|
||||
start spinner
|
||||
body
|
||||
stop spinner
|
||||
|
||||
template withSpinner*(body: untyped): untyped =
|
||||
withSpinner("", body)
|
||||
|
||||
|
8
pkgs/oizys-nim/todo.md
Normal file
8
pkgs/oizys-nim/todo.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
# oizys-nim todo's
|
||||
|
||||
- [x] nix commands including dry runs
|
||||
- [ ] gh api commands
|
||||
- [ ] ci <- start with the easier one
|
||||
- [ ] update
|
||||
|
||||
<!-- generated with <3 by daylinmorgan/todo -->
|
Loading…
Reference in a new issue