on 147cf21 help sign in
haskell.nix/lib/default.nix
131 lines 5.0 kB history raw
1{ lib, haskellLib }:
3with haskellLib;
5{
6 # Within the package components, these are the attribute names of
7 # nested attrsets.
8 subComponentTypes = [
9 "sublibs"
10 "foreignlibs"
11 "exes"
12 "tests"
13 "benchmarks"
14 ];
16 foldrAttrVals = f: z: attrs:
17 lib.foldr (g: acc: g acc) z (lib.mapAttrsToList (_name: f) attrs);
19 foldComponents = tys: f: z: conf:
20 let
21 comps = conf.components or {};
22 # ensure that comps.library exists and is not null.
23 libComp = acc: if (comps.library or null) != null then f comps.library acc else acc;
24 subComps = acc:
25 lib.foldr
26 (ty: acc': foldrAttrVals f acc' (comps.${ty} or {}))
27 acc
28 tys;
29 in libComp (subComps z);
31 getAllComponents = foldComponents subComponentTypes (c: acc:
32 lib.optional c.buildable c ++ acc) [];
34 componentPrefix = {
35 # Are all of these right?
36 sublibs = "lib";
37 foreignlibs = "foreignlib";
38 exes = "exe";
39 tests = "test";
40 benchmarks = "bench";
41 };
43 applyComponents = f: config:
44 let
45 comps = config.components;
46 applyLibrary = cname: f { cname = config.package.identifier.name; ctype = "lib"; };
47 applySubComp = ctype: cname: f { inherit cname; ctype = componentPrefix.${ctype} or (throw "Missing component mapping for ${ctype}."); };
48 applyAllComp = f { cname = config.package.identifier.name; ctype = "all"; };
49 buildableAttrs = lib.filterAttrs (n: comp: comp.buildable or true);
50 libComp = if comps.library == null || !(comps.library.buildable or true)
51 then {}
52 else lib.mapAttrs applyLibrary (removeAttrs comps (subComponentTypes ++ [ "all" ]));
53 subComps = lib.mapAttrs
54 (ctype: attrs: lib.mapAttrs (applySubComp ctype) (buildableAttrs attrs))
55 (builtins.intersectAttrs (lib.genAttrs subComponentTypes (_: null)) comps);
56 allComp = { all = applyAllComp comps.all; };
57 in subComps // libComp // allComp;
59 isLibrary = componentId: componentId.ctype == "lib";
60 isAll = componentId: componentId.ctype == "all";
61 isTest = componentId: componentId.ctype == "test";
62 isBenchmark = componentId: componentId.ctype == "bench";
64 # Was there a reference to the package source in the `cabal.project` or `stack.yaml` file.
65 # This is used to make the default `packages` list for `shellFor`.
66 isLocalPackage = p: p.isLocal or false;
67 selectLocalPackages = ps: lib.filterAttrs (n: p: p != null && isLocalPackage p) ps;
69 # Format a componentId as it should appear as a target on the
70 # command line of the setup script.
71 componentTarget = componentId:
72 if componentId.ctype == "all" then ""
73 else "${componentId.ctype}:${componentId.cname}";
75 # Remove null or empty values from an attrset.
76 optionalHooks = lib.filterAttrs (_: hook: hook != null && hook != "");
78 # Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
79 # style programming that we should avoid until we know we want it.
81 # weakCallPackage: call a function or (importable expression)
82 # with scope + args.
83 #
84 # weakCallPackage scope f args
85 # will call f (scope // args)
86 #
87 # weakCallpackage scope ./path args
88 # will call the expression at ./path with (scope // args)
89 #
90 weakCallPackage = scope: f: args:
91 let f' = if lib.isFunction f then f else import f;
92 args' = (builtins.intersectAttrs (builtins.functionArgs f') scope) // args;
93 in f' args';
95 # Collect all (transitive) Haskell library dependencies of a
96 # component.
97 ## flatLibDepends :: Component -> [Package]
98 flatLibDepends = component:
99 let
100 makePairs = map (p: rec { key="${val}"; val=(p.components.library or p); });
101 closure = builtins.genericClosure {
102 startSet = makePairs component.depends;
103 operator = {val,...}: makePairs val.config.depends;
104 };
105 in map ({val,...}: val) closure;
107 # Extracts a selection of components from a Haskell package set.
108 #
109 # This can be used to filter out all test suites or benchmarks of
110 # your project, so that they can be built in Hydra.
111 #
112 # For example:
113 #
114 # tests = collectComponents "tests" (package: package.identifier.name == "mypackage") hsPkgs;
115 #
116 # Will result in moving:
117 # from: hsPkgs.mypackage.components.tests.unit-tests
118 # to: tests.mypackage.unit-tests
119 #
120 collectComponents = group: packageSel: haskellPackages:
121 (mapAttrs (_: package: package.components.${group} // { recurseForDerivations = true; })
122 (filterAttrs (name: package: (package.isHaskell or false) && packageSel package) haskellPackages))
123 // { recurseForDerivations = true; };
125 # Replacement for lib.cleanSourceWith that has a subDir argument.
126 inherit (import ./clean-source-with.nix { inherit lib; }) cleanSourceWith canCleanSource;
128 # Use cleanSourceWith to filter just the files needed for a particular
129 # component of a package
130 cleanCabalComponent = import ./clean-cabal-component.nix { inherit lib cleanSourceWith; };