aboutsummaryrefslogtreecommitdiff
path: root/src/nix
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix')
-rw-r--r--src/nix/app.cc14
-rw-r--r--src/nix/bundle.cc2
-rw-r--r--src/nix/develop.cc4
-rw-r--r--src/nix/doctor.cc4
-rw-r--r--src/nix/eval.cc2
-rw-r--r--src/nix/flake.cc18
-rw-r--r--src/nix/flake.md4
-rw-r--r--src/nix/fmt.cc53
-rw-r--r--src/nix/fmt.md53
-rw-r--r--src/nix/profile.cc62
-rw-r--r--src/nix/run.cc8
-rw-r--r--src/nix/search.cc4
-rw-r--r--src/nix/show-derivation.cc4
13 files changed, 193 insertions, 39 deletions
diff --git a/src/nix/app.cc b/src/nix/app.cc
index 803d028f0..df7303e15 100644
--- a/src/nix/app.cc
+++ b/src/nix/app.cc
@@ -35,7 +35,7 @@ struct InstallableDerivedPath : Installable
/**
* Return the rewrites that are needed to resolve a string whose context is
- * included in `dependencies`
+ * included in `dependencies`.
*/
StringPairs resolveRewrites(Store & store, const BuiltPaths dependencies)
{
@@ -51,7 +51,7 @@ StringPairs resolveRewrites(Store & store, const BuiltPaths dependencies)
}
/**
- * Resolve the given string assuming the given context
+ * Resolve the given string assuming the given context.
*/
std::string resolveString(Store & store, const std::string & toResolve, const BuiltPaths dependencies)
{
@@ -61,14 +61,18 @@ std::string resolveString(Store & store, const std::string & toResolve, const Bu
UnresolvedApp Installable::toApp(EvalState & state)
{
- auto [cursor, attrPath] = getCursor(state);
+ auto cursor = getCursor(state);
+ auto attrPath = cursor->getAttrPath();
auto type = cursor->getAttr("type")->getString();
+ std::string expected = !attrPath.empty() && attrPath[0] == "apps" ? "app" : "derivation";
+ if (type != expected)
+ throw Error("attribute '%s' should have type '%s'", cursor->getAttrPathStr(), expected);
+
if (type == "app") {
auto [program, context] = cursor->getAttr("program")->getStringWithContext();
-
std::vector<StorePathWithOutputs> context2;
for (auto & [path, name] : context)
context2.push_back({path, {name}});
@@ -101,7 +105,7 @@ UnresolvedApp Installable::toApp(EvalState & state)
}
else
- throw Error("attribute '%s' has unsupported type '%s'", attrPath, type);
+ throw Error("attribute '%s' has unsupported type '%s'", cursor->getAttrPathStr(), type);
}
// FIXME: move to libcmd
diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc
index 7ed558dee..81fb8464a 100644
--- a/src/nix/bundle.cc
+++ b/src/nix/bundle.cc
@@ -9,7 +9,7 @@ using namespace nix;
struct CmdBundle : InstallableCommand
{
- std::string bundler = "github:matthewbauer/nix-bundle";
+ std::string bundler = "github:NixOS/bundlers";
std::optional<Path> outLink;
CmdBundle()
diff --git a/src/nix/develop.cc b/src/nix/develop.cc
index d2f9b5a6a..7fc74d34e 100644
--- a/src/nix/develop.cc
+++ b/src/nix/develop.cc
@@ -204,10 +204,10 @@ static StorePath getDerivationEnvironment(ref<Store> store, ref<Store> evalStore
output.second = DerivationOutput::Deferred { };
drv.env[output.first] = "";
}
- auto h0 = hashDerivationModulo(*evalStore, drv, true);
- const Hash & h = h0.requireNoFixedNonDeferred();
+ auto hashesModulo = hashDerivationModulo(*evalStore, drv, true);
for (auto & output : drv.outputs) {
+ Hash h = hashesModulo.hashes.at(output.first);
auto outPath = store->makeOutputPath(output.first, h, drv.name);
output.second = DerivationOutput::InputAddressed {
.path = outPath,
diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc
index 4f3003448..ea87e3d87 100644
--- a/src/nix/doctor.cc
+++ b/src/nix/doctor.cc
@@ -24,12 +24,12 @@ std::string formatProtocol(unsigned int proto)
}
bool checkPass(const std::string & msg) {
- logger->log(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg);
+ notice(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg);
return true;
}
bool checkFail(const std::string & msg) {
- logger->log(ANSI_RED "[FAIL] " ANSI_NORMAL + msg);
+ notice(ANSI_RED "[FAIL] " ANSI_NORMAL + msg);
return false;
}
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index 8cd04d5fe..733b93661 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -16,7 +16,7 @@ struct CmdEval : MixJSON, InstallableCommand
std::optional<std::string> apply;
std::optional<Path> writeTo;
- CmdEval()
+ CmdEval() : InstallableCommand(true /* supportReadOnlyMode */)
{
addFlag({
.longName = "raw",
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 47a380238..04b23ed0f 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -463,7 +463,7 @@ struct CmdFlakeCheck : FlakeCommand
for (auto & attr : *v.attrs) {
std::string name(attr.name);
- if (name != "path" && name != "description")
+ if (name != "path" && name != "description" && name != "welcomeText")
throw Error("template '%s' has unsupported attribute '%s'", attrPath, name);
}
} catch (Error & e) {
@@ -508,6 +508,7 @@ struct CmdFlakeCheck : FlakeCommand
name == "defaultBundler" ? "bundlers.<system>.default" :
name == "overlay" ? "overlays.default" :
name == "devShell" ? "devShells.<system>.default" :
+ name == "nixosModule" ? "nixosModules.default" :
"";
if (replacement != "")
warn("flake output attribute '%s' is deprecated; use '%s' instead", name, replacement);
@@ -527,6 +528,16 @@ struct CmdFlakeCheck : FlakeCommand
}
}
+ else if (name == "formatter") {
+ state->forceAttrs(vOutput, pos);
+ for (auto & attr : *vOutput.attrs) {
+ checkSystemName(attr.name, *attr.pos);
+ checkApp(
+ fmt("%s.%s", name, attr.name),
+ *attr.value, *attr.pos);
+ }
+ }
+
else if (name == "packages" || name == "devShells") {
state->forceAttrs(vOutput, pos);
for (auto & attr : *vOutput.attrs) {
@@ -704,7 +715,7 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand
defaultTemplateAttrPathsPrefixes,
lockFlags);
- auto [cursor, attrPath] = installable.getCursor(*evalState);
+ auto cursor = installable.getCursor(*evalState);
auto templateDirAttr = cursor->getAttr("path");
auto templateDir = templateDirAttr->getString();
@@ -1010,6 +1021,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
|| (attrPath.size() == 1 && (
attrPath[0] == "defaultPackage"
|| attrPath[0] == "devShell"
+ || attrPath[0] == "formatter"
|| attrPath[0] == "nixosConfigurations"
|| attrPath[0] == "nixosModules"
|| attrPath[0] == "defaultApp"
@@ -1026,7 +1038,7 @@ struct CmdFlakeShow : FlakeCommand, MixJSON
}
else if (
- (attrPath.size() == 2 && (attrPath[0] == "defaultPackage" || attrPath[0] == "devShell"))
+ (attrPath.size() == 2 && (attrPath[0] == "defaultPackage" || attrPath[0] == "devShell" || attrPath[0] == "formatter"))
|| (attrPath.size() == 3 && (attrPath[0] == "checks" || attrPath[0] == "packages" || attrPath[0] == "devShells"))
)
{
diff --git a/src/nix/flake.md b/src/nix/flake.md
index d59915eeb..7d179a6c4 100644
--- a/src/nix/flake.md
+++ b/src/nix/flake.md
@@ -177,8 +177,8 @@ Currently the `type` attribute can be one of the following:
attribute `url`.
In URL form, the schema must be `http://`, `https://` or `file://`
- URLs and the extension must be `.zip`, `.tar`, `.tar.gz`, `.tar.xz`,
- `.tar.bz2` or `.tar.zst`.
+ URLs and the extension must be `.zip`, `.tar`, `.tgz`, `.tar.gz`,
+ `.tar.xz`, `.tar.bz2` or `.tar.zst`.
* `github`: A more efficient way to fetch repositories from
GitHub. The following attributes are required:
diff --git a/src/nix/fmt.cc b/src/nix/fmt.cc
new file mode 100644
index 000000000..e5d44bd38
--- /dev/null
+++ b/src/nix/fmt.cc
@@ -0,0 +1,53 @@
+#include "command.hh"
+#include "run.hh"
+
+using namespace nix;
+
+struct CmdFmt : SourceExprCommand {
+ std::vector<std::string> args;
+
+ CmdFmt() { expectArgs({.label = "args", .handler = {&args}}); }
+
+ std::string description() override {
+ return "reformat your code in the standard style";
+ }
+
+ std::string doc() override {
+ return
+ #include "fmt.md"
+ ;
+ }
+
+ Category category() override { return catSecondary; }
+
+ Strings getDefaultFlakeAttrPaths() override {
+ return Strings{"formatter." + settings.thisSystem.get()};
+ }
+
+ Strings getDefaultFlakeAttrPathPrefixes() override { return Strings{}; }
+
+ void run(ref<Store> store) {
+ auto evalState = getEvalState();
+ auto evalStore = getEvalStore();
+
+ auto installable = parseInstallable(store, ".");
+ auto app = installable->toApp(*evalState).resolve(evalStore, store);
+
+ Strings programArgs{app.program};
+
+ // Propagate arguments from the CLI
+ if (args.empty()) {
+ // Format the current flake out of the box
+ programArgs.push_back(".");
+ } else {
+ // User wants more power, let them decide which paths to include/exclude
+ for (auto &i : args) {
+ programArgs.push_back(i);
+ }
+ }
+
+ runProgramInStore(store, app.program, programArgs);
+ };
+};
+
+static auto r2 = registerCommand<CmdFmt>("fmt");
diff --git a/src/nix/fmt.md b/src/nix/fmt.md
new file mode 100644
index 000000000..1c78bb36f
--- /dev/null
+++ b/src/nix/fmt.md
@@ -0,0 +1,53 @@
+R""(
+
+# Examples
+
+With [nixpkgs-fmt](https://github.com/nix-community/nixpkgs-fmt):
+
+```nix
+# flake.nix
+{
+ outputs = { nixpkgs, self }: {
+ formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixpkgs-fmt;
+ };
+}
+```
+
+- Format the current flake: `$ nix fmt`
+
+- Format a specific folder or file: `$ nix fmt ./folder ./file.nix`
+
+With [nixfmt](https://github.com/serokell/nixfmt):
+
+```nix
+# flake.nix
+{
+ outputs = { nixpkgs, self }: {
+ formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.nixfmt;
+ };
+}
+```
+
+- Format specific files: `$ nix fmt ./file1.nix ./file2.nix`
+
+With [Alejandra](https://github.com/kamadorueda/alejandra):
+
+```nix
+# flake.nix
+{
+ outputs = { nixpkgs, self }: {
+ formatter.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.alejandra;
+ };
+}
+```
+
+- Format the current flake: `$ nix fmt`
+
+- Format a specific folder or file: `$ nix fmt ./folder ./file.nix`
+
+# Description
+
+`nix fmt` will rewrite all Nix files (\*.nix) to a canonical format
+using the formatter specified in your flake.
+
+)""
diff --git a/src/nix/profile.cc b/src/nix/profile.cc
index 1d9da087c..3a32a7b55 100644
--- a/src/nix/profile.cc
+++ b/src/nix/profile.cc
@@ -62,22 +62,21 @@ struct ProfileElement
return std::tuple(describe(), storePaths) < std::tuple(other.describe(), other.storePaths);
}
- void updateStorePaths(ref<Store> evalStore, ref<Store> store, Installable & installable)
+ void updateStorePaths(
+ ref<Store> evalStore,
+ ref<Store> store,
+ const BuiltPaths & builtPaths)
{
// FIXME: respect meta.outputsToInstall
storePaths.clear();
- for (auto & buildable : getBuiltPaths(evalStore, store, installable.toDerivedPaths())) {
+ for (auto & buildable : builtPaths) {
std::visit(overloaded {
[&](const BuiltPath::Opaque & bo) {
storePaths.insert(bo.path);
},
[&](const BuiltPath::Built & bfd) {
- // TODO: Why are we querying if we know the output
- // names already? Is it just to figure out what the
- // default one is?
- for (auto & output : store->queryDerivationOutputMap(bfd.drvPath)) {
+ for (auto & output : bfd.outputs)
storePaths.insert(output.second);
- }
},
}, buildable.raw());
}
@@ -98,19 +97,30 @@ struct ProfileManifest
auto json = nlohmann::json::parse(readFile(manifestPath));
auto version = json.value("version", 0);
- if (version != 1)
- throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version);
+ std::string sUrl;
+ std::string sOriginalUrl;
+ switch(version){
+ case 1:
+ sUrl = "uri";
+ sOriginalUrl = "originalUri";
+ break;
+ case 2:
+ sUrl = "url";
+ sOriginalUrl = "originalUrl";
+ break;
+ default:
+ throw Error("profile manifest '%s' has unsupported version %d", manifestPath, version);
+ }
for (auto & e : json["elements"]) {
ProfileElement element;
for (auto & p : e["storePaths"])
element.storePaths.insert(state.store->parseStorePath((std::string) p));
element.active = e["active"];
- if (e.value("uri", "") != "") {
- auto originalUrl = e.value("originalUrl", e["originalUri"]);
+ if (e.value(sUrl,"") != "") {
element.source = ProfileElementSource{
- parseFlakeRef(originalUrl),
- parseFlakeRef(e["uri"]),
+ parseFlakeRef(e[sOriginalUrl]),
+ parseFlakeRef(e[sUrl]),
e["attrPath"]
};
}
@@ -145,13 +155,13 @@ struct ProfileManifest
obj["active"] = element.active;
if (element.source) {
obj["originalUrl"] = element.source->originalRef.to_string();
- obj["uri"] = element.source->resolvedRef.to_string();
+ obj["url"] = element.source->resolvedRef.to_string();
obj["attrPath"] = element.source->attrPath;
}
array.push_back(obj);
}
nlohmann::json json;
- json["version"] = 1;
+ json["version"] = 2;
json["elements"] = array;
return json.dump();
}
@@ -245,6 +255,16 @@ struct ProfileManifest
}
};
+static std::map<Installable *, BuiltPaths>
+builtPathsPerInstallable(
+ const std::vector<std::pair<std::shared_ptr<Installable>, BuiltPath>> & builtPaths)
+{
+ std::map<Installable *, BuiltPaths> res;
+ for (auto & [installable, builtPath] : builtPaths)
+ res[installable.get()].push_back(builtPath);
+ return res;
+}
+
struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
{
std::string description() override
@@ -263,7 +283,9 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
{
ProfileManifest manifest(*getEvalState(), *profile);
- auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
+ auto builtPaths = builtPathsPerInstallable(
+ Installable::build2(
+ getEvalStore(), store, Realise::Outputs, installables, bmNormal));
for (auto & installable : installables) {
ProfileElement element;
@@ -278,7 +300,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile
};
}
- element.updateStorePaths(getEvalStore(), store, *installable);
+ element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]);
manifest.elements.push_back(std::move(element));
}
@@ -466,12 +488,14 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf
warn ("Use 'nix profile list' to see the current profile.");
}
- auto builtPaths = Installable::build(getEvalStore(), store, Realise::Outputs, installables, bmNormal);
+ auto builtPaths = builtPathsPerInstallable(
+ Installable::build2(
+ getEvalStore(), store, Realise::Outputs, installables, bmNormal));
for (size_t i = 0; i < installables.size(); ++i) {
auto & installable = installables.at(i);
auto & element = manifest.elements[indices.at(i)];
- element.updateStorePaths(getEvalStore(), store, *installable);
+ element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()]);
}
updateProfile(manifest.build(store));
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 033263c36..25a8fa8d3 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -38,9 +38,12 @@ void runProgramInStore(ref<Store> store,
unshare(CLONE_NEWUSER) doesn't work in a multithreaded program
(which "nix" is), so we exec() a single-threaded helper program
(chrootHelper() below) to do the work. */
- auto store2 = store.dynamic_pointer_cast<LocalStore>();
+ auto store2 = store.dynamic_pointer_cast<LocalFSStore>();
- if (store2 && store->storeDir != store2->getRealStoreDir()) {
+ if (!store2)
+ throw Error("store '%s' is not a local store so it does not support command execution", store->getUri());
+
+ if (store->storeDir != store2->getRealStoreDir()) {
Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), program };
for (auto & arg : args) helperArgs.push_back(arg);
@@ -179,6 +182,7 @@ struct CmdRun : InstallableCommand
{
auto state = getEvalState();
+ lockFlags.applyNixConfig = true;
auto app = installable->toApp(*state).resolve(getEvalStore(), store);
Strings allArgs{app.program};
diff --git a/src/nix/search.cc b/src/nix/search.cc
index e9307342c..e96a85ea2 100644
--- a/src/nix/search.cc
+++ b/src/nix/search.cc
@@ -165,8 +165,8 @@ struct CmdSearch : InstallableCommand, MixJSON
}
};
- for (auto & [cursor, prefix] : installable->getCursors(*state))
- visit(*cursor, parseAttrPath(*state, prefix), true);
+ for (auto & cursor : installable->getCursors(*state))
+ visit(*cursor, cursor->getAttrPath(), true);
if (!json && !results)
throw Error("no results for the given search term(s)!");
diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc
index 0d9655732..fb46b4dbf 100644
--- a/src/nix/show-derivation.cc
+++ b/src/nix/show-derivation.cc
@@ -77,6 +77,10 @@ struct CmdShowDerivation : InstallablesCommand
outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType));
},
[&](const DerivationOutput::Deferred &) {},
+ [&](const DerivationOutput::Impure & doi) {
+ outputObj.attr("hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType));
+ outputObj.attr("impure", true);
+ },
}, output.raw());
}
}