summary refs log tree commit diff
path: root/pkgs/test/nixpkgs-check-by-name/tests/mock-nixpkgs.nix
blob: 01bb27a480388209bff21b188d81ba6848b83c67 (plain) (blame)
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
/*
This file returns a mocked version of Nixpkgs' default.nix for testing purposes.
It does not depend on Nixpkgs itself for the sake of simplicity.

It takes one attribute as an argument:
- `root`: The root of Nixpkgs to read other files from, including:
  - `./pkgs/by-name`: The `pkgs/by-name` directory to test
  - `./all-packages.nix`: A file containing an overlay to mirror the real `pkgs/top-level/all-packages.nix`.
    This allows adding overrides on top of the auto-called packages in `pkgs/by-name`.

It returns a Nixpkgs-like function that can be auto-called and evaluates to an attribute set.
*/
{
  root,
}:
# The arguments for the Nixpkgs function
{
  # Passed by the checker to modify `callPackage`
  overlays ? [],
  # Passed by the checker to make sure a real Nixpkgs isn't influenced by impurities
  config ? {},
}:
let

  # Simplified versions of lib functions
  lib = {
    fix = f: let x = f x; in x;

    extends = overlay: f: final:
      let
        prev = f final;
      in
      prev // overlay final prev;

    callPackageWith = autoArgs: fn: args:
      let
        f = if builtins.isFunction fn then fn else import fn;
        fargs = builtins.functionArgs f;
        allArgs = builtins.intersectAttrs fargs autoArgs // args;
      in
      f allArgs;

    isDerivation = value: value.type or null == "derivation";
  };

  # The base fixed-point function to populate the resulting attribute set
  pkgsFun = self: {
    inherit lib;
    callPackage = lib.callPackageWith self;
    someDrv = { type = "derivation"; };
  };

  baseDirectory = root + "/pkgs/by-name";

  # Generates { <name> = <file>; } entries mapping package names to their `package.nix` files in `pkgs/by-name`.
  # Could be more efficient, but this is only for testing.
  autoCalledPackageFiles =
    let
      entries = builtins.readDir baseDirectory;

      namesForShard = shard:
        if entries.${shard} != "directory" then
          # Only README.md is allowed to be a file, but it's not this code's job to check for that
          { }
        else
          builtins.mapAttrs
            (name: _: baseDirectory + "/${shard}/${name}/package.nix")
            (builtins.readDir (baseDirectory + "/${shard}"));

    in
    builtins.foldl'
      (acc: el: acc // el)
      { }
      (map namesForShard (builtins.attrNames entries));

  # Turns autoCalledPackageFiles into an overlay that `callPackage`'s all of them
  autoCalledPackages = self: super:
    {
      # Needed to be able to detect empty arguments in all-packages.nix
      # See a more detailed description in pkgs/top-level/by-name-overlay.nix
      _internalCallByNamePackageFile = file: self.callPackage file { };
    }
    // builtins.mapAttrs
      (name: self._internalCallByNamePackageFile)
      autoCalledPackageFiles;

  # A list optionally containing the `all-packages.nix` file from the test case as an overlay
  optionalAllPackagesOverlay =
    if builtins.pathExists (root + "/all-packages.nix") then
      [ (import (root + "/all-packages.nix")) ]
    else
      [ ];

  # All the overlays in the right order, including the user-supplied ones
  allOverlays =
    [
      autoCalledPackages
    ]
    ++ optionalAllPackagesOverlay
    ++ overlays;

  # Apply all the overlays in order to the base fixed-point function pkgsFun
  f = builtins.foldl' (f: overlay: lib.extends overlay f) pkgsFun allOverlays;
in
# Evaluate the fixed-point
lib.fix f