1{ pkgs, stdenv, lib, haskellLib, recurseIntoAttrs, srcOnly }:
7 # Why `final.evalPackages.buildPackages.gitMinimal`?
8 # Why not just final.evalPackages.gitMinimal?
10 # A problem arises when `evalPackages` is `buildPackages`.i
11 # As may be the case in a flake.
13 # It turns out `git` depends on `gdb` in a round about way:
14 # git -> openssh -> libfido2 -> systemd -> python libxml -> Cython -> gdb
15 # Somewhere in that chain there should perhaps be a `buildPackages` so
16 # that the `gdb` that is used is not the one for debugging code in
17 # the `final` (but instead the one for debugging code in
18 # `final.buildPackages`).
20 # Using `final.buildPackages.git` causes two problems:
22 # * Multiple versions of `git` (and that dependency chain
23 # to `gdb` are needed when cross compiling).
24 # * When `gdb` does not exist for `js`, so when cross
25 # compiling with ghcjs `final.buildPackages.git` fails
27 inherit (pkgs.evalPackages.buildPackages) gitMinimal;
30 # Within the package components, these are the attribute names of
40 foldrAttrVals = f: z: attrs:
41 lib.foldr (g: acc: g acc) z (lib.mapAttrsToList (_name: f) attrs);
43 foldComponents = tys: f: z: conf:
45 comps = conf.components or {};
46 # ensure that comps.library exists and is not null.
47 libComp = acc: if (comps.library or null) != null then f comps.library acc else acc;
50 (ty: acc': foldrAttrVals f acc' (comps.${ty} or {}))
53 in libComp (subComps z);
55 getAllComponents = foldComponents subComponentTypes (c: acc: [c] ++ acc) [];
65 # For looking up the components attribute based on the cabal component type
68 lib.mapAttrsToList (value: name: { inherit name value; })
71 applyComponents = f: config:
73 comps = config.components;
74 applyLibrary = cname: f { cname = config.package.identifier.name; ctype = "lib"; };
75 applySubComp = ctype: cname: f { inherit cname; ctype = componentPrefix.${ctype} or (throw "Missing component mapping for ${ctype}."); };
77 config.package.buildable # Set manually in a module (allows whole packages to be disabled)
78 && comp.buildable # Set based on `buildable` in `.cabal` files
79 && comp.planned; # Set if the component was in the `plan.json`
80 buildableAttrs = lib.filterAttrs (n: isBuildable);
81 libComp = if comps.library == null || !(isBuildable comps.library)
83 else lib.mapAttrs applyLibrary (removeAttrs comps (subComponentTypes ++ [ "setup" ]));
84 subComps = lib.mapAttrs
85 (ctype: attrs: lib.mapAttrs (applySubComp ctype) (buildableAttrs attrs))
86 (builtins.intersectAttrs (lib.genAttrs subComponentTypes (_: null)) comps);
87 in subComps // libComp;
89 isLibrary = componentId: componentId.ctype == "lib";
90 isExe = componentId: componentId.ctype == "exe";
91 isTest = componentId: componentId.ctype == "test";
92 isBenchmark = componentId: componentId.ctype == "bench";
93 isExecutableType = componentId:
96 || isBenchmark componentId;
97 mayHaveExecutable = componentId:
98 isExecutableType componentId;
100 # Was there a reference to the package source in the `cabal.project` or `stack.yaml` file.
101 # This is used to make the default `packages` list for `shellFor`.
102 isLocalPackage = p: p.isLocal or false;
103 selectLocalPackages = ps: lib.filterAttrs (n: p: p != null && isLocalPackage p) ps;
105 # if it's a project package it has a src attribute set with an origSubDir attribute.
106 # project packages are a subset of localPackages
107 isProjectPackage = p: p.isProject or false;
108 selectProjectPackages = ps: lib.filterAttrs (n: p: p != null && isLocalPackage p && isProjectPackage p) ps;
110 # Format a componentId as it should appear as a target on the
111 # command line of the setup script.
112 componentTarget = componentId:"${componentId.ctype}:${componentId.cname}";
114 # Remove null or empty values from an attrset.
115 optionalHooks = lib.filterAttrs (_: hook: hook != null && hook != "");
117 # Avoid pkgs.callPackage for now. It does a lot of nonsense with OOP
118 # style programming that we should avoid until we know we want it.
120 # weakCallPackage: call a function or (importable expression)
123 # weakCallPackage scope f args
124 # will call f (scope // args)
126 # weakCallpackage scope ./path args
127 # will call the expression at ./path with (scope // args)
129 weakCallPackage = scope: f: args:
130 let f' = if lib.isFunction f then f else import f;
131 args' = (builtins.intersectAttrs (builtins.functionArgs f') scope) // args;
134 # Collect all (transitive) Haskell library dependencies of a
136 ## flatLibDepends :: Component -> [Package]
137 flatLibDepends = component:
139 makePairs = map (p: rec { key=val.name; val=(p.components.library or p); });
140 closure = builtins.genericClosure {
141 startSet = makePairs component.depends;
142 operator = {val,...}: makePairs val.config.depends;
144 in map ({val,...}: val) closure;
147 # Extracts a selection of components from a Haskell package set.
149 # This can be used to filter out all test suites or benchmarks of
150 # your project, so that they can be built in Hydra.
154 # tests = collectComponents "tests" (package: package.identifier.name == "mypackage") hsPkgs;
156 # Will result in moving:
157 # from: hsPkgs.mypackage.components.tests.unit-tests
158 # to: tests.mypackage.unit-tests
160 collectComponents = group: packageSel: haskellPackages:
161 let packageToComponents = name: package:
162 # look for the components with this group if there are any
163 let components = package.components.${group} or {};
164 # set recurseForDerivations unless it's a derivation itself (e.g. the "library" component) or an empty set
165 in if lib.isDerivation components || components == {}
167 else recurseIntoAttrs components;
168 packageFilter = name: package: (package.isHaskell or false) && packageSel package;
169 filteredPkgs = lib.filterAttrs packageFilter haskellPackages;
170 # at this point we can filter out packages that don't have any of the given kind of component
171 packagesByComponent = lib.filterAttrs (_: components: components != {}) (lib.mapAttrs packageToComponents filteredPkgs);
172 in recurseIntoAttrs packagesByComponent;
174 # Equivalent to collectComponents with (_: true) as selection function.
175 # Useful for pre-filtered package-set.
179 # myHaskellPackages = selectProjectPackages hsPkgs;
180 # myTests = collectComponents' "tests" myHaskellPackages;
181 collectComponents' = group: collectComponents group (_: true);
183 # Extracts a selection of 'checks' from a Haskell package set.
185 # This can be used to collect all the test runs in your project, so that can be run in CI.
186 collectChecks = packageSel: haskellPackages:
187 let packageFilter = name: package: (package.isHaskell or false) && packageSel package;
188 in recurseIntoAttrs (lib.mapAttrs (_: p: p.checks) (lib.filterAttrs packageFilter haskellPackages));
190 # Equivalent to collectChecks with (_: true) as selection function.
191 # Useful for pre-filtered package-set.
192 collectChecks' = collectChecks (_: true);
194 # Replacement for lib.cleanSourceWith that has a subDir argument.
195 inherit (import ./clean-source-with.nix { inherit lib; }) cleanSourceWith;
197 # Use cleanSourceWith to filter just the files needed for a particular
198 # component of a package
199 cleanCabalComponent = import ./clean-cabal-component.nix { inherit lib cleanSourceWith; };
201 # Clean git directory based on `git ls-files --recurse-submodules`
202 cleanGit = import ./clean-git.nix {
203 inherit lib cleanSourceWith;
205 inherit (pkgs.evalPackages.buildPackages) runCommand;
208 # Some times it is handy to temporarily use a relative path between git
209 # repos. If the repos are individually cleaned this is not possible
210 # (since the cleaned version of one repo will never include the files
213 # `cleanGits` allows us to specify a root directory and any number of
214 # sub directories containing git repos.
216 # See docs/user-guide/clean-git.md for details of how to use this
217 # with `cabalProject`.
218 cleanGits = { src, gitDirs, name ? null, caller ? "cleanGits" }@args:
220 # List of filters, one for each git directory.
221 filters = builtins.map (subDir:
222 (pkgs.haskell-nix.haskellLib.cleanGit {
223 src = pkgs.haskell-nix.haskellLib.cleanSourceWith {
227 in pkgs.haskell-nix.haskellLib.cleanSourceWith {
228 inherit src name caller;
229 # Keep files that match any of the filters
230 filter = path: type: pkgs.lib.any (f: f path type) filters;
233 # Check a test component
234 check = import ./check.nix {
235 inherit stdenv lib haskellLib srcOnly;
238 # Do coverage of a package
239 coverageReport = import ./cover.nix {
240 inherit stdenv lib haskellLib pkgs;
243 # Do coverage of a project
244 projectCoverageReport = import ./cover-project.nix {
245 inherit stdenv lib haskellLib pkgs;
248 # Use `isCrossHost` to identify when we are cross compiling and
249 # the code we are producing will not run on the build system
250 # without an emulator.
251 # In most cases we do not want to treat musl as a cross compiler.
252 # For instance when building ghc we want to include ghci.
253 isCrossHost = stdenv.hostPlatform != stdenv.buildPlatform
254 && !(stdenv.buildPlatform.isLinux && stdenv.hostPlatform.isMusl && stdenv.buildPlatform.linuxArch == stdenv.hostPlatform.linuxArch);
255 # This is the same as isCrossHost but for use when building ghc itself
256 isCrossTarget = stdenv.targetPlatform != stdenv.hostPlatform
257 && !(stdenv.hostPlatform.isLinux && stdenv.targetPlatform.isMusl && stdenv.hostPlatform.linuxArch == stdenv.targetPlatform.linuxArch);
258 # Native musl build-host-target combo
259 isNativeMusl = stdenv.hostPlatform.isMusl
260 && stdenv.buildPlatform == stdenv.hostPlatform
261 && stdenv.hostPlatform == stdenv.targetPlatform;
263 # Takes a version number or attr set of arguments (for cabalProject)
264 # and converts it to an attr set of arguments. This allows
265 # the use of "1.0.0.0" or { version = "1.0.0.0"; ... }
266 versionOrArgsToArgs = versionOrArgs:
267 if lib.isAttrs versionOrArgs
269 else { version = versionOrArgs; };
271 # Find the resolver in the stack.yaml file and fetch it if a sha256 value is provided
272 fetchResolver = import ./fetch-resolver.nix {
273 inherit (pkgs.evalPackages) pkgs;
276 inherit (import ./cabal-project-parser.nix {
278 }) parseIndexState parseSourceRepositoryPackages parseRepositories parseSourceRepositoryPackageBlock parseRepositoryBlock;
281 cabalToNixpkgsLicense = import ./spdx/cabal.nix pkgs;
283 # This function is like
284 # `src + (if subDir == "" then "" else "/" + subDir)`
285 # however when `includeSiblings` is set it maintains
286 # `src.origSrc` if there is one and instead adds to
287 # `src.origSubDir`. It uses `cleanSourceWith` when possible
288 # to keep `cleanSourceWith` support in the result.
289 appendSubDir = { src, subDir, includeSiblings ? false }:
293 haskellLib.cleanSourceWith {
294 inherit src subDir includeSiblings;
297 # Givin a `src` split it into a `root` path (based on `src.origSrc` if
298 # present) and `subDir` (based on `src.origSubDir). The
299 # `root` will still use the `filter` of `src` if there was one.
300 rootAndSubDir = src: rec {
301 subDir = src.origSubDir or "";
304 then src # if there was no subdir use the original src
306 # Use `cleanSourceWith` to make sure the `filter` is still used
307 if src ? origSrc && src ? filter
308 then haskellLib.cleanSourceWith {
309 name = src.name or "source" + "-root";
311 # Not passing src.origSubDir so that the result points `origSrc`
312 inherit (src) filter;
314 else src.origSrc or src; # If there is a subDir and origSrc (but no filter) use origSrc
317 # Run evalModules passing the project function argument (m) as a module along with
318 # the the a projectType module (../modules/cabal-project.nix or ../modules/stack-project.nix).
319 # The resulting config is then passed to the project function's implementation.
320 evalProjectModule = projectType: m: f:
323 modules = (if builtins.isList m then m else [m]) ++ [
324 # Include ../modules/cabal-project.nix or ../modules/stack-project.nix
325 (import ../modules/project-common.nix)
327 # Pass the pkgs and the buildProject to the modules
328 ({ config, lib, ... }: {
331 # to make it easy to depends on build packages in, eg., shell definition:
332 inherit (project) buildProject;
334 inherit (project) hsPkgs;
340 # Converts from a `compoent.depends` value to a library derivation.
341 # In the case of sublibs the `depends` value should already be the derivation.
342 dependToLib = d: d.components.library or d;
344 projectOverlays = import ./project-overlays.nix {
345 inherit lib haskellLib;
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list