aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2022-05-03 15:38:47 +0200
committerGitHub <noreply@github.com>2022-05-03 15:38:47 +0200
commit9489b4b7ef73ab20e8f49213d8711ca56b59107e (patch)
treed1484046123f178724d86e265b49425e2c90628b /src/nix
parent404c222444b4c8c60148ccf890cd41611f26b0a0 (diff)
parenta3c6c5b1c745a72a6a46bdf1a1de7a51a53f76b0 (diff)
Merge pull request #6449 from edolstra/outputs-spec
Allow selecting derivation outputs
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/bundle.cc4
-rw-r--r--src/nix/develop.cc1
-rw-r--r--src/nix/flake.cc2
-rw-r--r--src/nix/nix.md45
-rw-r--r--src/nix/profile-install.md7
-rw-r--r--src/nix/profile.cc29
6 files changed, 73 insertions, 15 deletions
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index 2421adf4e..2e48e4c74 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -75,10 +75,10 @@ struct CmdBundle : InstallableCommand
auto val = installable->toValue(*evalState).first;
- auto [bundlerFlakeRef, bundlerName] = parseFlakeRefWithFragment(bundler, absPath("."));
+ auto [bundlerFlakeRef, bundlerName, outputsSpec] = parseFlakeRefWithFragmentAndOutputsSpec(bundler, absPath("."));
const flake::LockFlags lockFlags{ .writeLockFile = false };
InstallableFlake bundler{this,
- evalState, std::move(bundlerFlakeRef), bundlerName,
+ evalState, std::move(bundlerFlakeRef), bundlerName, outputsSpec,
{"bundlers." + settings.thisSystem.get() + ".default",
"defaultBundler." + settings.thisSystem.get()
},
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index 7fc74d34e..1190b8348 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -507,6 +507,7 @@ struct CmdDevelop : Common, MixEnvironment
state,
installable->nixpkgsFlakeRef(),
"bashInteractive",
+ DefaultOutputs(),
Strings{},
Strings{"legacyPackages." + settings.thisSystem.get() + "."},
nixpkgsLockFlags);
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 6a34ca67b..1938ce4e6 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -724,7 +724,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
auto [templateFlakeRef, templateName] = parseFlakeRefWithFragment(templateUrl, absPath("."));
auto installable = InstallableFlake(nullptr,
- evalState, std::move(templateFlakeRef), templateName,
+ evalState, std::move(templateFlakeRef), templateName, DefaultOutputs(),
defaultTemplateAttrPaths,
defaultTemplateAttrPathsPrefixes,
lockFlags);
diff --git a/src/nix/nix.md b/src/nix/nix.md
index 0dacadee6..d48682a94 100644
--- a/src/nix/nix.md
+++ b/src/nix/nix.md
@@ -146,6 +146,51 @@ For most commands, if no installable is specified, the default is `.`,
i.e. Nix will operate on the default flake output attribute of the
flake in the current directory.
+## Derivation output selection
+
+Derivations can have multiple outputs, each corresponding to a
+different store path. For instance, a package can have a `bin` output
+that contains programs, and a `dev` output that provides development
+artifacts like C/C++ header files. The outputs on which `nix` commands
+operate are determined as follows:
+
+* You can explicitly specify the desired outputs using the syntax
+ *installable*`^`*output1*`,`*...*`,`*outputN*. For example, you can
+ obtain the `dev` and `static` outputs of the `glibc` package:
+
+ ```console
+ # nix build 'nixpkgs#glibc^dev,static'
+ # ls ./result-dev/include/ ./result-static/lib/
+ …
+ ```
+
+* You can also specify that *all* outputs should be used using the
+ syntax *installable*`^*`. For example, the following shows the size
+ of all outputs of the `glibc` package in the binary cache:
+
+ ```console
+ # nix path-info -S --eval-store auto --store https://cache.nixos.org 'nixpkgs#glibc^*'
+ /nix/store/g02b1lpbddhymmcjb923kf0l7s9nww58-glibc-2.33-123 33208200
+ /nix/store/851dp95qqiisjifi639r0zzg5l465ny4-glibc-2.33-123-bin 36142896
+ /nix/store/kdgs3q6r7xdff1p7a9hnjr43xw2404z7-glibc-2.33-123-debug 155787312
+ /nix/store/n4xa8h6pbmqmwnq0mmsz08l38abb06zc-glibc-2.33-123-static 42488328
+ /nix/store/q6580lr01jpcsqs4r5arlh4ki2c1m9rv-glibc-2.33-123-dev 44200560
+ ```
+
+* If you didn't specify the desired outputs, but the derivation has an
+ attribute `meta.outputsToInstall`, Nix will use those outputs. For
+ example, since the package `nixpkgs#libxml2` has this attribute:
+
+ ```console
+ # nix eval 'nixpkgs#libxml2.meta.outputsToInstall'
+ [ "bin" "man" ]
+ ```
+
+ a command like `nix shell nixpkgs#libxml2` will provide only those
+ two outputs by default.
+
+* Otherwise, Nix will use all outputs of the derivation.
+
# Nix stores
Most `nix` subcommands operate on a *Nix store*.
diff --git a/src/nix/profile-install.md b/src/nix/profile-install.md
index e3009491e..aed414963 100644
--- a/src/nix/profile-install.md
+++ b/src/nix/profile-install.md
@@ -20,6 +20,13 @@ R""(
# nix profile install nixpkgs/d73407e8e6002646acfdef0e39ace088bacc83da#hello
```
+* Install a specific output of a package:
+
+ ```console
+ # nix profile install nixpkgs#bash^man
+ ```
+
+
# Description
This command adds *installables* to a Nix profile.
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 52c918016..685776bec 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -22,13 +22,13 @@ struct ProfileElementSource
// FIXME: record original attrpath.
FlakeRef resolvedRef;
std::string attrPath;
- // FIXME: output names
+ OutputsSpec outputs;
bool operator < (const ProfileElementSource & other) const
{
return
- std::pair(originalRef.to_string(), attrPath) <
- std::pair(other.originalRef.to_string(), other.attrPath);
+ std::tuple(originalRef.to_string(), attrPath, outputs) <
+ std::tuple(other.originalRef.to_string(), other.attrPath, other.outputs);
}
};
@@ -42,7 +42,7 @@ struct ProfileElement
std::string describe() const
{
if (source)
- return fmt("%s#%s", source->originalRef, source->attrPath);
+ return fmt("%s#%s%s", source->originalRef, source->attrPath, printOutputsSpec(source->outputs));
StringSet names;
for (auto & path : storePaths)
names.insert(DrvName(path.name()).name);
@@ -98,7 +98,7 @@ struct ProfileManifest
auto version = json.value("version", 0);
std::string sUrl;
std::string sOriginalUrl;
- switch(version){
+ switch (version) {
case 1:
sUrl = "uri";
sOriginalUrl = "originalUri";
@@ -116,11 +116,12 @@ struct ProfileManifest
for (auto & p : e["storePaths"])
element.storePaths.insert(state.store->parseStorePath((std::string) p));
element.active = e["active"];
- if (e.value(sUrl,"") != "") {
- element.source = ProfileElementSource{
+ if (e.value(sUrl, "") != "") {
+ element.source = ProfileElementSource {
parseFlakeRef(e[sOriginalUrl]),
parseFlakeRef(e[sUrl]),
- e["attrPath"]
+ e["attrPath"],
+ e["outputs"].get<OutputsSpec>()
};
}
elements.emplace_back(std::move(element));
@@ -156,6 +157,7 @@ struct ProfileManifest
obj["originalUrl"] = element.source->originalRef.to_string();
obj["url"] = element.source->resolvedRef.to_string();
obj["attrPath"] = element.source->attrPath;
+ obj["outputs"] = element.source->outputs;
}
array.push_back(obj);
}
@@ -283,10 +285,11 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
if (auto installable2 = std::dynamic_pointer_cast<InstallableFlake>(installable)) {
// FIXME: make build() return this?
auto [attrPath, resolvedRef, drv] = installable2->toDerivation();
- element.source = ProfileElementSource{
+ element.source = ProfileElementSource {
installable2->flakeRef,
resolvedRef,
attrPath,
+ installable2->outputsSpec
};
}
@@ -443,6 +446,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
getEvalState(),
FlakeRef(element.source->originalRef),
"",
+ element.source->outputs,
Strings{element.source->attrPath},
Strings{},
lockFlags);
@@ -454,10 +458,11 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
printInfo("upgrading '%s' from flake '%s' to '%s'",
element.source->attrPath, element.source->resolvedRef, resolvedRef);
- element.source = ProfileElementSource{
+ element.source = ProfileElementSource {
installable->flakeRef,
resolvedRef,
attrPath,
+ installable->outputsSpec
};
installables.push_back(installable);
@@ -513,8 +518,8 @@ struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultPro
for (size_t i = 0; i < manifest.elements.size(); ++i) {
auto & element(manifest.elements[i]);
logger->cout("%d %s %s %s", i,
- element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath : "-",
- element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath : "-",
+ element.source ? element.source->originalRef.to_string() + "#" + element.source->attrPath + printOutputsSpec(element.source->outputs) : "-",
+ element.source ? element.source->resolvedRef.to_string() + "#" + element.source->attrPath + printOutputsSpec(element.source->outputs) : "-",
concatStringsSep(" ", store->printStorePathSet(element.storePaths)));
}
}