Initial commit
This commit is contained in:
commit
bdc8ae889d
1
.envrc
Normal file
1
.envrc
Normal file
@ -0,0 +1 @@
|
|||||||
|
use flake
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
.direnv/
|
54
README.md
Normal file
54
README.md
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
# nixq
|
||||||
|
|
||||||
|
Like `jq`, `yq` and `htmlq`, but for nix :snowflake::snowflake::snowflake:
|
||||||
|
Basically just a shell interface for [nix-select](https://git.clan.lol/clan/nix-select/).
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
$ nixq . 'packages.{x86_64-linux,aarch64-linux}.*' --yaml
|
||||||
|
aarch64-linux:
|
||||||
|
default: /nix/store/6nrvhk2viafsy84sg29jrzkf4xdap529-nixq
|
||||||
|
nixq: /nix/store/6nrvhk2viafsy84sg29jrzkf4xdap529-nixq
|
||||||
|
nixq-lix: /nix/store/2m7z3kjf76mqaldh40r3zfg39vfbrg93-nixq
|
||||||
|
nixq-nix: /nix/store/q8jqlz75hs6hlpzsbjhr994w2ffzyply-nixq
|
||||||
|
x86_64-linux:
|
||||||
|
default: /nix/store/fx8n5krq20y6z1p97iv7ra77zzq0lvf6-nixq
|
||||||
|
nixq: /nix/store/fx8n5krq20y6z1p97iv7ra77zzq0lvf6-nixq
|
||||||
|
nixq-lix: /nix/store/a2znjf47hhfd2749ff0lwy7ljz3nsz43-nixq
|
||||||
|
nixq-nix: /nix/store/046dkmci916zgy1690pqvcb0wijrij98-nixq
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ nixq -f '<nixpkgs>' 'pkgs.{spade,sus-compiler,pagefind}.meta.maintainers.*.github'
|
||||||
|
{
|
||||||
|
"pagefind": [
|
||||||
|
"pbsds"
|
||||||
|
],
|
||||||
|
"spade": [
|
||||||
|
"pbsds"
|
||||||
|
],
|
||||||
|
"sus-compiler": [
|
||||||
|
"pbsds"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ nixq flake:nixpkgs 'legacyPackages.x86_64-linux.{disko,pagefind}.meta.available'
|
||||||
|
{
|
||||||
|
"disko": true,
|
||||||
|
"pagefind": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
$ nixq github:NixOS/nixpkgs/nixos-unstable 'legacyPackages.x86_64-linux.python313Packages' --keys | jq .[:5]
|
||||||
|
[
|
||||||
|
"acompressor",
|
||||||
|
"autocrop",
|
||||||
|
"autodeint",
|
||||||
|
"autoload",
|
||||||
|
"autosub",
|
||||||
|
]
|
||||||
|
```
|
59
flake.lock
generated
Normal file
59
flake.lock
generated
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nix-select": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1739677887,
|
||||||
|
"narHash": "sha256-VIGgoWnzXzlwRHfJt3YRNQsRyX1I1dPdVm61hnyKJZo=",
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"rev": "d2aa1f72b6e1ac318f4125d6eebee256bbeb05a3",
|
||||||
|
"revCount": 11,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.clan.lol/clan/nix-select.git"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.clan.lol/clan/nix-select.git"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1739866667,
|
||||||
|
"narHash": "sha256-EO1ygNKZlsAC9avfcwHkKGMsmipUk1Uc0TbrEZpkn64=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "73cf49b8ad837ade2de76f87eb53fc85ed5d4680",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1739667890,
|
||||||
|
"narHash": "sha256-7QtSNdCEbYG1v+ZVrFWhBkhlo2GWehPffWC0BP1VZSo=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"rev": "9b883b6d4d3bd580734ddb4b5bfde8ebffd26559",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nix-select": "nix-select",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
44
flake.nix
Normal file
44
flake.nix
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
inputs.nix-select.url = "git+https://git.clan.lol/clan/nix-select.git";
|
||||||
|
inputs.nixpkgs-lib.url = "github:nix-community/nixpkgs.lib";
|
||||||
|
|
||||||
|
outputs = inputs:
|
||||||
|
let
|
||||||
|
forAllSystems = f: inputs.nixpkgs.lib.genAttrs inputs.nixpkgs.lib.systems.flakeExposed (system: f rec {
|
||||||
|
inherit system;
|
||||||
|
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||||
|
inherit (pkgs) lib;
|
||||||
|
});
|
||||||
|
in {
|
||||||
|
inherit inputs;
|
||||||
|
|
||||||
|
overlays.default = prev: {
|
||||||
|
nixq = prev.callPackage ./package.nix { inherit (inputs) nix-select nixpkgs-lib; };
|
||||||
|
};
|
||||||
|
|
||||||
|
packages = forAllSystems ({ pkgs, ... }: rec {
|
||||||
|
default = nixq;
|
||||||
|
nixq = pkgs.callPackage ./package.nix { inherit (inputs) nix-select nixpkgs-lib; };
|
||||||
|
nixq-nix = pkgs.callPackage ./package.nix { inherit (inputs) nix-select nixpkgs-lib; extraRuntimeDeps = [ pkgs.nix ]; };
|
||||||
|
nixq-lix = pkgs.callPackage ./package.nix { inherit (inputs) nix-select nixpkgs-lib; extraRuntimeDeps = [ pkgs.lix ]; };
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = forAllSystems ({ lib, pkgs, ... }: rec {
|
||||||
|
default = pkgs.mkShellNoCC {
|
||||||
|
packages = builtins.attrValues {
|
||||||
|
inherit (pkgs)
|
||||||
|
lix
|
||||||
|
jq
|
||||||
|
yq
|
||||||
|
bat
|
||||||
|
;
|
||||||
|
};
|
||||||
|
env.NIXQ_NIX_SELECT_PATH = inputs.nix-select.outPath;
|
||||||
|
env.NIXQ_NIXPKGS_LIB_PATH = inputs.nixpkgs.outPath;
|
||||||
|
env.UV_PYTHON_DOWNLOADS = "never";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
219
nixq.sh
Executable file
219
nixq.sh
Executable file
@ -0,0 +1,219 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -z "${NIXQ_NIX_SELECT_PATH:-}" ]; then
|
||||||
|
>&2 echo "nix-select not found! Please set NIXQ_NIX_SELECT_PATH!"
|
||||||
|
fi
|
||||||
|
if [ -z "${NIXQ_NIXPKGS_LIB_PATH:-}" ]; then
|
||||||
|
>&2 echo "nixpkgs-lib not found! Please set NIXQ_NIXPKGS_LIB_PATH!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
die() {
|
||||||
|
>&2 echo "ERROR:" "$@"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
print_help() {
|
||||||
|
echo "nixq: A nix tool to query elements/lists/attrs from nested list/attrs,"
|
||||||
|
echo " using the nix-select library: https://git.clan.lol/clan/nix-select/"
|
||||||
|
echo ""
|
||||||
|
echo "Usage:"
|
||||||
|
echo " $0 [-f] <file> [-q] <query> [-k] [-v] [-D] [-y] [--apply <expr>] ..."
|
||||||
|
echo ""
|
||||||
|
echo " -f, --file <file> Load a file, typically named default.nix"
|
||||||
|
echo " -f, --file <file> Load a file, typically named default.nix"
|
||||||
|
echo " [--flake] <file> Load a flake, does not support attributes after '#'"
|
||||||
|
echo " [-q, --query] <query> The select query to perform"
|
||||||
|
echo " -k, --keys, --names Will '--apply builtins.attrName'"
|
||||||
|
echo " -v, --values Will '--apply builtins.attrValue'"
|
||||||
|
echo " -t, --try-values Will tryEval the attribute set values"
|
||||||
|
# echo " -D, --rename-outPath Rename \"outPath\" keys to \"outPath'\""
|
||||||
|
echo " -y, --yaml Output as yaml"
|
||||||
|
echo " --raw Output raw"
|
||||||
|
echo " --apply <expr> Apply custom expression with nixpkgs 'lib' in scope, can be used multiple times"
|
||||||
|
echo " ... Passed on to 'nix eval'"
|
||||||
|
# PAGER="" nix --extra-experimental-features "nix-command flakes" eval --help
|
||||||
|
}
|
||||||
|
|
||||||
|
nix_str() {
|
||||||
|
local out="$1"
|
||||||
|
out="${out/\"/\\\"}"
|
||||||
|
out="${out/\$/\\\$}"
|
||||||
|
printf '"%s"\n' "$out"
|
||||||
|
}
|
||||||
|
|
||||||
|
lib_expr="let lib = import $NIXQ_NIXPKGS_LIB_PATH/lib; in"
|
||||||
|
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
print_help
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
file_expr=""
|
||||||
|
query=""
|
||||||
|
output_raw=false
|
||||||
|
output_yaml=false
|
||||||
|
|
||||||
|
set_file_expr_normal() {
|
||||||
|
if [[ -z "${1:-}" ]]; then
|
||||||
|
die "No file provided"
|
||||||
|
fi
|
||||||
|
local path
|
||||||
|
if [[ $1 =~ \<[a-zA-Z0-9_-]+\> ]]; then
|
||||||
|
path="$1"
|
||||||
|
else
|
||||||
|
path="$(nix_str "$(realpath "$1")")"
|
||||||
|
fi
|
||||||
|
file_expr="(let f = import $path; in if builtins.isFunction f then f {} else f)"
|
||||||
|
}
|
||||||
|
set_file_expr_flake() {
|
||||||
|
if [[ -z "${1:-}" ]]; then
|
||||||
|
die "No flake provided"
|
||||||
|
fi
|
||||||
|
file_expr="(builtins.getFlake $(nix_str "$1"))"
|
||||||
|
}
|
||||||
|
|
||||||
|
posargs=()
|
||||||
|
filtered_args=()
|
||||||
|
|
||||||
|
while [[ "$#" -gt 0 ]]; do
|
||||||
|
arg="$1"
|
||||||
|
case "$1" in
|
||||||
|
-[^-][^-]*)
|
||||||
|
shift
|
||||||
|
# shellcheck disable=SC2046
|
||||||
|
set -- $(echo "${arg:1:99999}" | sed -e 's/\(.\)/ -\1/g') "$@"
|
||||||
|
;;
|
||||||
|
--help)
|
||||||
|
print_help
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
-f | --file)
|
||||||
|
shift
|
||||||
|
set_file_expr_normal "$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--flake)
|
||||||
|
shift
|
||||||
|
set_file_expr_flake "$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-q | --query)
|
||||||
|
shift
|
||||||
|
query="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-y | --yaml)
|
||||||
|
output_yaml=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--raw)
|
||||||
|
output_raw=true
|
||||||
|
filtered_args+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-k | --keys | --names)
|
||||||
|
filtered_args+=("--apply" "builtins.attrNames")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-v | --values)
|
||||||
|
filtered_args+=("--apply" "builtins.attrValues")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
#-D | --rename-out-path)
|
||||||
|
# filtered_args+=("--apply" "$lib_expr lib.mapAttrs' (k: v: { name= { outPath=\"outPath'\"; }.\${k} or k; value = v; })");
|
||||||
|
# shift
|
||||||
|
# ;;
|
||||||
|
-t | --try-values)
|
||||||
|
# TODO: figure out how to force the full value
|
||||||
|
# filtered_args+=("--apply" "builtins.mapAttrs (k: v: if (builtins.tryEval (builtins.toJSON v == \"\")).success then v else null)");
|
||||||
|
filtered_args+=("--apply" "builtins.mapAttrs (k: v: if (builtins.tryEval (v == null)).success then v else null)")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
#-d | --max-depth)
|
||||||
|
# filtered_args+=("--apply" "");
|
||||||
|
# shift
|
||||||
|
# ;;
|
||||||
|
--apply)
|
||||||
|
filtered_args+=("$1")
|
||||||
|
shift
|
||||||
|
filtered_args+=("$lib_expr $1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
[^-]*)
|
||||||
|
posargs+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
filtered_args+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
for arg in "${posargs[@]}"; do
|
||||||
|
if [[ -z "$file_expr" ]]; then
|
||||||
|
set_file_expr_flake "$arg"
|
||||||
|
elif [[ -z "$query" ]]; then
|
||||||
|
query="$arg"
|
||||||
|
else
|
||||||
|
die "Too many positional arguments!"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z "$file_expr" ]]; then
|
||||||
|
die "No file provided"
|
||||||
|
fi
|
||||||
|
if [[ -z "$query" ]]; then
|
||||||
|
die "No query provided"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! $output_raw; then
|
||||||
|
# TODO: figure out why this is slow
|
||||||
|
#filtered_args+=(
|
||||||
|
# "--apply"
|
||||||
|
# '
|
||||||
|
# let
|
||||||
|
# mapTree = x:
|
||||||
|
# if !(builtins.tryEval (x==null)).success then
|
||||||
|
# null
|
||||||
|
# else if builtins.isAttrs x then
|
||||||
|
# builtins.mapAttrs (k: v: mapTree v) x
|
||||||
|
# else if builtins.isList x then
|
||||||
|
# builtins.map mapTree x
|
||||||
|
# else if builtins.isFunction x then
|
||||||
|
# "<lambda>"
|
||||||
|
# else
|
||||||
|
# x;
|
||||||
|
# in mapTree
|
||||||
|
# '
|
||||||
|
#);
|
||||||
|
filtered_args+=(--json)
|
||||||
|
fi
|
||||||
|
|
||||||
|
nix_cmd=(
|
||||||
|
nix
|
||||||
|
--extra-experimental-features "nix-command flakes"
|
||||||
|
eval --impure
|
||||||
|
--expr "(import $NIXQ_NIX_SELECT_PATH/select.nix).select $(nix_str "$query") $file_expr"
|
||||||
|
"${filtered_args[@]}"
|
||||||
|
)
|
||||||
|
|
||||||
|
output="$(
|
||||||
|
# set -x
|
||||||
|
"${nix_cmd[@]}"
|
||||||
|
)"
|
||||||
|
|
||||||
|
if $output_raw; then
|
||||||
|
cat <<<"$output"
|
||||||
|
elif $output_yaml; then
|
||||||
|
if [[ -t 1 ]] && >/dev/null command -v bat; then
|
||||||
|
yq . -y <<<"$output" | bat --language yaml --style plain --paging never
|
||||||
|
else
|
||||||
|
yq . -y <<<"$output"
|
||||||
|
fi
|
||||||
|
elif [[ -t 1 ]] && >/dev/null command -v jq; then
|
||||||
|
jq . <<<"$output"
|
||||||
|
else
|
||||||
|
cat <<<"$output"
|
||||||
|
fi
|
31
package.nix
Normal file
31
package.nix
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
writeShellApplication,
|
||||||
|
coreutils,
|
||||||
|
gnused,
|
||||||
|
jq,
|
||||||
|
yq,
|
||||||
|
bat,
|
||||||
|
|
||||||
|
nix-select ? "",
|
||||||
|
nixpkgs-lib ? "",
|
||||||
|
extraRuntimeDeps ? [ ],
|
||||||
|
}:
|
||||||
|
writeShellApplication {
|
||||||
|
name = "nixq";
|
||||||
|
|
||||||
|
text = builtins.readFile ./nixq.sh;
|
||||||
|
extraShellCheckFlags = [ "--severity" "info" ];
|
||||||
|
|
||||||
|
runtimeInputs = [
|
||||||
|
coreutils
|
||||||
|
gnused
|
||||||
|
jq
|
||||||
|
yq
|
||||||
|
bat
|
||||||
|
] ++ extraRuntimeDeps;
|
||||||
|
|
||||||
|
runtimeEnv = {
|
||||||
|
NIXQ_NIX_SELECT_PATH = nix-select;
|
||||||
|
NIXQ_NIXPKGS_LIB_PATH = nixpkgs-lib;
|
||||||
|
};
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user