aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/internal-api/meson.build1
-rw-r--r--doc/manual/src/command-ref/nix-build.md5
-rw-r--r--src/libcmd/common-eval-args.cc32
-rw-r--r--src/libcmd/common-eval-args.hh22
-rw-r--r--tests/unit/libcmd/args.cc57
-rw-r--r--tests/unit/meson.build27
6 files changed, 125 insertions, 19 deletions
diff --git a/doc/internal-api/meson.build b/doc/internal-api/meson.build
index 35d8a0e5b..faa30f194 100644
--- a/doc/internal-api/meson.build
+++ b/doc/internal-api/meson.build
@@ -28,6 +28,7 @@ internal_api_docs = custom_target(
output : 'html',
install : true,
install_dir : datadir / 'doc/nix/internal-api',
+ build_always_stale : true,
)
alias_target('internal-api-html', internal_api_docs)
diff --git a/doc/manual/src/command-ref/nix-build.md b/doc/manual/src/command-ref/nix-build.md
index b548edf82..24714b2b4 100644
--- a/doc/manual/src/command-ref/nix-build.md
+++ b/doc/manual/src/command-ref/nix-build.md
@@ -14,9 +14,8 @@
# Disambiguation
-This man page describes the command `nix-build`, which is distinct from `nix
-build`. For documentation on the latter, run `nix build --help` or see `man
-nix3-build`.
+This man page describes the command `nix-build`, which is distinct from [`nix build`](./new-cli/nix3-build.md).
+For documentation on the latter, run `nix build --help` or see `man nix3-build`.
# Description
diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc
index 94a4b7922..9beea5aa2 100644
--- a/src/libcmd/common-eval-args.cc
+++ b/src/libcmd/common-eval-args.cc
@@ -164,28 +164,30 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
return res.finish();
}
-SourcePath lookupFileArg(EvalState & state, std::string_view s)
+SourcePath lookupFileArg(EvalState & state, std::string_view fileArg)
{
- if (EvalSettings::isPseudoUrl(s)) {
- auto storePath = fetchers::downloadTarball(
- state.store, EvalSettings::resolvePseudoUrl(s), "source", false).tree.storePath;
+ if (EvalSettings::isPseudoUrl(fileArg)) {
+ auto const url = EvalSettings::resolvePseudoUrl(fileArg);
+ auto const downloaded = fetchers::downloadTarball(
+ state.store,
+ url,
+ /* name */ "source",
+ /* locked */ false
+ );
+ StorePath const storePath = downloaded.tree.storePath;
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
- }
-
- else if (s.starts_with("flake:")) {
+ } else if (fileArg.starts_with("flake:")) {
experimentalFeatureSettings.require(Xp::Flakes);
- auto flakeRef = parseFlakeRef(std::string(s.substr(6)), {}, true, false);
+ static constexpr size_t FLAKE_LEN = std::string_view("flake:").size();
+ auto flakeRef = parseFlakeRef(std::string(fileArg.substr(FLAKE_LEN)), {}, true, false);
auto storePath = flakeRef.resolve(state.store).fetchTree(state.store).first.storePath;
return state.rootPath(CanonPath(state.store->toRealPath(storePath)));
- }
-
- else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
- Path p(s.substr(1, s.size() - 2));
+ } else if (fileArg.size() > 2 && fileArg.at(0) == '<' && fileArg.at(fileArg.size() - 1) == '>') {
+ Path p(fileArg.substr(1, fileArg.size() - 2));
return state.findFile(p);
+ } else {
+ return state.rootPath(CanonPath::fromCwd(fileArg));
}
-
- else
- return state.rootPath(CanonPath::fromCwd(s));
}
}
diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh
index 6359b2579..08a4b65e4 100644
--- a/src/libcmd/common-eval-args.hh
+++ b/src/libcmd/common-eval-args.hh
@@ -28,6 +28,26 @@ private:
std::map<std::string, std::string> autoArgs;
};
-SourcePath lookupFileArg(EvalState & state, std::string_view s);
+/** @brief Resolve an argument that is generally a file, but could be something that
+ * is easy to resolve to a file, like a <lookup path> or a tarball URL.
+ *
+ * In particular, this will resolve and fetch pseudo-URLs starting with
+ * @c channel:, flakerefs starting with @c flake:, and anything that
+ * @ref nix::fetchers::downloadTarball() can take.
+ *
+ * Non-absolute files are looked up relative to the current directory(?)
+ * FIXME: the process's current directory or EvalState's current directory?
+ *
+ * @param state The nix::EvalState to base settings, store, and nixPath from.
+ *
+ * @param fileArg The the path-ish to resolve.
+ *
+ * @return A nix::SourcePath to the resolved and fetched file.
+ *
+ * @exception nix::FileTransferError from nix::fetchers::downloadTarball(). Probably others.
+ *
+ * @exception nix::ThrownError for failed search path lookup. Probably others.
+ */
+SourcePath lookupFileArg(EvalState & state, std::string_view fileArg);
}
diff --git a/tests/unit/libcmd/args.cc b/tests/unit/libcmd/args.cc
new file mode 100644
index 000000000..73550dacf
--- /dev/null
+++ b/tests/unit/libcmd/args.cc
@@ -0,0 +1,57 @@
+#include <iostream>
+#include <memory>
+#include <string_view>
+
+#include <boost/core/demangle.hpp>
+#include <gtest/gtest.h>
+
+#include "common-eval-args.hh"
+#include "eval.hh"
+#include "filetransfer.hh"
+#include "shared.hh"
+#include "store-api.hh"
+#include "util.hh"
+
+constexpr std::string_view INVALID_CHANNEL = "channel:example";
+constexpr std::string_view CHANNEL_URL = "https://nixos.org/channels/example/nixexprs.tar.xz";
+
+namespace nix
+{
+
+TEST(Arguments, lookupFileArg) {
+ initNix();
+ initGC();
+
+ std::string const unitDataPath = getEnv("_NIX_TEST_UNIT_DATA").value();
+ // Meson should be allowed to pass us a relative path here tbh.
+ auto const canonDataPath = CanonPath::fromCwd(unitDataPath);
+
+ std::string const searchPathElem = fmt("example=%s", unitDataPath);
+
+ SearchPath searchPath;
+ searchPath.elements.push_back(SearchPath::Elem::parse(searchPathElem));
+
+ auto store = openStore("dummy://");
+ auto statePtr = std::make_shared<EvalState>(searchPath, store, store);
+ auto & state = *statePtr;
+
+ SourcePath const foundUnitData = lookupFileArg(state, "<example>");
+ EXPECT_EQ(foundUnitData.path, canonDataPath);
+
+ // lookupFileArg should not resolve <search paths> if anything else is before or after it.
+ SourcePath const yepEvenSpaces = lookupFileArg(state, " <example>");
+ EXPECT_EQ(yepEvenSpaces.path, CanonPath::fromCwd(" <example>"));
+ EXPECT_EQ(lookupFileArg(state, "<example>/nixos").path, CanonPath::fromCwd("<example>/nixos"));
+
+ try {
+ lookupFileArg(state, INVALID_CHANNEL);
+ } catch (FileTransferError const & ex) {
+ std::string_view const msg(ex.what());
+ EXPECT_NE(msg.find(CHANNEL_URL), msg.npos);
+ }
+
+ SourcePath const normalFile = lookupFileArg(state, unitDataPath);
+ EXPECT_EQ(normalFile.path, canonDataPath);
+}
+
+}
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index a997a0d56..35a11a5d3 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -212,3 +212,30 @@ test(
protocol : 'gtest',
verbose : true,
)
+
+libcmd_tester = executable(
+ 'liblixcmd-tests',
+ files('libcmd/args.cc'),
+ dependencies : [
+ liblixcmd,
+ liblixutil,
+ liblixmain,
+ liblixexpr,
+ liblixstore,
+ gtest,
+ boost,
+ ],
+)
+
+test(
+ 'libcmd-unit-tests',
+ libcmd_tester,
+ args : tests_args,
+ env : {
+ # No special meaning here, it's just a file laying around that is unlikely to go anywhere
+ # any time soon.
+ '_NIX_TEST_UNIT_DATA': meson.project_source_root() / 'src/nix-env/buildenv.nix',
+ },
+ suite : 'check',
+ protocol : 'gtest',
+)