blob: 119b23e66c34c307b428c0a747edb96c302f7191 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
self: super:
let
inherit (super) lib mylib;
# Takes a path to a shellscript an builds it into a package.
#
# The shellscript may contain instructions for modifying the PATH variable:
# #!buildShellBin path=PKGS resets the PATH variable to the specified packages
# #!buildShellBin append-path=PKGS append the packages to the PATH variable
# #!buildShellBin prepend-path=PKGS prepend the packages to the PATH variable
# where
# PKGS is a non-empty, colon-delimited list of package attribute names, e.g. coreutils:binutils:which
buildShellBin = name: path:
assert mylib.types.filename.check name;
assert isShellScript path;
self.callPackage
({ pkgs }: pkgs.runCommand "${name}" {} /* sh */ ''
mkdir -p $out/bin
touch $out/bin/${name}
chmod +x $out/bin/${name}
exec > $out/bin/${name}
echo '#! ${pkgs.dash}/bin/dash'
echo ${mylib.shell.escape (lib.concatStringsSep "\n" (pathMods pkgs path))}
cat ${path}
'') {};
# Determine if a line is an instruction to modify the PATH variable.
readPathMod = pkgs: path: line: string: let
match = builtins.match "^#! *buildShellBin ((prepend-|append-)?path)=(.*)" string;
in
lib.optionalAttrs (match != null) {
inherit path line;
method = builtins.elemAt match 0;
packages = map (name: pkgs.${name}) (lib.splitString ":" (builtins.elemAt match 2));
};
# Generate shell assignment to modify the PATH variable.
applyPathMod = { method, packages, ... }: {
path = /* sh */ "PATH=${lib.makeBinPath packages}";
append-path = /* sh */ "PATH=\${PATH+$PATH:}${lib.makeBinPath packages}";
prepend-path = /* sh */ "PATH=${lib.makeBinPath packages}\${PATH+:$PATH}";
}.${method};
applyPathMods = mods:
assert checkPathMods mods;
map applyPathMod mods;
# Check if a list of list of PATH modifications for sanity.
checkPathMods = mods: let
index = lib.lists.findFirstIndex (mod: mod.method == "path") 0 mods;
mod = lib.elemAt mods index;
in
if index > 0 then
builtins.trace "warning: resetting PATH in ${toString mod.path}:${toString mod.line}" true
else
true;
pathMods = pkgs: path:
applyPathMods
(builtins.filter
(x: x != {})
(lib.imap1
(readPathMod pkgs path)
(lib.splitString "\n" (builtins.readFile path))));
isShellScript = path:
mylib.test "#! */bin/sh" (builtins.head (lib.splitString "\n" (builtins.readFile path)));
in
lib.mapAttrs
(name: _: buildShellBin name (./. + "/${name}"))
(lib.filterAttrs
(name: _: name != "default.nix")
(builtins.readDir ./.))
|