-
Notifications
You must be signed in to change notification settings - Fork 3
/
mybuilders.nix
205 lines (198 loc) · 7.6 KB
/
mybuilders.nix
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
{pkgs, lib, ...}:
rec {
# Creates a derivation with only links to the given binaries.
# The binaries to include are described by a spec, see the examples below.
#
# Can be used:
# * to rename binaries
# * to rename binaries to allow multiple version of the same software
# in the same derivation or the same top-level environment (which is also a derivation).
# * to expose only a few binaries of a derivation.
#
# NOTE: Using linkBins, the packages used to define the new binaries can't install their normal
# outputs, thus 'man' output is never available... Similarly shell completions, icons, libs,
# includes, configs are not included.
# This builder is ONLY useful to make binaries available.
# => Use `replaceBinsInPkg` to replace bins in an existing package while keeping its structure.
#
# Types:
# linkBins :: { name :: String; ... } -> derivation
# linkBins :: [ String or { name :: String; path :: String; } ] -> derivation
#
# Examples:
# (linkBins "my-bins1" [
# pkgs.neovim
# "/tmp/foo/bar"
# ])
# => creates a derivation like:
# /nix/store/znk3qkb30ccgq6kvgmv69jj4ci9bin18-my-bins1/
# └── bin/
# ├── nvim -> /nix/store/frlxim9yz5qx34ap3iaf55caawgdqkip-neovim-0.5.1/bin/nvim
# └── bar -> /tmp/foo/bar
#
# (linkBins "my-bins2" [
# {name = "nvim-stable"; path = pkgs.neovim;}
# "/tmp/foo/bar"
# ])
# => creates a derivation like:
# /nix/store/f35182nny6lb95srh0lbxfd5hq99kr8s-my-bins2/
# └── bin/
# ├── nvim-stable -> /nix/store/frlxim9yz5qx34ap3iaf55caawgdqkip-neovim-0.5.1/bin/nvim
# └── bar -> /tmp/foo/bar
#
# (linkBins "my-bins3" {
# nvim-stable = pkgs.neovim;
# bar-tmp = "/tmp/foo/bar";
# })
# => creates a derivation like:
# /nix/store/3v6mk91b4n4758zli921y2z27xm3a5v2-my-bins3/
# └── bin/
# ├── nvim-stable -> /nix/store/frlxim9yz5qx34ap3iaf55caawgdqkip-neovim-0.5.1/bin/nvim
# └── bar-tmp -> /tmp/foo/bar
#
# TODO: allow to pass `mainProgram = true;` in a spec
# => set a bin as the `meta.mainProgram` of the resulting drv
linkBins = name: binsSpec:
let
binSpecHelp = ''
a binSpec can be either:
- a string: "/path/to/foo"
- a set pointing to a string: { name = "foo"; path = "/path/to/foo"; }
- a derivation: pkgs.neovim
- a set pointing to a derivation: { name = "nvim-custom"; path = pkgs.neovim; }
'';
binsSpecHelp = ''
binsSpec argument can be either:
- a list of binSpec: (see below)
- a set: { foo = "/path/to/foo"; }
${binSpecHelp}
'';
typeOf = builtins.typeOf;
binsSpecList =
if (typeOf binsSpec) == "list" then binsSpec
else if (typeOf binsSpec) == "set" then
lib.mapAttrsToList (name: path: { inherit name path; }) binsSpec
else
throw ''
For linkBins: Unable to normalize given binsSpec argument of type '${typeOf binsSpec}'
${binsSpecHelp}
'';
normalizedBinsSpec = lib.forEach binsSpecList (item:
if (typeOf item) == "string" then
{ name = baseNameOf item; path = item; }
else if (typeOf item) == "set" && (item ? "name") && (item ? "path") then
let binTarget = item.path; in {
inherit (item) name;
path = (
if (typeOf binTarget) == "string" then
binTarget
else if (typeOf binTarget) == "set" && (binTarget ? outPath) then
lib.getExe binTarget
else
throw ''
For linkBins: Unable to find target bin path '${name}' of type '${typeOf binTarget}'
${binsSpecHelp}
''
);
}
else
throw ''
For linkBins: Unable to normalize bin spec of type '${typeOf item}'
${binSpecHelp}
''
);
in pkgs.runCommandLocal name {} ''
mkdir -p $out/bin
cd $out/bin
${lib.concatMapStrings ({name, path}: ''
ln -s ${lib.escapeShellArg path} ${lib.escapeShellArg name}
'') normalizedBinsSpec}
'';
# Creates a derivation with a single link in bin/ to the given binary path.
#
# Type: linkSingleBin :: String -> derivation
#
# Example:
# linkSingleBin "${pkgs.neovim}/bin/nvim"
# => creates a derivation like:
# /nix/store/yv5aigjy8l9bi9kpqh7y1dzf6nv07cl0-nvim-single-bin/
# └── bin/
# └── nvim -> /nix/store/frlxim9yz5qx34ap3iaf55caawgdqkip-neovim-0.5.1/bin/nvim
#
linkSingleBin = path: let
binName = baseNameOf path;
in pkgs.runCommandLocal "${binName}-single-bin" { meta.mainProgram = binName; } ''
mkdir -p $out/bin
ln -s ${lib.escapeShellArg path} $out/bin/
'';
# Copy full package, remove existing bin/ and replace with the given list of bins.
#
# This is useful to patch some binaries / force them to use some
# configuration, while preserving the pkg layout, allowing `man tool` to
# auto-find the manpage of the tool when it's installed in home.packages!
#
# Example:
# replaceBinsInPkg {
# name = "custom-fzf";
# copyFromPkg = fzf;
# bins = {
# fzf = writeShellScript "fzf" ''
# exec ${fzf}/bin/fzf --custom-args right here --and=here "$@"
# '';
# };
# postBuild = "
# }
# => creates a derivation like:
# /nix/store/xx3yknpx0yvnks0dqvsd11n7p1zm5mb4-custom-fzf
# ├── bin
# │ └── fzf
# └── share
# ├── fish -> /nix/store/3fz694nbl7ndyinz7xmhz77inzn0a17h-fzf-0.35.1/share/fish
# ├── fzf -> /nix/store/3fz694nbl7ndyinz7xmhz77inzn0a17h-fzf-0.35.1/share/fzf
# ├── man -> /nix/store/5fl47ah7k40j6pk0ln74wf3kby2h8jp1-fzf-0.35.1-man/share/man
# └── vim-plugins -> /nix/store/3fz694nbl7ndyinz7xmhz77inzn0a17h-fzf-0.35.1/share/vim-plugins
#
# replaceBinsInPkg {
# name = "custom-zsh";
# copyFromPkg = zsh;
# nativeBuildInputs = [ makeWrapper ];
# postBuild = /* sh */ ''
# makeWrapper ${zsh}/bin/zsh $out/bin/zsh --set ZDOTDIR /some/new/zdotdir
# '';
# };
# => creates a derivation like:
# /nix/store/p85wi35yda68xw9xr2s1lamgv4hqh1jl-custom-zsh
# ├── bin
# │ └── zsh
# ├── etc -> /nix/store/dy11j8bd6a6gq0nsgx54zddg32qrcd7l-zsh-5.8.1/etc
# ├── lib -> /nix/store/dy11j8bd6a6gq0nsgx54zddg32qrcd7l-zsh-5.8.1/lib
# └── share -> /nix/store/dy11j8bd6a6gq0nsgx54zddg32qrcd7l-zsh-5.8.1/share
#
replaceBinsInPkg = { name, copyFromPkg, bins ? {}, nativeBuildInputs ? [], postBuild ? "", meta ? {} }:
pkgs.buildEnv {
inherit name nativeBuildInputs meta;
paths = [ copyFromPkg ];
postBuild = /* sh */ ''
if [[ -e $out/bin ]]; then
echo "Remove existing bin/ (was: `readlink $out/bin`)"
# No need for '-r', it's a symlink!
rm -f $out/bin
fi
echo "Create empty bin/"
mkdir $out/bin
${lib.optionalString (0 != (lib.length (lib.attrNames bins))) ''
echo "Add binaries: ${lib.concatStringsSep ", " (lib.attrNames bins)}"
${lib.concatStringsSep "\n"
(lib.mapAttrsToList
(name: targetBin: "cp ${toString targetBin} $out/bin/${name}")
bins
)
}
''}
${lib.optionalString (0 != (lib.stringLength postBuild)) ''
echo "Run postBuild to add more binaries"
${postBuild}
''}
'';
};
}