33 devFlake ,
44} :
55
6+ let
7+ # Some helper functions
8+
9+ /**
10+ Compute a filtered closure of build inputs.
11+
12+ Specifically, `buildInputsClosure cond startSet` computes the closure formed
13+ by recursive application of `p: filter cond p.buildInputs ++ filter cond p.propagatedBuildInputs`
14+ to `startSet`.
15+
16+ Example:
17+ ```nix
18+ builtInputsClosure isInternal [ pkg1 pkg2 ]
19+ => [ pkg1 pkg3 pkg2 pkg10 ]
20+ ```
21+
22+ Note: order tbd
23+
24+ Note: `startSet` is *NOT* filtered.
25+ */
26+ buildInputsClosureCond =
27+ cond : startSet :
28+ let
29+ closure = builtins . genericClosure {
30+ startSet = map ( d : {
31+ key = d . drvPath ;
32+ value = d ;
33+ } ) startSet ;
34+ operator =
35+ d :
36+ let
37+ r =
38+ map
39+ ( d' : {
40+ key = d' . drvPath ;
41+ value = d' ;
42+ } )
43+ (
44+ lib . filter cond d . value . buildInputs or [ ] ++ lib . filter cond d . value . propagatedBuildInputs or [ ]
45+ ) ;
46+ in
47+ r ;
48+ } ;
49+ in
50+ map ( item : item . value ) closure ;
51+
52+ /**
53+ `[ pkg1 pkg2 ]` -> `{ "...-pkg2.drv" = null; "...-pkg1.drv" = null }`
54+
55+ Note: fairly arbitrary order (hash based). Use for efficient set membership test only.
56+ */
57+ byDrvPath =
58+ l :
59+ lib . listToAttrs (
60+ map ( c : {
61+ name =
62+ # Just a lookup key
63+ builtins . unsafeDiscardStringContext c . drvPath ;
64+ value = null ;
65+ } ) l
66+ ) ;
67+
68+ /**
69+ Stable dedup.
70+
71+ Unlike `listToAttrs` -> `attrValues`, this preserves the input ordering,
72+ which is more predictable ("deterministic") than e.g. sorting store paths,
73+ whose hashes affect the ordering on every change.
74+ */
75+ # TODO: add to Nixpkgs lib, refer from uniqueStrings
76+ dedupByString =
77+ key : l :
78+ let
79+ r =
80+ lib . foldl'
81+ (
82+ a @{ list , set } :
83+ elem :
84+ let
85+ k = builtins . unsafeDiscardStringContext ( key elem ) ;
86+ in
87+ if set ? ${ k } then
88+ a
89+ else
90+ let
91+ # Note: O(n²) copying. Use linkedLists to concat them in one go at the end.
92+ # https://github.com/NixOS/nixpkgs/pull/452088
93+ newList = [ elem ] ++ list ;
94+ newSet = set // {
95+ ${ k } = null ;
96+ } ;
97+ in
98+ builtins . seq newList builtins . seq newSet {
99+ list = newList ;
100+ set = newSet ;
101+ }
102+ )
103+ {
104+ list = [ ] ;
105+ set = { } ;
106+ }
107+ l ;
108+ in
109+ r . list ;
110+
111+ in
112+
6113{ pkgs } :
7114
115+ # TODO: don't use nix-util for this?
8116pkgs . nixComponents2 . nix-util . overrideAttrs (
9- attrs :
117+ finalAttrs : prevAttrs :
10118
11119 let
12120 stdenv = pkgs . nixDependencies2 . stdenv ;
@@ -21,13 +129,89 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
21129 "-D${ prefix } :${ rest } " ;
22130 havePerl = stdenv . buildPlatform == stdenv . hostPlatform && stdenv . hostPlatform . isUnix ;
23131 ignoreCrossFile = flags : builtins . filter ( flag : ! ( lib . strings . hasInfix "cross-file" flag ) ) flags ;
132+
133+ activeComponents = buildInputsClosureCond isInternal (
134+ lib . attrValues ( finalAttrs . passthru . config . getComponents allComponents )
135+ ) ;
136+
137+ allComponents = lib . filterAttrs ( k : v : lib . isDerivation v ) pkgs . nixComponents2 ;
138+ internalDrvs = byDrvPath (
139+ # Drop the attr names (not present in buildInputs anyway)
140+ lib . attrValues allComponents
141+ ++ lib . concatMap ( c : lib . attrValues c . tests or { } ) ( lib . attrValues allComponents )
142+ ) ;
143+
144+ isInternal =
145+ dep : internalDrvs ? ${ builtins . unsafeDiscardStringContext dep . drvPath or "_non-existent_" } ;
146+
24147 in
25148 {
26- pname = "shell-for-" + attrs . pname ;
149+ pname = "shell-for-nix" ;
150+
151+ passthru = {
152+ inherit activeComponents ;
153+
154+ # We use this attribute to store non-derivation values like functions and
155+ # perhaps other things that are primarily for overriding and not the shell.
156+ config = {
157+ # Default getComponents
158+ getComponents =
159+ c :
160+ builtins . removeAttrs c (
161+ lib . optionals ( ! havePerl ) [ "nix-perl-bindings" ]
162+ ++ lib . optionals ( ! buildCanExecuteHost ) [ "nix-manual" ]
163+ ) ;
164+ } ;
165+
166+ /**
167+ Produce a devShell for a given set of nix components
168+
169+ Example:
170+
171+ ```nix
172+ shell.withActiveComponents (c: {
173+ inherit (c) nix-util;
174+ })
175+ ```
176+ */
177+ withActiveComponents =
178+ f2 :
179+ finalAttrs . finalPackage . overrideAttrs (
180+ finalAttrs : prevAttrs : {
181+ passthru = prevAttrs . passthru // {
182+ config = prevAttrs . passthru . config // {
183+ getComponents = f2 ;
184+ } ;
185+ } ;
186+ }
187+ ) ;
188+
189+ small =
190+ ( finalAttrs . finalPackage . withActiveComponents ( c : {
191+ inherit ( c )
192+ nix-cli
193+ nix-util-tests
194+ nix-store-tests
195+ nix-expr-tests
196+ nix-fetchers-tests
197+ nix-flake-tests
198+ nix-functional-tests
199+ # Currently required
200+ nix-perl-bindings
201+ ;
202+ } ) ) . overrideAttrs
203+ ( o : {
204+ mesonFlags = o . mesonFlags ++ [
205+ # TODO: infer from activeComponents or vice versa
206+ "-Dkaitai-struct-checks=false"
207+ "-Djson-schema-checks=false"
208+ ] ;
209+ } ) ;
210+ } ;
27211
28212 # Remove the version suffix to avoid unnecessary attempts to substitute in nix develop
29213 version = lib . fileContents ../.version ;
30- name = attrs . pname ;
214+ name = finalAttrs . pname ;
31215
32216 installFlags = "sysconfdir=$(out)/etc" ;
33217 shellHook = ''
@@ -98,17 +282,9 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
98282 nativeBuildInputs =
99283 let
100284 inputs =
101- attrs . nativeBuildInputs or [ ]
102- ++ pkgs . nixComponents2 . nix-util . nativeBuildInputs
103- ++ pkgs . nixComponents2 . nix-store . nativeBuildInputs
104- ++ pkgs . nixComponents2 . nix-fetchers . nativeBuildInputs
105- ++ pkgs . nixComponents2 . nix-expr . nativeBuildInputs
106- ++ lib . optionals havePerl pkgs . nixComponents2 . nix-perl-bindings . nativeBuildInputs
107- ++ lib . optionals buildCanExecuteHost pkgs . nixComponents2 . nix-manual . externalNativeBuildInputs
108- ++ pkgs . nixComponents2 . nix-internal-api-docs . nativeBuildInputs
109- ++ pkgs . nixComponents2 . nix-external-api-docs . nativeBuildInputs
110- ++ pkgs . nixComponents2 . nix-functional-tests . externalNativeBuildInputs
111- ++ pkgs . nixComponents2 . nix-json-schema-checks . externalNativeBuildInputs
285+ dedupByString ( v : "${ v } " ) (
286+ lib . filter ( x : ! isInternal x ) ( lib . lists . concatMap ( c : c . nativeBuildInputs ) activeComponents )
287+ )
112288 ++ lib . optional (
113289 ! buildCanExecuteHost
114290 # Hack around https://github.com/nixos/nixpkgs/commit/bf7ad8cfbfa102a90463433e2c5027573b462479
@@ -117,9 +293,7 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
117293 && lib . meta . availableOn stdenv . buildPlatform ( stdenv . hostPlatform . emulator pkgs . buildPackages )
118294 ) pkgs . buildPackages . mesonEmulatorHook
119295 ++ [
120- pkgs . buildPackages . cmake
121296 pkgs . buildPackages . gnused
122- pkgs . buildPackages . changelog-d
123297 modular . pre-commit . settings . package
124298 ( pkgs . writeScriptBin "pre-commit-hooks-install" modular . pre-commit . settings . installationScript )
125299 pkgs . buildPackages . nixfmt-rfc-style
@@ -136,18 +310,22 @@ pkgs.nixComponents2.nix-util.overrideAttrs (
136310 # from making its way into NIX_CFLAGS_COMPILE.
137311 lib . filter ( p : ! lib . hasInfix "separate-debug-info" p ) inputs ;
138312
313+ propagatedNativeBuildInputs = dedupByString ( v : "${ v } " ) (
314+ lib . filter ( x : ! isInternal x ) (
315+ lib . lists . concatMap ( c : c . propagatedNativeBuildInputs ) activeComponents
316+ )
317+ ) ;
318+
139319 buildInputs = [
140320 pkgs . gbenchmark
141321 ]
142- ++ attrs . buildInputs or [ ]
143- ++ pkgs . nixComponents2 . nix-util . buildInputs
144- ++ pkgs . nixComponents2 . nix-store . buildInputs
145- ++ pkgs . nixComponents2 . nix-store-tests . externalBuildInputs
146- ++ pkgs . nixComponents2 . nix-fetchers . buildInputs
147- ++ pkgs . nixComponents2 . nix-expr . buildInputs
148- ++ pkgs . nixComponents2 . nix-expr . externalPropagatedBuildInputs
149- ++ pkgs . nixComponents2 . nix-cmd . buildInputs
150- ++ lib . optionals havePerl pkgs . nixComponents2 . nix-perl-bindings . externalBuildInputs
322+ ++ dedupByString ( v : "${ v } " ) (
323+ lib . filter ( x : ! isInternal x ) ( lib . lists . concatMap ( c : c . buildInputs ) activeComponents )
324+ )
151325 ++ lib . optional havePerl pkgs . perl ;
326+
327+ propagatedBuildInputs = dedupByString ( v : "${ v } " ) (
328+ lib . filter ( x : ! isInternal x ) ( lib . lists . concatMap ( c : c . propagatedBuildInputs ) activeComponents )
329+ ) ;
152330 }
153331)
0 commit comments