From cff24cc115da906508949f71b892ac0f7b6a5ddc Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Thu, 26 Sep 2024 18:31:39 +0200 Subject: [PATCH 1/6] lib/modules: Improve error when loading a flake as a module --- lib/modules.nix | 111 ++++++++++++++++++++++++++++++++++++++++--- lib/tests/modules.sh | 5 +- 2 files changed, 108 insertions(+), 8 deletions(-) diff --git a/lib/modules.nix b/lib/modules.nix index 381480a1a..3472085a7 100644 --- a/lib/modules.nix +++ b/lib/modules.nix @@ -354,12 +354,7 @@ let else if m._type == "if" || m._type == "override" then loadModule args fallbackFile fallbackKey { config = m; } else - throw ( - "Could not load a value as a module, because it is of type ${lib.strings.escapeNixString m._type}" - + optionalString (fallbackFile != unknownModule) ", in file ${toString fallbackFile}." - + optionalString (m._type == "configuration") " If you do intend to import this configuration, please only import the modules that make up the configuration. You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules.\nWhile loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice." - # Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line. - ) + throw (messages.not_a_module { inherit fallbackFile; value = m; _type = m._type; expectedClass = class; }) else if isList m then let defs = [{ file = fallbackFile; value = m; }]; in throw "Module imports can't be nested lists. Perhaps you meant to remove one level of lists? Definitions: ${showDefs defs}" @@ -1450,6 +1445,110 @@ let collectModules = collectModules null; }; + /** + Error messages produced by the module system. + + We factor these out to improve the flow when reading the code. + + Functions in `messages` that produce error messages are spelled in + lower_snake_case. This goes against the convention in order to make the + error message implementation more readable, and to visually distinguish + them from other functions in the module system. + */ + messages = let + inherit (lib.strings) concatMapStringsSep escapeNixString trim; + /** "" or ", in file FOO" */ + into_fallback_file_maybe = file: + optionalString + (file != null && file != unknownModule) + ", while trying to load a module into ${toString file}"; + + /** Format text with one line break between each list item. */ + lines = concatMapStringsSep "\n" trim; + + /** Format text with two line break between each list item. */ + paragraphs = concatMapStringsSep "\n\n" trim; + + /** + ``` + optionalMatch + { foo = "Foo result"; + bar = "Bar result"; + } "foo" + == [ "Foo result" ] + + optionalMatch { foo = "Foo"; } "baz" == [ ] + + optionalMatch { foo = "Foo"; } true == [ ] + ``` + */ + optionalMatch = cases: value: + if isString value && cases?${value} + then [ cases.${value} ] + else []; + + # esc = builtins.fromJSON "\"\\u001b\""; + esc = builtins.fromJSON "\"\\u001b\""; + # Bold purple for warnings + warn = s: "${esc}[1;35m${s}${esc}[0m"; + # Bold green for suggestions + good = s: "${esc}[1;32m${s}${esc}[0m"; + # Bold, default color for code + code = s: "${esc}[1m${s}${esc}[0m"; + + in { + + /** When load a value with a (wrong) _type as a module */ + not_a_module = { fallbackFile, value, _type, expectedClass ? null }: + paragraphs ( + [ '' + Expected a module, but found a value of type ${warn (escapeNixString _type)}${into_fallback_file_maybe fallbackFile}. + A module is typically loaded by adding it the ${code "imports = [ ... ];"} attribute of an existing module, or in the ${code "modules = [ ... ];"} argument of various functions. + Please make sure that each of the list items is a module, and not a different kind of value. + '' + ] + ++ (optionalMatch + { + "configuration" = trim '' + If you really mean to import this configuration, instead please only import the modules that make up the configuration. + You may have to create a `let` binding, file or attribute to give yourself access to the relevant modules. + While loading a configuration into the module system is a very sensible idea, it can not be done cleanly in practice. + ''; + # ^^ Extended explanation: That's because a finalized configuration is more than just a set of modules. For instance, it has its own `specialArgs` that, by the nature of `specialArgs` can't be loaded through `imports` or the the `modules` argument. So instead, we have to ask you to extract the relevant modules and use those instead. This way, we keep the module system comparatively simple, and hopefully avoid a bad surprise down the line. + + "flake" = lines + ([(trim '' + Perhaps you forgot to select an attribute name? + Instead of, for example, + ${warn "inputs.someflake"} + you need to write something like + ${warn "inputs.someflake"}${ + if expectedClass == null + then good ".modules.someApp.default" + else good ".modules.${expectedClass}.default" + + } + '')] + ++ optionalMatch + { # We'll no more than 5 custom suggestions here. + # Please switch to `.modules.${class}` in your Module System application. + "nixos" = trim '' + or + ${warn "inputs.someflake"}${good ".nixosModules.default"} + ''; + "darwin" = trim '' + or + ${warn "inputs.someflake"}${good ".darwinModules.default"} + ''; + } + expectedClass + ); + } + _type + ) + ); + }; + in private // { diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index 685856f16..999e105f4 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -534,9 +534,10 @@ checkConfigError 'The module .*/module-class-is-darwin.nix was imported into nix checkConfigError 'A submoduleWith option is declared multiple times with conflicting class values "darwin" and "nixos".' config.sub.mergeFail.config ./class-check.nix # _type check -checkConfigError 'Could not load a value as a module, because it is of type "flake", in file .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix +checkConfigError 'Expected a module, but found a value of type .*"flake".*, while trying to load a module into .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix checkConfigOutput '^true$' "$@" config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix -checkConfigError 'Could not load a value as a module, because it is of type "configuration", in file .*/import-configuration.nix.*please only import the modules that make up the configuration.*' config ./import-configuration.nix +checkConfigError 'Expected a module, but found a value of type .*"configuration".*, while trying to load a module into .*/import-configuration.nix.' config ./import-configuration.nix +checkConfigError 'please only import the modules that make up the configuration' config ./import-configuration.nix # doRename works when `warnings` does not exist. checkConfigOutput '^1234$' config.c.d.e ./doRename-basic.nix From 0e937b4dc450a0b259a4baa867ad0597ffc02477 Mon Sep 17 00:00:00 2001 From: Artturin Date: Mon, 30 Sep 2024 18:01:28 +0300 Subject: [PATCH 2/6] lib.systems.examples: Fix deprecated attr `For android 'sdkVer' has been renamed to 'androidSdkVersion'` While doing the above rename I forgot to consider if there were still darwin platforms in `lib.systems.examples` using `sdkVer` These still fail eval, but that happened before the renaming too. `error: Unsupported sdk: 14.3` --- lib/systems/examples.nix | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/systems/examples.nix b/lib/systems/examples.nix index 971f6b873..5059f6e0c 100644 --- a/lib/systems/examples.nix +++ b/lib/systems/examples.nix @@ -256,7 +256,7 @@ rec { iphone64 = { config = "aarch64-apple-ios"; # config = "aarch64-apple-darwin14"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneOS"; useiOSPrebuilt = true; @@ -265,7 +265,7 @@ rec { iphone32 = { config = "armv7a-apple-ios"; # config = "arm-apple-darwin10"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneOS"; useiOSPrebuilt = true; @@ -274,7 +274,7 @@ rec { iphone64-simulator = { config = "x86_64-apple-ios"; # config = "x86_64-apple-darwin14"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneSimulator"; darwinPlatform = "ios-simulator"; @@ -284,7 +284,7 @@ rec { iphone32-simulator = { config = "i686-apple-ios"; # config = "i386-apple-darwin11"; - sdkVer = "14.3"; + darwinSdkVersion = "14.3"; xcodeVer = "12.3"; xcodePlatform = "iPhoneSimulator"; darwinPlatform = "ios-simulator"; From 1b8005deab371060ae851268c89b91819a5fc333 Mon Sep 17 00:00:00 2001 From: oxalica Date: Mon, 30 Sep 2024 03:02:27 -0400 Subject: [PATCH 3/6] lib.systems: fix rustTarget for WASI The corresponding Rust target name is "wasm32-wasip?", not "wasm32-unknown-wasi". --- lib/systems/default.nix | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/systems/default.nix b/lib/systems/default.nix index 40125c429..901912ed4 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -384,8 +384,17 @@ let }.${cpu.name} or cpu.name; vendor_ = final.rust.platform.vendor; # TODO: deprecate args.rustc in favour of args.rust after 23.05 is EOL. - in args.rust.rustcTarget or args.rustc.config - or "${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi.name}"}"; + in + args.rust.rustcTarget or + args.rustc.config or ( + # Rust uses `wasm32-wasip?` rather than `wasm32-unknown-wasi`. + # We cannot know which subversion does the user want, and + # currently use WASI 0.1 as default for compatibility. Custom + # users can set `rust.rustcTarget` to override it. + if final.isWasi + then "${cpu_}-wasip1" + else "${cpu_}-${vendor_}-${kernel.name}${optionalString (abi.name != "unknown") "-${abi.name}"}" + ); # The name of the rust target if it is standard, or the json file # containing the custom target spec. From 2748a513ac0b00ab60c250f5ddcfc98b4badf2a6 Mon Sep 17 00:00:00 2001 From: Julius Michaelis Date: Wed, 7 Aug 2024 21:57:39 +0900 Subject: [PATCH 4/6] lib/systems: use qemu-user package instead of custom definition --- lib/systems/default.nix | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/lib/systems/default.nix b/lib/systems/default.nix index 901912ed4..85a33af0e 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -277,25 +277,6 @@ let let selectEmulator = pkgs: let - qemu-user = pkgs.qemu.override { - smartcardSupport = false; - spiceSupport = false; - openGLSupport = false; - virglSupport = false; - vncSupport = false; - gtkSupport = false; - sdlSupport = false; - alsaSupport = false; - pulseSupport = false; - pipewireSupport = false; - jackSupport = false; - smbdSupport = false; - seccompSupport = false; - tpmSupport = false; - capstoneSupport = false; - enableDocs = false; - hostCpuTargets = [ "${final.qemuArch}-linux-user" ]; - }; wine = (pkgs.winePackagesFor "wine${toString final.parsed.cpu.bits}").minimal; in # Note: we guarantee that the return value is either `null` or a path @@ -306,7 +287,7 @@ let else if final.isWindows then "${wine}/bin/wine${optionalString (final.parsed.cpu.bits == 64) "64"}" else if final.isLinux && pkgs.stdenv.hostPlatform.isLinux && final.qemuArch != null - then "${qemu-user}/bin/qemu-${final.qemuArch}" + then "${pkgs.qemu-user}/bin/qemu-${final.qemuArch}" else if final.isWasi then "${pkgs.wasmtime}/bin/wasmtime" else if final.isMmix From 92c9b2eede0db6795dc3cca770b26e39f97d44c9 Mon Sep 17 00:00:00 2001 From: Zhaofeng Li Date: Sat, 27 May 2023 11:11:49 -0600 Subject: [PATCH 5/6] nixos/binfmt: Add option to use static emulators when available The fixBinary flag will be enabled if a static emulator is in use. --- lib/systems/default.nix | 4 ++++ lib/tests/systems.nix | 1 + 2 files changed, 5 insertions(+) diff --git a/lib/systems/default.nix b/lib/systems/default.nix index 85a33af0e..a6ceef2cc 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -296,6 +296,10 @@ let in { emulatorAvailable = pkgs: (selectEmulator pkgs) != null; + # whether final.emulator pkgs.pkgsStatic works + staticEmulatorAvailable = pkgs: final.emulatorAvailable pkgs + && (final.isLinux || final.isWasi || final.isMmix); + emulator = pkgs: if (final.emulatorAvailable pkgs) then selectEmulator pkgs diff --git a/lib/tests/systems.nix b/lib/tests/systems.nix index 03c5d6868..f5e7bdd5b 100644 --- a/lib/tests/systems.nix +++ b/lib/tests/systems.nix @@ -96,6 +96,7 @@ lib.runTests ( canExecute = null; emulator = null; emulatorAvailable = null; + staticEmulatorAvailable = null; isCompatible = null; }?${platformAttrName}; }; From 60e543d332ca2bb78adbd6d5497e3281da7ea31a Mon Sep 17 00:00:00 2001 From: Felix Stupp Date: Sat, 5 Oct 2024 14:10:14 +0000 Subject: [PATCH 6/6] lib.modules: fix test line using empty "$@" Probably a missed left over from somewhere in the commit 9420324a99a111f0602518c3707db2a91f96ec80. As can be seen in that commit where this line was introduced, "$@" was also just emptied by the last `set` call in line 169. This line is currently valid, but breaks suddenly when somewhere earlier a `set --` instruction is used in the future. Neither in commit 9420324a99a111f0602518c3707db2a91f96ec80 nor in PR https://github.com/NixOS/nixpkgs/pull/197547 have I found anything stating that this "defect" was intentional. --- lib/tests/modules.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tests/modules.sh b/lib/tests/modules.sh index 999e105f4..ad2ea44c3 100755 --- a/lib/tests/modules.sh +++ b/lib/tests/modules.sh @@ -535,7 +535,7 @@ checkConfigError 'A submoduleWith option is declared multiple times with conflic # _type check checkConfigError 'Expected a module, but found a value of type .*"flake".*, while trying to load a module into .*/module-imports-_type-check.nix' config.ok.config ./module-imports-_type-check.nix -checkConfigOutput '^true$' "$@" config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix +checkConfigOutput '^true$' config.enable ./declare-enable.nix ./define-enable-with-top-level-mkIf.nix checkConfigError 'Expected a module, but found a value of type .*"configuration".*, while trying to load a module into .*/import-configuration.nix.' config ./import-configuration.nix checkConfigError 'please only import the modules that make up the configuration' config ./import-configuration.nix