Skip to content

Commit

Permalink
pkgs/top-level: introduce configs argument and marry `nixpkgs.confi…
Browse files Browse the repository at this point in the history
…g` of NixOS to it

This types `nixpkgs.config` of NixOS with `types.opaque` type and applies the
resulting evaluated value to the newly introduced `configs` argument of `pkgs`.

The new `configs` argument is like the old `config` argument (still available for
convenience) but a list.

This design was chosen because we can't just make a submodule out of
`pkgs/top-level/config.nix` in NixOS because

- firstly, we would have to duplicate all the magic `pkgs/top-level/default.nix`
  does to `config` in NixOS,

- secondly, in principle, we might not have all the arguments needed by
  `pkgs/top-level/config.nix` in NixOS because some of them can be
  computed internally by `pkgs` (this is not a problem now
  but it will be a problem in use-flags patchset that comes after), thus all
  of those computations will need to be duplicated too,

- thirdly, doing it this way keeps NixOS and pkgs separated, so that, in
  principle, one could replace NixOS with an alternative thing without duplicating
  all of the above once again and/or one could use separate module and type
  systems between NixOS and pkgs (`types.opaque` is trivial to
  implement in any type system and pkgs can use "types-simple" of NixOS#37252 today,
  if we were to wish it so).

Note that since this design removes the need to do any preprocessing of
`nixpkgs.config` in NixOS all the ad-hoc merging code was removed. Yay!
  • Loading branch information
oxij committed Mar 9, 2019
1 parent 4bee532 commit 9ab9e2a
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 68 deletions.
41 changes: 3 additions & 38 deletions nixos/modules/misc/nixpkgs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,6 @@ let
cfg = config.nixpkgs;
opt = options.nixpkgs;

isConfig = x:
builtins.isAttrs x || lib.isFunction x;

optCall = f: x:
if lib.isFunction f
then f x
else f;

mergeConfig = lhs_: rhs_:
let
lhs = optCall lhs_ { inherit pkgs; };
rhs = optCall rhs_ { inherit pkgs; };
in
lhs // rhs //
optionalAttrs (lhs ? packageOverrides) {
packageOverrides = pkgs:
optCall lhs.packageOverrides pkgs //
optCall (attrByPath ["packageOverrides"] ({}) rhs) pkgs;
} //
optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides = pkgs:
optCall lhs.perlPackageOverrides pkgs //
optCall (attrByPath ["perlPackageOverrides"] ({}) rhs) pkgs;
};

configType = mkOptionType {
name = "nixpkgs-config";
description = "nixpkgs config";
check = x:
let traceXIfNot = c:
if c x then true
else lib.traceSeqN 1 x false;
in traceXIfNot isConfig;
merge = args: fold (def: mergeConfig def.value) {};
};

overlayType = mkOptionType {
name = "nixpkgs-overlay";
description = "nixpkgs overlay";
Expand All @@ -56,7 +20,8 @@ let
};

defaultPkgs = import ../../.. {
inherit (cfg) config overlays localSystem crossSystem;
configs = cfg.config;
inherit (cfg) overlays localSystem crossSystem;
};

finalPkgs = if opt.pkgs.isDefined then cfg.pkgs.appendOverlays cfg.overlays else defaultPkgs;
Expand Down Expand Up @@ -113,7 +78,7 @@ in
''
{ allowBroken = true; allowUnfree = true; }
'';
type = configType;
type = types.opaque;
description = ''
The configuration of the Nix Packages collection. (For
details, see the Nixpkgs documentation.) It allows you to set
Expand Down
6 changes: 6 additions & 0 deletions pkgs/top-level/config.nix
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ let
internal = true;
};

unknowns = mkOption {
type = types.attrsOf (types.uniq types.unspecified);
default = {};
internal = true;
};

/* Config options */

inHydra = mkMeta {
Expand Down
56 changes: 35 additions & 21 deletions pkgs/top-level/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
, # The system packages will ultimately be run on.
crossSystem ? localSystem

, # Allow a configuration attribute set to be passed in as an argument.
config ? {}
, # List of configuration modules to apply.
configs ? []

, # List of overlays layers used to extend Nixpkgs.
overlays ? []
Expand All @@ -41,45 +41,59 @@
} @ args:

let # Rename the function arguments
config0 = config;
crossSystem0 = crossSystem;

in let
lib = import ../../lib;

# Allow both:
# { /* the config */ } and
# { pkgs, ... } : { /* the config */ }
config1 =
if lib.isFunction config0
then config0 { inherit pkgs; }
else config0;

