1{lib, pkgs}:
2let inherit (lib) nv nvs; in
3{
4
5 # composableDerivation basically mixes these features:
6 # - fix function
7 # - mergeAttrBy
8 # - provides shortcuts for "options" such as "--enable-foo" and adding
9 # buildInputs, see php example
10 #
11 # It predates styles which are common today, such as
12 # * the config attr
13 # * mkDerivation.override feature
14 # * overrideDerivation (lib/customization.nix)
15 #
16 # Some of the most more important usage examples (which could be rewritten if it was important):
17 # * php
18 # * postgis
19 # * vim_configurable
20 #
21 # A minimal example illustrating most features would look like this:
22 # let base = composableDerivation { (fixed: let inherit (fixed.fixed) name in {
23 # src = fetchurl {
24 # }
25 # buildInputs = [A];
26 # preConfigre = "echo ${name}";
27 # # attention, "name" attr is missing, thus you cannot instantiate "base".
28 # }
29 # in {
30 # # These all add name attribute, thus you can instantiate those:
31 # v1 = base.merge ({ name = "foo-add-B"; buildInputs = [B]; }); // B gets merged into buildInputs
32 # v2 = base.merge ({ name = "mix-in-pre-configure-lines" preConfigre = ""; });
33 # v3 = base.replace ({ name = "foo-no-A-only-B;" buildInputs = [B]; });
34 # }
35 #
36 # So yes, you can think about it being something like nixos modules, and
37 # you'd be merging "features" in one at a time using .merge or .replace
38 # Thanks Shea for telling me that I rethink the documentation ..
39 #
40 # issues:
41 # * its complicated to understand
42 # * some "features" such as exact merge behaviour are buried in mergeAttrBy
43 # and defaultOverridableDelayableArgs assuming the default behaviour does
44 # the right thing in the common case
45 # * Eelco once said using such fix style functions are slow to evaluate
46 # * Too quick & dirty. Hard to understand for others. The benefit was that
47 # you were able to create a kernel builder like base derivation and replace
48 # / add patches the way you want without having to declare function arguments
49 #
50 # nice features:
51 # declaring "optional features" is modular. For instance:
52 # flags.curl = {
53 # configureFlags = ["--with-curl=${curl.dev}" "--with-curlwrappers"];
54 # buildInputs = [curl openssl];
55 # };
56 # flags.other = { .. }
57 # (Example taken from PHP)
58 #
59 # alternative styles / related features:
60 # * Eg see function supporting building the kernel
61 # * versionedDerivation (discussion about this is still going on - or ended)
62 # * composedArgsAndFun
63 # * mkDerivation.override
64 # * overrideDerivation
65 # * using { .., *Support ? false }: like configurable options.
66 # To find those examples use grep
67 #
68 # To sum up: It exists for historical reasons - and for most commonly used
69 # tasks the alternatives should be used
70 #
71 # If you have questions about this code ping Marc Weber.
72 composableDerivation = {
73 mkDerivation ? pkgs.stdenv.mkDerivation,
74
75 # list of functions to be applied before defaultOverridableDelayableArgs removes removeAttrs names
76 # prepareDerivationArgs handles derivation configurations
77 applyPreTidy ? [ lib.prepareDerivationArgs ],
78
79 # consider adding addtional elements by derivation.merge { removeAttrs = ["elem"]; };
80 removeAttrs ? ["cfg" "flags"]
81
82 }: (lib.defaultOverridableDelayableArgs ( a: mkDerivation a)
83 {
84 inherit applyPreTidy removeAttrs;
85 }).merge;
86
87 # some utility functions
88 # use this function to generate flag attrs for prepareDerivationArgs
89 # E nable D isable F eature
90 edf = {name, feat ? name, enable ? {}, disable ? {} , value ? ""}:
91 nvs name {
92 set = {
93 configureFlags = ["--enable-${feat}${if value == "" then "" else "="}${value}"];
94 } // enable;
95 unset = {
96 configureFlags = ["--disable-${feat}"];
97 } // disable;
98 };
99
100 # same for --with and --without-
101 # W ith or W ithout F eature
102 wwf = {name, feat ? name, enable ? {}, disable ? {}, value ? ""}:
103 nvs name {
104 set = enable // {
105 configureFlags = ["--with-${feat}${if value == "" then "" else "="}${value}"]
106 ++ lib.maybeAttr "configureFlags" [] enable;
107 };
108 unset = disable // {
109 configureFlags = ["--without-${feat}"]
110 ++ lib.maybeAttr "configureFlags" [] disable;
111 };
112 };
113}