From 0565f97e78f9ebd97849f79a3327f51e2157fc53 Mon Sep 17 00:00:00 2001 From: Qyriad Date: Tue, 21 May 2024 12:10:24 -0600 Subject: [PATCH 1/5] add libcmd test for lookupFileArg Change-Id: I9e2ef170ffe916f902daec8b5630d29434c5d5f2 --- tests/unit/libcmd/args.cc | 57 +++++++++++++++++++++++++++++++++++++++ tests/unit/meson.build | 27 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 tests/unit/libcmd/args.cc 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 +#include +#include + +#include +#include + +#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(searchPath, store, store); + auto & state = *statePtr; + + SourcePath const foundUnitData = lookupFileArg(state, ""); + EXPECT_EQ(foundUnitData.path, canonDataPath); + + // lookupFileArg should not resolve if anything else is before or after it. + SourcePath const yepEvenSpaces = lookupFileArg(state, " "); + EXPECT_EQ(yepEvenSpaces.path, CanonPath::fromCwd(" ")); + EXPECT_EQ(lookupFileArg(state, "/nixos").path, CanonPath::fromCwd("/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 f5355cce8..6041ba497 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', +) From 3a597f1d0bd1719423d71b7b7b029690b84b58a9 Mon Sep 17 00:00:00 2001 From: Qyriad Date: Mon, 20 May 2024 13:16:09 -0600 Subject: [PATCH 2/5] add docstring to lookupFileArg Change-Id: Ifc149764f5a15725d3d630677c6da29def4b0f3e --- src/libcmd/common-eval-args.hh | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) 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 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 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); } From a0dcfbb0842b3ab705d6fdfe0408d8ce5ed518fd Mon Sep 17 00:00:00 2001 From: Qyriad Date: Mon, 20 May 2024 13:51:42 -0600 Subject: [PATCH 3/5] cleanup lookupFileArg Change-Id: I2acd56e7a542b12138f43c95af78fdd50e944619 --- src/libcmd/common-eval-args.cc | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) 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)); } } From a8b2fc6d4132defcbe82e7f60fa73b4440cba654 Mon Sep 17 00:00:00 2001 From: Qyriad Date: Mon, 20 May 2024 20:54:00 -0600 Subject: [PATCH 4/5] build: make internal-api-docs PHONY Since we're skipping Meson's dependency tracking, for the internal-api-docs custom target, we should just consider it a phony target and build it on every request. Change-Id: I3b0bcea30ee9a4830023ccc5bededf995e96cccc --- doc/internal-api/meson.build | 1 + 1 file changed, 1 insertion(+) 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) From a0172dc81bff7f0665de77e771919e2e0b554788 Mon Sep 17 00:00:00 2001 From: Qyriad Date: Mon, 20 May 2024 21:58:27 -0600 Subject: [PATCH 5/5] docs: linkify nix3-build mention in nix-build.md Change-Id: I462a8cf0da42b5045ce84b48dc1841ecdccbb89e --- doc/manual/src/command-ref/nix-build.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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