mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-01-18 02:44:30 +00:00
nix-required-mounts: init
This commit is contained in:
parent
2bfe2058a3
commit
b422dafc89
@ -243,6 +243,7 @@
|
||||
./programs/nh.nix
|
||||
./programs/nix-index.nix
|
||||
./programs/nix-ld.nix
|
||||
./programs/nix-required-mounts.nix
|
||||
./programs/nm-applet.nix
|
||||
./programs/nncp.nix
|
||||
./programs/noisetorch.nix
|
||||
|
85
nixos/modules/programs/nix-required-mounts.nix
Normal file
85
nixos/modules/programs/nix-required-mounts.nix
Normal file
@ -0,0 +1,85 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
cfg = config.programs.nix-required-mounts;
|
||||
hook =
|
||||
pkgs.nix-required-mounts.override { inherit (cfg) allowedPatterns; };
|
||||
|
||||
patternType = with lib.types; submodule ({ config, name, ... }: {
|
||||
options.onFeatures = lib.mkOption {
|
||||
type = listOf str;
|
||||
description = "Which requiredSystemFeatures should trigger relaxation of the sandbox";
|
||||
default = [ name ];
|
||||
};
|
||||
options.paths = lib.mkOption {
|
||||
type = listOf path;
|
||||
description = "A list of glob patterns, indicating which paths to expose to the sandbox";
|
||||
};
|
||||
});
|
||||
|
||||
defaults = {
|
||||
opengl.onFeatures = [ "opengl" ];
|
||||
opengl.paths = [
|
||||
"/dev/video*"
|
||||
"/dev/dri"
|
||||
|
||||
pkgs.addOpenGLRunpath.driverLink
|
||||
# /run/opengl-driver/lib only contains symlinks
|
||||
config.hardware.opengl.package
|
||||
] ++ config.hardware.opengl.extraPackages;
|
||||
cuda.onFeatures = [ "cuda" ];
|
||||
cuda.paths = defaults.opengl.paths ++ [ "/dev/nvidia*" ];
|
||||
};
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ SomeoneSerge ];
|
||||
options.programs.nix-required-mounts = {
|
||||
enable = lib.mkEnableOption
|
||||
"Expose extra paths to the sandbox depending on derivations' requiredSystemFeatures";
|
||||
presets.opengl.enable = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = config.hardware.opengl.enable;
|
||||
defaultText = lib.literalExpression "hardware.opengl.enable";
|
||||
description = ''
|
||||
Expose OpenGL drivers to derivations marked with requiredSystemFeatures = [ "opengl" ]
|
||||
'';
|
||||
};
|
||||
presets.cuda.enable = lib.mkEnableOption ''
|
||||
Expose CUDA drivers and GPUs to derivations marked with requiredSystemFeatures = [ "cuda" ]
|
||||
'';
|
||||
allowedPatterns = with lib.types;
|
||||
lib.mkOption rec {
|
||||
type = attrsOf patternType;
|
||||
description = "The hook config, describing which paths to mount for which system features";
|
||||
default = { inherit (defaults) opengl; };
|
||||
defaultText = lib.literalExpression ''
|
||||
{
|
||||
opengl.paths = config.hardware.opengl.extraPackages ++ [
|
||||
config.hardware.opengl.package
|
||||
pkgs.addOpenGLRunpath.driverLink
|
||||
"/dev/video*"
|
||||
"/dev/dri"
|
||||
];
|
||||
}
|
||||
'';
|
||||
example.require-ipfs = [ "/ipfs" ];
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable (lib.mkMerge [
|
||||
{
|
||||
nix.settings.pre-build-hook = lib.getExe hook;
|
||||
}
|
||||
(lib.mkIf cfg.presets.opengl.enable {
|
||||
nix.settings.system-features = [ "opengl" ];
|
||||
programs.nix-required-mounts.allowedPatterns = {
|
||||
inherit (defaults) opengl;
|
||||
};
|
||||
})
|
||||
(lib.mkIf cfg.presets.cuda.enable {
|
||||
nix.settings.system-features = [ "cuda" ];
|
||||
programs.nix-required-mounts.allowedPatterns = {
|
||||
inherit (defaults) cuda;
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
118
pkgs/by-name/ni/nix-required-mounts/main.py
Normal file
118
pkgs/by-name/ni/nix-required-mounts/main.py
Normal file
@ -0,0 +1,118 @@
|
||||
import glob
|
||||
import json
|
||||
import subprocess
|
||||
import textwrap
|
||||
from argparse import ArgumentParser
|
||||
from itertools import chain
|
||||
from pathlib import Path
|
||||
from sys import stderr
|
||||
from typing import List
|
||||
|
||||
CONFIG = {
|
||||
"nixExe": "nix",
|
||||
"allowedPatterns": {},
|
||||
}
|
||||
|
||||
parser = ArgumentParser("pre-build-hook")
|
||||
parser.add_argument("derivation_path")
|
||||
parser.add_argument("sandbox_path", nargs="?")
|
||||
parser.add_argument(
|
||||
"--issue-command",
|
||||
choices=("always", "conditional", "never"),
|
||||
default="conditional",
|
||||
help="Whether to print extra-sandbox-paths",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--issue-stop",
|
||||
choices=("always", "conditional", "never"),
|
||||
default="conditional",
|
||||
help="Whether to print the final empty line",
|
||||
)
|
||||
|
||||
|
||||
def symlink_parents(p: Path) -> List[Path]:
|
||||
out = []
|
||||
while p.is_symlink() and p not in out:
|
||||
p = p.readlink()
|
||||
out.append(p)
|
||||
return out
|
||||
|
||||
|
||||
def entrypoint():
|
||||
if __name__ != "__main__":
|
||||
return
|
||||
|
||||
args = parser.parse_args()
|
||||
drv_path = args.derivation_path
|
||||
|
||||
if not Path(drv_path).exists():
|
||||
print(
|
||||
f"[E] {drv_path} doesn't exist."
|
||||
" This may happen with the remote builds."
|
||||
" Exiting the hook",
|
||||
file=stderr,
|
||||
)
|
||||
|
||||
proc = subprocess.run(
|
||||
[
|
||||
CONFIG["nixExe"],
|
||||
"show-derivation",
|
||||
drv_path,
|
||||
],
|
||||
capture_output=True,
|
||||
)
|
||||
try:
|
||||
drv = json.loads(proc.stdout)
|
||||
except json.JSONDecodeError:
|
||||
print(
|
||||
"[E] Couldn't parse the output of"
|
||||
"`nix show-derivation`"
|
||||
f". Expected JSON, observed: {proc.stdout}",
|
||||
file=stderr,
|
||||
)
|
||||
print(
|
||||
textwrap.indent(proc.stdout.decode("utf8"), prefix=" " * 4),
|
||||
file=stderr,
|
||||
)
|
||||
print("[I] Exiting the nix-required-binds hook", file=stderr)
|
||||
return
|
||||
[canon_drv_path] = drv.keys()
|
||||
|
||||
allowed_patterns = CONFIG["allowedPatterns"]
|
||||
known_features = set(
|
||||
chain.from_iterable(
|
||||
pattern["onFeatures"] for pattern in allowed_patterns.values()
|
||||
)
|
||||
)
|
||||
|
||||
drv_env = drv[canon_drv_path].get("env", {})
|
||||
features = drv_env.get("requiredSystemFeatures", [])
|
||||
if isinstance(features, str):
|
||||
features = features.split()
|
||||
|
||||
features = list(filter(known_features.__contains__, features))
|
||||
|
||||
patterns = list(chain.from_iterable(allowed_patterns[f]["paths"] for f in features)) # noqa: E501
|
||||
|
||||
roots = sorted(
|
||||
set(Path(path) for pattern in patterns for path in glob.glob(pattern))
|
||||
)
|
||||
|
||||
# the pre-build-hook command
|
||||
if args.issue_command == "always" or (
|
||||
args.issue_command == "conditional" and roots
|
||||
):
|
||||
print("extra-sandbox-paths")
|
||||
|
||||
# arguments, one per line
|
||||
for p in roots:
|
||||
guest_path, host_path = p, p
|
||||
print(f"{guest_path}={host_path}")
|
||||
|
||||
# terminated by an empty line
|
||||
something_to_terminate = args.issue_stop == "conditional" and roots
|
||||
if args.issue_stop == "always" or something_to_terminate:
|
||||
print()
|
||||
|
||||
|
||||
entrypoint()
|
57
pkgs/by-name/ni/nix-required-mounts/package.nix
Normal file
57
pkgs/by-name/ni/nix-required-mounts/package.nix
Normal file
@ -0,0 +1,57 @@
|
||||
{ addOpenGLRunpath
|
||||
, cmake
|
||||
, allowedPatterns ? rec {
|
||||
opengl.onFeatures = [ "opengl" ];
|
||||
opengl.paths = [
|
||||
addOpenGLRunpath.driverLink
|
||||
"/dev/video*"
|
||||
"/dev/dri"
|
||||
];
|
||||
cuda.onFeatures = [ "cuda" ];
|
||||
cuda.paths = opengl.paths ++ [
|
||||
"/dev/nvidia*"
|
||||
];
|
||||
}
|
||||
, buildPackages
|
||||
, formats
|
||||
, lib
|
||||
, nix
|
||||
, python3
|
||||
, runCommand
|
||||
}:
|
||||
|
||||
|
||||
let
|
||||
confPath = (formats.pythonVars { }).generate "config.py" {
|
||||
CONFIG = {
|
||||
inherit allowedPatterns;
|
||||
nixExe = lib.getExe nix;
|
||||
};
|
||||
};
|
||||
pname = "nix-required-mounts";
|
||||
in
|
||||
|
||||
runCommand pname
|
||||
{
|
||||
inherit confPath;
|
||||
meta.mainProgram = pname;
|
||||
} ''
|
||||
${lib.getExe buildPackages.python3.pkgs.flake8} ${./main.py}
|
||||
|
||||
cat > main.py << EOF
|
||||
#!${lib.getExe python3}
|
||||
|
||||
$(cat ${./main.py})
|
||||
EOF
|
||||
|
||||
sed -ie '
|
||||
/^entrypoint()$/ {
|
||||
x ;
|
||||
r ${confPath}
|
||||
}' main.py
|
||||
|
||||
echo "entrypoint()" >> main.py
|
||||
|
||||
mkdir -p $out/bin
|
||||
install main.py $out/bin/${pname}
|
||||
''
|
2
pkgs/by-name/ni/nix-required-mounts/pyproject.toml
Normal file
2
pkgs/by-name/ni/nix-required-mounts/pyproject.toml
Normal file
@ -0,0 +1,2 @@
|
||||
[tool.black]
|
||||
line-length = 79
|
Loading…
Reference in New Issue
Block a user