# From a minimum of `system` or `config` (actually a target triple, *not*
# nixpkgs configuration), infer the other one and platform as needed.
localSystem = lib.systems.elaborate (
# Allow setting the platform in the config file. This take precedence over
# the inferred platform, but not over an explicitly passed-in one.
builtins.intersectAttrs { platform = null; } config1
builtins.intersectAttrs { platform = null; } config
// args.localSystem);

crossSystem = if crossSystem0 == null then localSystem
else lib.systems.elaborate crossSystem0;

# Massage e into a NixOS module.
mkModule = e: { options, ... }@args:
let
# We need all this stuff only because we want to support unknown options,
# without them this can be simplified a lot.
unify = file: value: lib.unifyModuleSyntax file file (lib.applyIfFunction file value args);

fake = "nixpkgs.configs element";
module =
if lib.isFunction e then unify fake e # { ... }: config
else if lib.isAttrs e then
(if e ? file && e ? value then unify e.file e.value # types.opaque
else unify fake e) # plain config
else unify (toString e) (import e); # path

# a bit of magic to move all options unknown to the ./config.nix
# under "unknowns" option so that the module checker won't complain
# FIXME: remove this eventually
configWithoutUnknowns = builtins.intersectAttrs options module.config // {
unknowns = lib.filterAttrs (n: v: !(options ? ${n})) module.config;
};
in module // {
config = configWithoutUnknowns;
};

# Eval configs.
configEval = lib.evalModules {
modules = [
{ _module.args = { inherit pkgs; }; }
./config.nix
({ options, ... }: {
_file = "nixpkgs.config";
# filter-out known options, FIXME: remove this eventually
config = builtins.intersectAttrs options config1;
})
];
] ++ map mkModule configs;
};

# take all the rest as-is
config = lib.showWarnings configEval.config.warnings
(config1 // builtins.removeAttrs configEval.config [ "_module" ]);
# Do the reverse of configWithoutUnknowns.
configWithUnknowns = configEval.config // configEval.config.unknowns;

config = lib.showWarnings configEval.config.warnings configWithUnknowns;

# A few packages make a new package set to draw their dependencies from.
# (Currently to get a cross tool chain, or forced-i686 package.) Rather than
Expand Down
22 changes: 13 additions & 9 deletions pkgs/top-level/impure.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@ let
# Return ‘x’ if it evaluates, or ‘def’ if it throws an exception.
try = x: def: let res = tryEval x; in if res.success then res.value else def;

configFile = getEnv "NIXPKGS_CONFIG";
configFile = getEnv "NIXPKGS_CONFIG";
configFile2 = homeDir + "/.config/nixpkgs/config.nix";
configFile3 = homeDir + "/.nixpkgs/config.nix"; # obsolete

config_ =
if configFile != "" && pathExists configFile then import configFile
else if homeDir != "" && pathExists configFile2 then import configFile2
else if homeDir != "" && pathExists configFile3 then import configFile3
else {};
mkConfigs = config:
if config != null then [ { file = "nixpkgs.config-argument"; value = config; } ]
else if configFile != "" && pathExists configFile then [ configFile ]
else if homeDir != "" && pathExists configFile2 then [ configFile2 ]
else if homeDir != "" && pathExists configFile3 then [ configFile3 ]
else [];

isDir = path: pathExists (path + "/.");
pathOverlays = try (toString <nixpkgs-overlays>) "";
Expand Down Expand Up @@ -69,7 +70,10 @@ in

, # Fallback: The contents of the configuration file found at $NIXPKGS_CONFIG or
# $HOME/.config/nixpkgs/config.nix.
config ? config_
config ? null

, # This is what actually gets evaluated for config.
configs ? mkConfigs config

, # Overlays are used to extend Nixpkgs collection with additional
# collections of packages. These collection of packages are part of the
Expand All @@ -83,8 +87,8 @@ in
# not be passed.
assert args ? localSystem -> !(args ? system || args ? platform);

import ./. (removeAttrs args [ "system" "platform" ] // {
inherit config overlays crossSystem;
import ./. (removeAttrs args [ "system" "platform" "config" ] // {
inherit configs overlays crossSystem;
# Fallback: Assume we are building packages on the current (build, in GNU
# Autotools parlance) system.
localSystem = (if args ? localSystem then {}
Expand Down

0 comments on commit 9ab9e2a

Please sign in to comment.