feat: restructure dev-components/dev-registry with direnv
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
pkgs.git
|
pkgs.git
|
||||||
packages.git-linearize
|
packages.git-linearize
|
||||||
packages.ggman
|
packages.ggman
|
||||||
pkgs.go
|
|
||||||
pkgs.python3
|
pkgs.python3
|
||||||
pkgs.mdbook
|
pkgs.mdbook
|
||||||
pkgs.marksman
|
pkgs.marksman
|
||||||
@@ -22,9 +21,5 @@
|
|||||||
pkgs.osc
|
pkgs.osc
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.direnv = {
|
|
||||||
enable = true;
|
|
||||||
nix-direnv.enable = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,14 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
home = _: {
|
||||||
|
programs.direnv = {
|
||||||
|
enable = true;
|
||||||
|
nix-direnv.enable = true;
|
||||||
|
config.global.hide_env_diff = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
xdg.configFile."direnv/lib/use_dev.sh".source = ./use_dev.sh;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
80
features/direnv/use_dev.sh
Normal file
80
features/direnv/use_dev.sh
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
# shellcheck shell=bash
|
||||||
|
# composable nix devshell from matej.nix
|
||||||
|
# usage in .envrc: use dev uv_14 pg_18
|
||||||
|
|
||||||
|
# generates a flake and delegates to use_flake at the calling scope
|
||||||
|
use_dev() {
|
||||||
|
local nix_list=""
|
||||||
|
for c in "$@"; do
|
||||||
|
if [[ ! "$c" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]]; then
|
||||||
|
log_error "use_dev: invalid component name: $c"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
nix_list="$nix_list \"$c\""
|
||||||
|
done
|
||||||
|
|
||||||
|
local system
|
||||||
|
case "$(uname -s)-$(uname -m)" in
|
||||||
|
Linux-x86_64) system="x86_64-linux" ;;
|
||||||
|
Linux-aarch64) system="aarch64-linux" ;;
|
||||||
|
Darwin-x86_64) system="x86_64-darwin" ;;
|
||||||
|
Darwin-arm64) system="aarch64-darwin" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -z "$system" ]]; then
|
||||||
|
log_error "use_dev: unsupported platform: $(uname -s)-$(uname -m)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local dev_path nixpkgs_path registry_filter
|
||||||
|
# shellcheck disable=SC2016 # $id is a jq variable, not shell
|
||||||
|
registry_filter='.flakes[] | select(.from.id == $id) | .to.path'
|
||||||
|
|
||||||
|
local registry_file="${XDG_CONFIG_HOME:-$HOME/.config}/nix/registry.json"
|
||||||
|
if [[ ! -f "$registry_file" ]]; then
|
||||||
|
registry_file="/etc/nix/registry.json"
|
||||||
|
fi
|
||||||
|
|
||||||
|
dev_path="$(jq -re --arg id dev "$registry_filter" "$registry_file" 2>/dev/null)"
|
||||||
|
nixpkgs_path="$(jq -re --arg id nixpkgs "$registry_filter" "$registry_file" 2>/dev/null)"
|
||||||
|
|
||||||
|
if [[ -z "$dev_path" ]]; then
|
||||||
|
log_error "use_dev: 'dev' not found in nix registry"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ -z "$nixpkgs_path" ]]; then
|
||||||
|
log_error "use_dev: 'nixpkgs' not found in nix registry"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local components_hash project_hash cache_dir
|
||||||
|
components_hash="$(sha256sum "$dev_path/flake/dev-components.nix" 2>/dev/null | cut -c1-16)"
|
||||||
|
project_hash="$(echo "$PWD" | sha256sum | cut -c1-16)"
|
||||||
|
cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/dev-flakes/$project_hash"
|
||||||
|
mkdir -p "$cache_dir"
|
||||||
|
|
||||||
|
cat >"$cache_dir/flake.nix.tmp" <<DEVFLAKE
|
||||||
|
# dev-components: $components_hash
|
||||||
|
{
|
||||||
|
inputs.dev = { url = "path:${dev_path}"; flake = false; };
|
||||||
|
inputs.nixpkgs.url = "path:${nixpkgs_path}";
|
||||||
|
outputs = { dev, nixpkgs, ... }:
|
||||||
|
let
|
||||||
|
system = "${system}";
|
||||||
|
pkgs = nixpkgs.legacyPackages.\${system};
|
||||||
|
devLib = import "\${dev}/flake/dev-components.nix" { inherit pkgs; lib = nixpkgs.lib; };
|
||||||
|
in {
|
||||||
|
devShells.\${system}.default = devLib.mkComponentShell [$nix_list ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
DEVFLAKE
|
||||||
|
|
||||||
|
if ! cmp -s "$cache_dir/flake.nix.tmp" "$cache_dir/flake.nix" 2>/dev/null; then
|
||||||
|
mv "$cache_dir/flake.nix.tmp" "$cache_dir/flake.nix"
|
||||||
|
rm -f "$cache_dir/flake.lock"
|
||||||
|
else
|
||||||
|
rm "$cache_dir/flake.nix.tmp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
use_flake "path:$cache_dir"
|
||||||
|
}
|
||||||
111
flake/dev-components.nix
Normal file
111
flake/dev-components.nix
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# composable dev environment components
|
||||||
|
# imported by generated per-project flakes via use_dev
|
||||||
|
{ pkgs, lib }:
|
||||||
|
let
|
||||||
|
# libraries needed by python native extensions
|
||||||
|
pythonLibraries = [
|
||||||
|
pkgs.stdenv.cc.cc.lib
|
||||||
|
pkgs.zlib
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.curl
|
||||||
|
];
|
||||||
|
|
||||||
|
mkNode = nodejs: {
|
||||||
|
packages = [
|
||||||
|
nodejs
|
||||||
|
pkgs.corepack
|
||||||
|
];
|
||||||
|
env = {
|
||||||
|
COREPACK_ENABLE_STRICT = "0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkUv = python: {
|
||||||
|
packages = [
|
||||||
|
python
|
||||||
|
pkgs.uv
|
||||||
|
];
|
||||||
|
libraries = pythonLibraries;
|
||||||
|
env = {
|
||||||
|
UV_PYTHON_DOWNLOADS = "never";
|
||||||
|
UV_PYTHON_PREFERENCE = "only-system";
|
||||||
|
UV_PYTHON = "${python}/bin/python";
|
||||||
|
};
|
||||||
|
shellHook = ''
|
||||||
|
unset PYTHONPATH
|
||||||
|
export UV_PROJECT_ENVIRONMENT="''${XDG_DATA_HOME:-$HOME/.local/share}/dev-venvs/$(basename "$PWD")-$(echo "$PWD" | sha256sum | cut -c1-8)"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
components = {
|
||||||
|
uv_10 = mkUv pkgs.python310;
|
||||||
|
uv_11 = mkUv pkgs.python311;
|
||||||
|
uv_12 = mkUv pkgs.python312;
|
||||||
|
uv_13 = mkUv pkgs.python313;
|
||||||
|
uv_14 = mkUv pkgs.python314;
|
||||||
|
|
||||||
|
pg_15 = {
|
||||||
|
packages = [ pkgs.postgresql_15 ];
|
||||||
|
};
|
||||||
|
pg_16 = {
|
||||||
|
packages = [ pkgs.postgresql_16 ];
|
||||||
|
};
|
||||||
|
pg_17 = {
|
||||||
|
packages = [ pkgs.postgresql_17 ];
|
||||||
|
};
|
||||||
|
pg_18 = {
|
||||||
|
packages = [ pkgs.postgresql_18 ];
|
||||||
|
};
|
||||||
|
|
||||||
|
node_20 = mkNode pkgs.nodejs_20;
|
||||||
|
node_22 = mkNode pkgs.nodejs_22;
|
||||||
|
node_24 = mkNode pkgs.nodejs_24;
|
||||||
|
|
||||||
|
go = {
|
||||||
|
packages = [ pkgs.go ];
|
||||||
|
};
|
||||||
|
|
||||||
|
rust = {
|
||||||
|
packages = [
|
||||||
|
pkgs.rustc
|
||||||
|
pkgs.cargo
|
||||||
|
pkgs.rust-analyzer
|
||||||
|
pkgs.openssl
|
||||||
|
pkgs.pkg-config
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
cmake = {
|
||||||
|
packages = [
|
||||||
|
pkgs.cmake
|
||||||
|
pkgs.ninja
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# build a single mkShell from one or more component names
|
||||||
|
mkComponentShell =
|
||||||
|
names:
|
||||||
|
let
|
||||||
|
selected = map (n: components.${n}) names;
|
||||||
|
allPackages = lib.concatMap (c: c.packages or [ ]) selected;
|
||||||
|
allLibraries = lib.concatMap (c: c.libraries or [ ]) selected;
|
||||||
|
allHooks = lib.concatMapStrings (c: c.shellHook or "") selected;
|
||||||
|
allEnvs = lib.foldl' (acc: c: acc // (c.env or { })) { } selected;
|
||||||
|
libPath = lib.makeLibraryPath allLibraries;
|
||||||
|
in
|
||||||
|
pkgs.mkShell (
|
||||||
|
{
|
||||||
|
packages = allPackages;
|
||||||
|
shellHook =
|
||||||
|
(lib.optionalString (allLibraries != [ ]) ''
|
||||||
|
export LD_LIBRARY_PATH="${libPath}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||||
|
'')
|
||||||
|
+ allHooks;
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs (allEnvs != { }) { env = allEnvs; }
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit components mkComponentShell;
|
||||||
|
}
|
||||||
@@ -1,93 +1,6 @@
|
|||||||
_: {
|
_: {
|
||||||
perSystem =
|
perSystem =
|
||||||
{ pkgs, lib, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
|
||||||
# libraries needed by python native extensions
|
|
||||||
pythonLibraries = [
|
|
||||||
pkgs.stdenv.cc.cc.lib
|
|
||||||
pkgs.zlib
|
|
||||||
pkgs.openssl
|
|
||||||
pkgs.curl
|
|
||||||
];
|
|
||||||
|
|
||||||
mkUv = python: {
|
|
||||||
packages = [
|
|
||||||
python
|
|
||||||
pkgs.uv
|
|
||||||
];
|
|
||||||
libraries = pythonLibraries;
|
|
||||||
env = {
|
|
||||||
UV_PYTHON_DOWNLOADS = "never";
|
|
||||||
UV_PYTHON_PREFERENCE = "only-system";
|
|
||||||
UV_PYTHON = "${python}/bin/python";
|
|
||||||
};
|
|
||||||
shellHook = ''
|
|
||||||
unset PYTHONPATH
|
|
||||||
export UV_PROJECT_ENVIRONMENT="$HOME/.venvs/$(basename "$PWD")-$(echo "$PWD" | md5sum | cut -c1-8)"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# composable dev environment components
|
|
||||||
# each is exposed as its own devShell, layered via `use dev` in .envrc
|
|
||||||
components = {
|
|
||||||
uv_10 = mkUv pkgs.python310;
|
|
||||||
uv_11 = mkUv pkgs.python311;
|
|
||||||
uv_12 = mkUv pkgs.python312;
|
|
||||||
uv_13 = mkUv pkgs.python313;
|
|
||||||
uv_14 = mkUv pkgs.python314;
|
|
||||||
|
|
||||||
pg_15 = {
|
|
||||||
packages = [ pkgs.postgresql_15 ];
|
|
||||||
};
|
|
||||||
pg_16 = {
|
|
||||||
packages = [ pkgs.postgresql_16 ];
|
|
||||||
};
|
|
||||||
pg_17 = {
|
|
||||||
packages = [ pkgs.postgresql_17 ];
|
|
||||||
};
|
|
||||||
pg_18 = {
|
|
||||||
packages = [ pkgs.postgresql_18 ];
|
|
||||||
};
|
|
||||||
|
|
||||||
rust = {
|
|
||||||
packages = [
|
|
||||||
pkgs.rustc
|
|
||||||
pkgs.cargo
|
|
||||||
pkgs.rust-analyzer
|
|
||||||
pkgs.openssl
|
|
||||||
pkgs.pkg-config
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
cmake = {
|
|
||||||
packages = [
|
|
||||||
pkgs.cmake
|
|
||||||
pkgs.ninja
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
mkComponentShell =
|
|
||||||
component:
|
|
||||||
let
|
|
||||||
c = components.${component};
|
|
||||||
libraries = c.libraries or [ ];
|
|
||||||
libPath = lib.makeLibraryPath libraries;
|
|
||||||
in
|
|
||||||
pkgs.mkShell (
|
|
||||||
{
|
|
||||||
packages = c.packages or [ ];
|
|
||||||
shellHook =
|
|
||||||
(lib.optionalString (libraries != [ ]) ''
|
|
||||||
export LD_LIBRARY_PATH="${libPath}''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
|
||||||
'')
|
|
||||||
+ (c.shellHook or "");
|
|
||||||
}
|
|
||||||
// lib.optionalAttrs (c ? env) { inherit (c) env; }
|
|
||||||
);
|
|
||||||
|
|
||||||
componentShells = lib.mapAttrs (name: _: mkComponentShell name) components;
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
formatter = pkgs.nixfmt-tree;
|
formatter = pkgs.nixfmt-tree;
|
||||||
|
|
||||||
@@ -103,7 +16,6 @@ _: {
|
|||||||
pkgs.ssh-to-age
|
pkgs.ssh-to-age
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
// componentShells;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ in
|
|||||||
"yubikey"
|
"yubikey"
|
||||||
"calibre"
|
"calibre"
|
||||||
"steam"
|
"steam"
|
||||||
"dev-registry"
|
"direnv"
|
||||||
"neovim"
|
"neovim"
|
||||||
"dev"
|
"dev"
|
||||||
"claude"
|
"claude"
|
||||||
@@ -57,7 +57,7 @@ in
|
|||||||
"calibre"
|
"calibre"
|
||||||
"steam"
|
"steam"
|
||||||
"initrd-ssh"
|
"initrd-ssh"
|
||||||
"dev-registry"
|
"direnv"
|
||||||
"neovim"
|
"neovim"
|
||||||
"dev"
|
"dev"
|
||||||
"claude"
|
"claude"
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ let
|
|||||||
hasUser = user != null;
|
hasUser = user != null;
|
||||||
|
|
||||||
# path helpers
|
# path helpers
|
||||||
featurePath = f: ../features/${f}.nix;
|
featurePath =
|
||||||
|
f:
|
||||||
|
let
|
||||||
|
file = ../features/${f}.nix;
|
||||||
|
dir = ../features/${f};
|
||||||
|
in
|
||||||
|
if builtins.pathExists file then file else dir;
|
||||||
userFeaturePath = u: ../features/user-${u}.nix;
|
userFeaturePath = u: ../features/user-${u}.nix;
|
||||||
hostConfig = ../hosts/${name}/configuration.nix;
|
hostConfig = ../hosts/${name}/configuration.nix;
|
||||||
hostHWConfig = ../hosts/${name}/hardware-configuration.nix;
|
hostHWConfig = ../hosts/${name}/hardware-configuration.nix;
|
||||||
|
|||||||
Reference in New Issue
Block a user