diff --git a/src/libcmd/builtin-flake-schemas.nix b/src/libcmd/builtin-flake-schemas.nix index 28671186e0a6..0ee6d8f5ae39 100644 --- a/src/libcmd/builtin-flake-schemas.nix +++ b/src/libcmd/builtin-flake-schemas.nix @@ -13,6 +13,34 @@ in builtins.isAttrs module || builtins.isFunction module; + mkApp = system: app: { + forSystems = [ system ]; + evalChecks.isValidApp = + app ? type + && app.type == "app" + && app ? program + && builtins.isString app.program + && + builtins.removeAttrs app [ + "type" + "program" + "meta" + ] == { }; + what = "app"; + shortDescription = app.meta.description or ""; + }; + + mkPackage = isFlakeCheck: what: system: package: { + forSystems = [ system ]; + shortDescription = package.meta.description or ""; + derivationAttrPath = [ ]; + inherit what isFlakeCheck; + }; + + singleDerivationInventory = + what: isFlakeCheck: output: + self.lib.mkChildren (builtins.mapAttrs (mkPackage isFlakeCheck what) output); + schemasSchema = { version = 1; doc = '' @@ -46,33 +74,24 @@ inventory = output: self.lib.mkChildren ( - builtins.mapAttrs ( - system: apps: - let - forSystems = [ system ]; - in - { - inherit forSystems; - children = builtins.mapAttrs (appName: app: { - inherit forSystems; - evalChecks.isValidApp = - app ? type - && app.type == "app" - && app ? program - && builtins.isString app.program - && - builtins.removeAttrs app [ - "type" - "program" - "meta" - ] == { }; - what = "app"; - }) apps; - } - ) output + builtins.mapAttrs (system: apps: { + forSystems = [ system ]; + children = builtins.mapAttrs (appName: app: mkApp system app) apps; + }) output ); }; + defaultAppSchema = { + version = 1; + doc = '' + **DEPRECATED**. Use `apps..default` instead. + ''; + roles.nix-run = { }; + appendSystem = true; + defaultAttrPath = [ ]; + inventory = output: self.lib.mkChildren (builtins.mapAttrs mkApp output); + }; + packagesSchema = { version = 1; doc = '' @@ -87,6 +106,20 @@ inventory = self.lib.derivationsInventory "package" false; }; + defaultPackageSchema = { + version = 1; + doc = '' + **DEPRECATED**. Use `packages..default` instead. + ''; + roles.nix-build = { }; + roles.nix-run = { }; + roles.nix-develop = { }; + roles.nix-search = { }; + appendSystem = true; + defaultAttrPath = [ ]; + inventory = singleDerivationInventory "package" false; + }; + ociImagesSchema = { version = 1; doc = '' @@ -167,6 +200,17 @@ inventory = self.lib.derivationsInventory "development environment" false; }; + devShellSchema = { + version = 1; + doc = '' + **DEPRECATED**. Use `devShells..default` instead. + ''; + roles.nix-develop = { }; + appendSystem = true; + defaultAttrPath = [ ]; + inventory = singleDerivationInventory "development environment" false; + }; + formatterSchema = { version = 1; doc = '' @@ -410,13 +454,9 @@ self.lib.mkChildren ( builtins.mapAttrs (systemType: packagesForSystem: { forSystems = [ systemType ]; - children = builtins.mapAttrs (packageName: package: { - forSystems = [ systemType ]; - shortDescription = package.meta.description or ""; - derivationAttrPath = [ ]; - inherit what; - isFlakeCheck = isFlakeCheck; - }) packagesForSystem; + children = builtins.mapAttrs ( + packageName: mkPackage isFlakeCheck what systemType + ) packagesForSystem; }) output ); }; @@ -424,10 +464,13 @@ # FIXME: distinguish between available and active schemas? schemas.schemas = schemasSchema; schemas.apps = appsSchema; + schemas.defaultApp = defaultAppSchema; schemas.packages = packagesSchema; + schemas.defaultPackage = defaultPackageSchema; schemas.legacyPackages = legacyPackagesSchema; schemas.checks = checksSchema; schemas.devShells = devShellsSchema; + schemas.devShell = devShellSchema; schemas.formatter = formatterSchema; schemas.templates = templatesSchema; schemas.hydraJobs = hydraJobsSchema; diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc index 84b6ccfa9d07..ebec82f2e30e 100644 --- a/src/libcmd/installable-flake.cc +++ b/src/libcmd/installable-flake.cc @@ -167,8 +167,11 @@ std::vector InstallableFlake::getAttrPaths(bool useDefaultAttrPath, re } }; doSchema("apps"); + doSchema("defaultApp"); doSchema("devShells"); + doSchema("devShell"); doSchema("packages"); + doSchema("defaultPackage"); doSchema("legacyPackages"); for (auto & schema : schemas) if (!schemasSeen.contains(schema.first)) diff --git a/src/nix/develop.cc b/src/nix/develop.cc index cfbb6ca1bba1..9536bf83e486 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -388,7 +388,8 @@ struct Common : InstallableCommand, MixProfile /* Substitute occurrences of output paths. */ auto outputs = buildEnvironment.vars.find("outputs"); - assert(outputs != buildEnvironment.vars.end()); + if (outputs == buildEnvironment.vars.end()) + throw Error("derivation does not have an 'outputs' attribute"); StringMap rewrites; if (buildEnvironment.providesStructuredAttrs()) { diff --git a/tests/functional/config.nix.in b/tests/functional/config.nix.in index 3ccc3d476bd2..066d29c43811 100644 --- a/tests/functional/config.nix.in +++ b/tests/functional/config.nix.in @@ -28,6 +28,7 @@ rec { eval "$buildCommand" '')]; PATH = path; + outputs = args.outputs or [ "out" ]; } // caArgs // optionalAttrs (builtins ? derivationWithMeta) { __meta = removeAttrs (args.meta or {}) ["position"]; } // removeAttrs args ["builder" "meta"]) diff --git a/tests/functional/flakes/develop.sh b/tests/functional/flakes/develop.sh index ee646860b112..0248adf49eaf 100755 --- a/tests/functional/flakes/develop.sh +++ b/tests/functional/flakes/develop.sh @@ -161,3 +161,34 @@ EOF [[ -z "$(nix develop --no-write-lock-file .#hello-structured "$TEST_HOME/flake.nix" +{ + inputs.nixpkgs.url = "$TEST_HOME/nixpkgs"; + outputs = {self, nixpkgs}: { + devShells.$system.default = (import ./config.nix).mkDerivation { + name = "hello"; + buildCommand = "set -x; mkdir \$out"; + x = "foo"; + }; + devShell.$system = (import ./config.nix).mkDerivation { + name = "hello"; + buildCommand = "set -x; mkdir \$out"; + x = "bar"; + }; + packages.$system.default = (import ./config.nix).mkDerivation { + name = "hello"; + buildCommand = "set -x; mkdir \$out"; + x = "xyzzy"; + }; + }; +} +EOF + +[[ $(nix develop . -L --command sh -c "echo \$x") == "foo" ]] +[[ $(nix develop ".#devShell.$system" -L --command sh -c "echo \$x") == "bar" ]] +sed -i "$TEST_HOME/flake.nix" -e 's/devShells/devShells2/' # remove devShells +[[ $(nix develop . -L --command sh -c "echo \$x") == "bar" ]] +sed -i "$TEST_HOME/flake.nix" -e 's/devShell/devShell2/' # remove devShell +[[ $(nix develop . -L --command sh -c "echo \$x") == "xyzzy" ]] diff --git a/tests/functional/flakes/dubious-query.sh b/tests/functional/flakes/dubious-query.sh index c147034c3dd9..114def179a8c 100644 --- a/tests/functional/flakes/dubious-query.sh +++ b/tests/functional/flakes/dubious-query.sh @@ -17,7 +17,7 @@ expectStderr 0 nix --offline build --dry-run "git+file://$repoDir?bar#foo" \ # Check that the anchor (#) is taken as a whole, not split, and throws an error. expectStderr 1 nix --offline build --dry-run "git+file://$repoDir#foo?bar" \ - | grepQuiet "error: flake 'git+file://$repoDir' does not provide attribute 'packages.$system.foo?bar', 'legacyPackages.$system.foo?bar' or 'foo?bar'" + | grepQuiet "error: flake 'git+file://$repoDir' does not provide attribute 'packages.$system.foo?bar', 'defaultPackage.$system.foo?bar', 'legacyPackages.$system.foo?bar' or 'foo?bar'" # Check that a literal `?` in the query doesn't print dubious query warning. expectStderr 0 nix --offline build --dry-run "git+file://$repoDir?#foo" \