From 5aa081e30c3d148bdc87a8e9b8bf866a17e2d098 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sun, 5 Feb 2023 15:18:05 -0500 Subject: [PATCH] WIP: Allow building a "store-only" nix This is a nix without the expression language or flakes, with just a few commands. TODO: - Do --help without libexper. - Dedup the two `main.cc`s - Dedup the two `nix.md`s - Dedup the two `help.md`s Pop out parser Fix completions --- .gitignore | 3 +- Makefile | 19 +- doc/manual/local.mk | 8 + local.mk | 3 +- src/libcmd/command-installable-value.cc | 11 + src/libcmd/command-installable-value.hh | 4 +- src/libcmd/command.cc | 286 +--------- src/libcmd/command.hh | 310 ++--------- src/libcmd/common-eval-args.cc | 15 +- src/libcmd/common-eval-args.hh | 4 +- src/libcmd/installable-attr-path.cc | 4 +- src/libcmd/installable-attr-path.hh | 6 +- src/libcmd/installable-flake.cc | 2 +- src/libcmd/installable-flake.hh | 4 +- src/libcmd/installable-value.hh | 4 +- src/libcmd/installables.cc | 371 ++----------- src/libcmd/local.mk | 7 +- src/libexpr/local.mk | 8 +- src/libfetchers/local.mk | 3 + src/libmain/common-args.hh | 6 +- src/libmain/local.mk | 3 + src/{libcmd => libstore-cmd}/built-path.cc | 0 src/{libcmd => libstore-cmd}/built-path.hh | 0 .../installable-derived-path.cc | 0 .../installable-derived-path.hh | 4 +- src/{libcmd => libstore-cmd}/legacy.cc | 0 src/{libcmd => libstore-cmd}/legacy.hh | 0 src/libstore-cmd/local.mk | 18 + src/{libcmd => libstore-cmd}/markdown.cc | 0 src/{libcmd => libstore-cmd}/markdown.hh | 0 src/libstore-cmd/nix-store-cmd.pc.in | 9 + src/libstore-cmd/store-command.cc | 76 +-- src/libstore-cmd/store-command.hh | 201 +++---- src/libstore-cmd/store-installables.cc | 523 +----------------- src/libstore/local.mk | 7 +- src/libutil/args.cc | 4 +- src/libutil/args.hh | 109 ++-- src/libutil/local.mk | 3 + src/nix-build/nix-build.cc | 7 +- src/nix-env/nix-env.cc | 7 +- src/nix-instantiate/nix-instantiate.cc | 7 +- src/nix/{ => common}/add-file.md | 0 src/nix/{ => common}/add-path.md | 0 src/nix/{ => common}/add-to-store.cc | 2 +- src/nix/{ => common}/build.cc | 7 +- src/nix/{ => common}/build.md | 0 src/nix/{ => common}/cat.cc | 2 +- src/nix/{ => common}/copy.cc | 2 +- src/nix/{ => common}/copy.md | 0 src/nix/{ => common}/daemon.cc | 2 +- src/nix/{ => common}/daemon.md | 0 src/nix/{ => common}/derivation-add.cc | 2 +- src/nix/{ => common}/derivation-add.md | 0 src/nix/{ => common}/derivation-show.cc | 2 +- src/nix/{ => common}/derivation-show.md | 0 src/nix/{ => common}/derivation.cc | 2 +- src/nix/{ => common}/diff-closures.cc | 15 +- src/nix/{ => common}/diff-closures.md | 0 src/nix/{ => common}/dump-path.cc | 2 +- src/nix/{ => common}/hash.cc | 2 +- src/nix/{ => common}/help-stores.md | 0 .../key-convert-secret-to-public.md | 0 src/nix/{ => common}/key-generate-secret.md | 0 src/nix/{ => common}/log.cc | 2 +- src/nix/{ => common}/log.md | 0 src/nix/{ => common}/ls.cc | 2 +- .../{ => common}/make-content-addressed.cc | 2 +- .../{ => common}/make-content-addressed.md | 0 src/nix/{ => common}/nar-cat.md | 0 src/nix/{ => common}/nar-dump-path.md | 0 src/nix/{ => common}/nar-ls.md | 0 src/nix/{ => common}/nar.cc | 2 +- src/nix/{ => common}/nar.md | 0 src/nix/{ => common}/optimise-store.cc | 2 +- src/nix/{ => common}/optimise-store.md | 0 src/nix/{ => common}/path-from-hash-part.cc | 2 +- src/nix/{ => common}/path-from-hash-part.md | 0 src/nix/{ => common}/path-info.cc | 2 +- src/nix/{ => common}/path-info.md | 0 src/nix/{ => common}/realisation.cc | 2 +- src/nix/{ => common}/realisation/info.md | 0 src/nix/{ => common}/sigs.cc | 2 +- src/nix/{ => common}/store-cat.md | 0 src/nix/{ => common}/store-copy-log.cc | 4 +- src/nix/{ => common}/store-copy-log.md | 0 src/nix/{ => common}/store-delete.cc | 2 +- src/nix/{ => common}/store-delete.md | 0 src/nix/{ => common}/store-dump-path.md | 0 src/nix/{ => common}/store-gc.cc | 2 +- src/nix/{ => common}/store-gc.md | 0 src/nix/{ => common}/store-info.cc | 2 +- src/nix/{ => common}/store-info.md | 0 src/nix/{ => common}/store-ls.md | 0 src/nix/{ => common}/store-repair.cc | 2 +- src/nix/{ => common}/store-repair.md | 0 src/nix/{ => common}/store.cc | 2 +- src/nix/{ => common}/verify.cc | 2 +- src/nix/{ => common}/verify.md | 0 src/nix/{ => common}/why-depends.cc | 15 +- src/nix/{ => common}/why-depends.md | 0 src/nix/{ => full}/app.cc | 2 +- src/nix/{ => full}/bundle.cc | 3 + src/nix/{ => full}/bundle.md | 0 src/nix/full/command.cc | 24 + src/nix/{ => full}/develop.cc | 17 +- src/nix/{ => full}/develop.md | 0 src/nix/{ => full}/doctor.cc | 0 src/nix/{ => full}/edit.cc | 6 + src/nix/{ => full}/edit.md | 0 src/nix/{ => full}/eval.cc | 7 +- src/nix/{ => full}/eval.md | 0 src/nix/{ => full}/flake-archive.md | 0 src/nix/{ => full}/flake-check.md | 0 src/nix/{ => full}/flake-clone.md | 0 src/nix/{ => full}/flake-init.md | 0 src/nix/{ => full}/flake-lock.md | 0 src/nix/{ => full}/flake-metadata.md | 0 src/nix/{ => full}/flake-new.md | 0 src/nix/{ => full}/flake-prefetch.md | 0 src/nix/{ => full}/flake-show.md | 0 src/nix/{ => full}/flake-update.md | 0 src/nix/{ => full}/flake.cc | 36 +- src/nix/{ => full}/flake.md | 0 src/nix/{ => full}/fmt.cc | 13 +- src/nix/{ => full}/fmt.md | 0 src/nix/{ => full}/get-env.sh | 0 src/nix/{ => full}/help.md | 0 src/nix/{ => full}/main.cc | 2 +- src/nix/{ => full}/nix.md | 0 src/nix/{ => full}/prefetch.cc | 7 +- src/nix/{ => full}/print-dev-env.md | 0 src/nix/{ => full}/profile-diff-closures.md | 0 src/nix/{ => full}/profile-history.md | 0 src/nix/{ => full}/profile-install.md | 0 src/nix/{ => full}/profile-list.md | 0 src/nix/{ => full}/profile-remove.md | 0 src/nix/{ => full}/profile-rollback.md | 0 src/nix/{ => full}/profile-upgrade.md | 0 src/nix/{ => full}/profile-wipe-history.md | 0 src/nix/{ => full}/profile.cc | 42 +- src/nix/{ => full}/profile.md | 0 src/nix/{ => full}/registry-add.md | 0 src/nix/{ => full}/registry-list.md | 0 src/nix/{ => full}/registry-pin.md | 0 src/nix/{ => full}/registry-remove.md | 0 src/nix/{ => full}/registry.cc | 4 + src/nix/{ => full}/registry.md | 0 src/nix/{ => full}/repl.cc | 8 +- src/nix/{ => full}/repl.md | 0 src/nix/{ => full}/run.cc | 9 +- src/nix/{ => full}/run.hh | 0 src/nix/{ => full}/run.md | 0 src/nix/{ => full}/search.cc | 3 + src/nix/{ => full}/search.md | 0 src/nix/{ => full}/shell.md | 0 src/nix/{ => full}/show-config.cc | 0 src/nix/{ => full}/store-prefetch-file.md | 0 src/nix/{ => full}/upgrade-nix.cc | 0 src/nix/{ => full}/upgrade-nix.md | 0 src/nix/local.mk | 62 ++- src/nix/store/command.cc | 64 +++ src/nix/store/help.md | 17 + src/nix/store/main.cc | 116 +--- src/nix/store/nix.md | 44 ++ 164 files changed, 821 insertions(+), 1810 deletions(-) rename src/{libcmd => libstore-cmd}/built-path.cc (100%) rename src/{libcmd => libstore-cmd}/built-path.hh (100%) rename src/{libcmd => libstore-cmd}/installable-derived-path.cc (100%) rename src/{libcmd => libstore-cmd}/installable-derived-path.hh (86%) rename src/{libcmd => libstore-cmd}/legacy.cc (100%) rename src/{libcmd => libstore-cmd}/legacy.hh (100%) create mode 100644 src/libstore-cmd/local.mk rename src/{libcmd => libstore-cmd}/markdown.cc (100%) rename src/{libcmd => libstore-cmd}/markdown.hh (100%) create mode 100644 src/libstore-cmd/nix-store-cmd.pc.in rename src/nix/{ => common}/add-file.md (100%) rename src/nix/{ => common}/add-path.md (100%) rename src/nix/{ => common}/add-to-store.cc (98%) rename src/nix/{ => common}/build.cc (97%) rename src/nix/{ => common}/build.md (100%) rename src/nix/{ => common}/cat.cc (98%) rename src/nix/{ => common}/copy.cc (98%) rename src/nix/{ => common}/copy.md (100%) rename src/nix/{ => common}/daemon.cc (99%) rename src/nix/{ => common}/daemon.md (100%) rename src/nix/{ => common}/derivation-add.cc (97%) rename src/nix/{ => common}/derivation-add.md (100%) rename src/nix/{ => common}/derivation-show.cc (98%) rename src/nix/{ => common}/derivation-show.md (100%) rename src/nix/{ => common}/derivation.cc (95%) rename src/nix/{ => common}/diff-closures.cc (87%) rename src/nix/{ => common}/diff-closures.md (100%) rename src/nix/{ => common}/dump-path.cc (97%) rename src/nix/{ => common}/hash.cc (99%) rename src/nix/{ => common}/help-stores.md (100%) rename src/nix/{ => common}/key-convert-secret-to-public.md (100%) rename src/nix/{ => common}/key-generate-secret.md (100%) rename src/nix/{ => common}/log.cc (98%) rename src/nix/{ => common}/log.md (100%) rename src/nix/{ => common}/ls.cc (99%) rename src/nix/{ => common}/make-content-addressed.cc (98%) rename src/nix/{ => common}/make-content-addressed.md (100%) rename src/nix/{ => common}/nar-cat.md (100%) rename src/nix/{ => common}/nar-dump-path.md (100%) rename src/nix/{ => common}/nar-ls.md (100%) rename src/nix/{ => common}/nar.cc (95%) rename src/nix/{ => common}/nar.md (100%) rename src/nix/{ => common}/optimise-store.cc (95%) rename src/nix/{ => common}/optimise-store.md (100%) rename src/nix/{ => common}/path-from-hash-part.cc (96%) rename src/nix/{ => common}/path-from-hash-part.md (100%) rename src/nix/{ => common}/path-info.cc (99%) rename src/nix/{ => common}/path-info.md (100%) rename src/nix/{ => common}/realisation.cc (98%) rename src/nix/{ => common}/realisation/info.md (100%) rename src/nix/{ => common}/sigs.cc (99%) rename src/nix/{ => common}/store-cat.md (100%) rename src/nix/{ => common}/store-copy-log.cc (89%) rename src/nix/{ => common}/store-copy-log.md (100%) rename src/nix/{ => common}/store-delete.cc (97%) rename src/nix/{ => common}/store-delete.md (100%) rename src/nix/{ => common}/store-dump-path.md (100%) rename src/nix/{ => common}/store-gc.cc (97%) rename src/nix/{ => common}/store-gc.md (100%) rename src/nix/{ => common}/store-info.cc (98%) rename src/nix/{ => common}/store-info.md (100%) rename src/nix/{ => common}/store-ls.md (100%) rename src/nix/{ => common}/store-repair.cc (94%) rename src/nix/{ => common}/store-repair.md (100%) rename src/nix/{ => common}/store.cc (94%) rename src/nix/{ => common}/verify.cc (99%) rename src/nix/{ => common}/verify.md (100%) rename src/nix/{ => common}/why-depends.cc (94%) rename src/nix/{ => common}/why-depends.md (100%) rename src/nix/{ => full}/app.cc (99%) rename src/nix/{ => full}/bundle.cc (96%) rename src/nix/{ => full}/bundle.md (100%) create mode 100644 src/nix/full/command.cc rename src/nix/{ => full}/develop.cc (96%) rename src/nix/{ => full}/develop.md (100%) rename src/nix/{ => full}/doctor.cc (100%) rename src/nix/{ => full}/edit.cc (88%) rename src/nix/{ => full}/edit.md (100%) rename src/nix/{ => full}/eval.cc (93%) rename src/nix/{ => full}/eval.md (100%) rename src/nix/{ => full}/flake-archive.md (100%) rename src/nix/{ => full}/flake-check.md (100%) rename src/nix/{ => full}/flake-clone.md (100%) rename src/nix/{ => full}/flake-init.md (100%) rename src/nix/{ => full}/flake-lock.md (100%) rename src/nix/{ => full}/flake-metadata.md (100%) rename src/nix/{ => full}/flake-new.md (100%) rename src/nix/{ => full}/flake-prefetch.md (100%) rename src/nix/{ => full}/flake-show.md (100%) rename src/nix/{ => full}/flake-update.md (100%) rename src/nix/{ => full}/flake.cc (97%) rename src/nix/{ => full}/flake.md (100%) rename src/nix/{ => full}/fmt.cc (79%) rename src/nix/{ => full}/fmt.md (100%) rename src/nix/{ => full}/get-env.sh (100%) rename src/nix/{ => full}/help.md (100%) rename src/nix/{ => full}/main.cc (99%) rename src/nix/{ => full}/nix.md (100%) rename src/nix/{ => full}/prefetch.cc (96%) rename src/nix/{ => full}/print-dev-env.md (100%) rename src/nix/{ => full}/profile-diff-closures.md (100%) rename src/nix/{ => full}/profile-history.md (100%) rename src/nix/{ => full}/profile-install.md (100%) rename src/nix/{ => full}/profile-list.md (100%) rename src/nix/{ => full}/profile-remove.md (100%) rename src/nix/{ => full}/profile-rollback.md (100%) rename src/nix/{ => full}/profile-upgrade.md (100%) rename src/nix/{ => full}/profile-wipe-history.md (100%) rename src/nix/{ => full}/profile.cc (95%) rename src/nix/{ => full}/profile.md (100%) rename src/nix/{ => full}/registry-add.md (100%) rename src/nix/{ => full}/registry-list.md (100%) rename src/nix/{ => full}/registry-pin.md (100%) rename src/nix/{ => full}/registry-remove.md (100%) rename src/nix/{ => full}/registry.cc (96%) rename src/nix/{ => full}/registry.md (100%) rename src/nix/{ => full}/repl.cc (92%) rename src/nix/{ => full}/repl.md (100%) rename src/nix/{ => full}/run.cc (95%) rename src/nix/{ => full}/run.hh (100%) rename src/nix/{ => full}/run.md (100%) rename src/nix/{ => full}/search.cc (97%) rename src/nix/{ => full}/search.md (100%) rename src/nix/{ => full}/shell.md (100%) rename src/nix/{ => full}/show-config.cc (100%) rename src/nix/{ => full}/store-prefetch-file.md (100%) rename src/nix/{ => full}/upgrade-nix.cc (100%) rename src/nix/{ => full}/upgrade-nix.md (100%) create mode 100644 src/nix/store/command.cc create mode 100644 src/nix/store/help.md create mode 100644 src/nix/store/nix.md diff --git a/.gitignore b/.gitignore index 04d96ca2c091..eb0de796599c 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,8 @@ perl/Makefile.config # /src/libutil/ /src/libutil/tests/libnixutil-tests -/src/nix/nix +/src/nix/store/mini-nix +/src/nix/full/nix /src/nix/doc diff --git a/Makefile b/Makefile index 4f4ac0c6e295..e0b386adc382 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,16 @@ -include Makefile.config clean-files += Makefile.config +NIX_FULL ?= 1 + ifeq ($(ENABLE_BUILD), yes) makefiles = \ mk/precompiled-headers.mk \ local.mk \ src/libutil/local.mk \ src/libstore/local.mk \ - src/libfetchers/local.mk \ src/libmain/local.mk \ - src/libexpr/local.mk \ - src/libcmd/local.mk \ + src/libstore-cmd/local.mk \ src/nix/local.mk \ src/resolve-system-dependencies/local.mk \ scripts/local.mk \ @@ -22,23 +22,34 @@ makefiles = \ misc/upstart/local.mk \ doc/manual/local.mk \ doc/internal-api/local.mk +ifeq ($(NIX_FULL), 1) +makefiles += \ + src/libfetchers/local.mk \ + src/libexpr/local.mk \ + src/libcmd/local.mk +endif endif ifeq ($(ENABLE_BUILD)_$(ENABLE_TESTS), yes_yes) UNIT_TEST_ENV = _NIX_TEST_UNIT_DATA=unit-test-data makefiles += \ src/libutil/tests/local.mk \ - src/libstore/tests/local.mk \ + src/libstore/tests/local.mk +ifeq ($(NIX_FULL), 1) +makefiles += \ src/libexpr/tests/local.mk endif +endif ifeq ($(ENABLE_TESTS), yes) +ifeq ($(NIX_FULL), 1) makefiles += \ tests/functional/local.mk \ tests/functional/ca/local.mk \ tests/functional/dyn-drv/local.mk \ tests/functional/test-libstoreconsumer/local.mk \ tests/functional/plugins/local.mk +endif else makefiles += \ mk/disable-tests.mk diff --git a/doc/manual/local.mk b/doc/manual/local.mk index db3daf2524af..16efd8e85c2d 100644 --- a/doc/manual/local.mk +++ b/doc/manual/local.mk @@ -96,6 +96,8 @@ $(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli $(d)/sr @cp $< $@ @$(call process-includes,$@,$@) +ifeq ($(NIX_FULL), 1) + $(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/utils.nix $(d)/generate-manpage.nix $(d)/generate-settings.nix $(d)/generate-store-info.nix $(bindir)/nix @rm -rf $@ $@.tmp $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-manpage.nix true (builtins.readFile $<)' @@ -106,6 +108,8 @@ $(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/utils.nix $(d)/gener $(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-settings.nix { prefix = "conf"; } (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp; @mv $@.tmp $@ +endif + $(d)/nix.json: $(bindir)/nix $(trace-gen) $(dummy-env) $(bindir)/nix __dump-cli > $@.tmp @mv $@.tmp $@ @@ -114,6 +118,8 @@ $(d)/conf-file.json: $(bindir)/nix $(trace-gen) $(dummy-env) $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp @mv $@.tmp $@ +ifeq ($(NIX_FULL), 1) + $(d)/src/contributing/experimental-feature-descriptions.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(bindir)/nix @rm -rf $@ $@.tmp $(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-xp-features.nix (builtins.fromJSON (builtins.readFile $<))' @@ -140,6 +146,8 @@ $(d)/src/language/builtin-constants.md: $(d)/language.json $(d)/generate-builtin @cat doc/manual/src/language/builtin-constants-suffix.md >> $@.tmp @mv $@.tmp $@ +endif + $(d)/language.json: $(bindir)/nix $(trace-gen) $(dummy-env) $(bindir)/nix __dump-language > $@.tmp @mv $@.tmp $@ diff --git a/local.mk b/local.mk index 3f3abb9f0d69..4cd877b116c4 100644 --- a/local.mk +++ b/local.mk @@ -2,8 +2,7 @@ GLOBAL_CXXFLAGS += -Wno-deprecated-declarations -Werror=switch # Allow switch-enum to be overridden for files that do not support it, usually because of dependency headers. ERROR_SWITCH_ENUM = -Werror=switch-enum -$(foreach i, config.h $(wildcard src/lib*/*.hh), \ - $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) +$(eval $(call install-file-in, config.h, $(includedir)/nix, 0644)) $(GCH): src/libutil/util.hh config.h diff --git a/src/libcmd/command-installable-value.cc b/src/libcmd/command-installable-value.cc index 7e0c15eb8cb9..cd8488ba53c2 100644 --- a/src/libcmd/command-installable-value.cc +++ b/src/libcmd/command-installable-value.cc @@ -2,6 +2,17 @@ namespace nix { +InstallableValueCommand::InstallableValueCommand() + : SourceExprCommand() +{ + expectArgs({ + .label = "installable", + .optional = true, + .handler = {&_installable}, + .completer = getCompleteInstallable(), + }); +} + void InstallableValueCommand::run(ref store, ref installable) { auto installableValue = InstallableValue::require(installable); diff --git a/src/libcmd/command-installable-value.hh b/src/libcmd/command-installable-value.hh index 7880d411998b..7058869ca44e 100644 --- a/src/libcmd/command-installable-value.hh +++ b/src/libcmd/command-installable-value.hh @@ -10,8 +10,10 @@ namespace nix { * An InstallableCommand where the single positional argument must be an * InstallableValue in particular. */ -struct InstallableValueCommand : InstallableCommand +struct InstallableValueCommand : AbstractInstallableCommand, SourceExprCommand { + InstallableValueCommand(); + /** * Entry point to this command */ diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index de9f546fc701..7265235058a1 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -8,86 +8,13 @@ #include -extern char * * environ __attribute__((weak)); - namespace nix { -RegisterCommand::Commands * RegisterCommand::commands = nullptr; - -nix::Commands RegisterCommand::getCommandsFor(const std::vector & prefix) -{ - nix::Commands res; - for (auto & [name, command] : *RegisterCommand::commands) - if (name.size() == prefix.size() + 1) { - bool equal = true; - for (size_t i = 0; i < prefix.size(); ++i) - if (name[i] != prefix[i]) equal = false; - if (equal) - res.insert_or_assign(name[prefix.size()], command); - } - return res; -} - -nlohmann::json NixMultiCommand::toJSON() -{ - // FIXME: use Command::toJSON() as well. - return MultiCommand::toJSON(); -} - -StoreCommand::StoreCommand() -{ -} - -ref StoreCommand::getStore() -{ - if (!_store) - _store = createStore(); - return ref(_store); -} - -ref StoreCommand::createStore() -{ - return openStore(); -} - -void StoreCommand::run() -{ - run(getStore()); -} - -CopyCommand::CopyCommand() -{ - addFlag({ - .longName = "from", - .description = "URL of the source Nix store.", - .labels = {"store-uri"}, - .handler = {&srcUri}, - }); - - addFlag({ - .longName = "to", - .description = "URL of the destination Nix store.", - .labels = {"store-uri"}, - .handler = {&dstUri}, - }); -} - -ref CopyCommand::createStore() -{ - return srcUri.empty() ? StoreCommand::createStore() : openStore(srcUri); -} - -ref CopyCommand::getDstStore() +HasEvalState::HasEvalState(AbstractArgs & args) + : MixRepair(args) + , MixEvalArgs(args) { - if (srcUri.empty() && dstUri.empty()) - throw UsageError("you must pass '--from' and/or '--to'"); - - return dstUri.empty() ? openStore() : openStore(dstUri); -} - -EvalCommand::EvalCommand() -{ - addFlag({ + args.addFlag({ .longName = "debugger", .description = "Start an interactive environment if evaluation fails.", .category = MixEvalArgs::category, @@ -95,29 +22,29 @@ EvalCommand::EvalCommand() }); } -EvalCommand::~EvalCommand() +HasEvalState::~HasEvalState() { if (evalState) evalState->maybePrintStats(); } -ref EvalCommand::getEvalStore() +ref HasEvalState::getDrvStore() { - if (!evalStore) - evalStore = evalStoreUrl ? openStore(*evalStoreUrl) : getStore(); - return ref(evalStore); + if (!drvStore) + drvStore = evalStoreUrl ? openStore(*evalStoreUrl) : getStore(); + return ref(drvStore); } -ref EvalCommand::getEvalState() +ref HasEvalState::getEvalState() { if (!evalState) { evalState = #if HAVE_BOEHMGC std::allocate_shared(traceable_allocator(), - searchPath, getEvalStore(), getStore()) + searchPath, getDrvStore(), getStore()) #else std::make_shared( - searchPath, getEvalStore(), getStore()) + searchPath, getDrvStore(), getStore()) #endif ; @@ -130,193 +57,4 @@ ref EvalCommand::getEvalState() return ref(evalState); } -MixOperateOnOptions::MixOperateOnOptions() -{ - addFlag({ - .longName = "derivation", - .description = "Operate on the [store derivation](../../glossary.md#gloss-store-derivation) rather than its outputs.", - .category = installablesCategory, - .handler = {&operateOn, OperateOn::Derivation}, - }); -} - -BuiltPathsCommand::BuiltPathsCommand(bool recursive) - : recursive(recursive) -{ - if (recursive) - addFlag({ - .longName = "no-recursive", - .description = "Apply operation to specified paths only.", - .category = installablesCategory, - .handler = {&this->recursive, false}, - }); - else - addFlag({ - .longName = "recursive", - .shortName = 'r', - .description = "Apply operation to closure of the specified paths.", - .category = installablesCategory, - .handler = {&this->recursive, true}, - }); - - addFlag({ - .longName = "all", - .description = "Apply the operation to every store path.", - .category = installablesCategory, - .handler = {&all, true}, - }); -} - -void BuiltPathsCommand::run(ref store, Installables && installables) -{ - BuiltPaths paths; - if (all) { - if (installables.size()) - throw UsageError("'--all' does not expect arguments"); - // XXX: Only uses opaque paths, ignores all the realisations - for (auto & p : store->queryAllValidPaths()) - paths.emplace_back(BuiltPath::Opaque{p}); - } else { - paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables); - if (recursive) { - // XXX: This only computes the store path closure, ignoring - // intermediate realisations - StorePathSet pathsRoots, pathsClosure; - for (auto & root : paths) { - auto rootFromThis = root.outPaths(); - pathsRoots.insert(rootFromThis.begin(), rootFromThis.end()); - } - store->computeFSClosure(pathsRoots, pathsClosure); - for (auto & path : pathsClosure) - paths.emplace_back(BuiltPath::Opaque{path}); - } - } - - run(store, std::move(paths)); -} - -StorePathsCommand::StorePathsCommand(bool recursive) - : BuiltPathsCommand(recursive) -{ -} - -void StorePathsCommand::run(ref store, BuiltPaths && paths) -{ - StorePathSet storePaths; - for (auto & builtPath : paths) - for (auto & p : builtPath.outPaths()) - storePaths.insert(p); - - auto sorted = store->topoSortPaths(storePaths); - std::reverse(sorted.begin(), sorted.end()); - - run(store, std::move(sorted)); -} - -void StorePathCommand::run(ref store, StorePaths && storePaths) -{ - if (storePaths.size() != 1) - throw UsageError("this command requires exactly one store path"); - - run(store, *storePaths.begin()); -} - -MixProfile::MixProfile() -{ - addFlag({ - .longName = "profile", - .description = "The profile to operate on.", - .labels = {"path"}, - .handler = {&profile}, - .completer = completePath - }); -} - -void MixProfile::updateProfile(const StorePath & storePath) -{ - if (!profile) return; - auto store = getStore().dynamic_pointer_cast(); - if (!store) throw Error("'--profile' is not supported for this Nix store"); - auto profile2 = absPath(*profile); - switchLink(profile2, - createGeneration(*store, profile2, storePath)); -} - -void MixProfile::updateProfile(const BuiltPaths & buildables) -{ - if (!profile) return; - - StorePaths result; - - for (auto & buildable : buildables) { - std::visit(overloaded { - [&](const BuiltPath::Opaque & bo) { - result.push_back(bo.path); - }, - [&](const BuiltPath::Built & bfd) { - for (auto & output : bfd.outputs) { - result.push_back(output.second); - } - }, - }, buildable.raw()); - } - - if (result.size() != 1) - throw UsageError("'--profile' requires that the arguments produce a single store path, but there are %d", result.size()); - - updateProfile(result[0]); -} - -MixDefaultProfile::MixDefaultProfile() -{ - profile = getDefaultProfile(); -} - -MixEnvironment::MixEnvironment() : ignoreEnvironment(false) -{ - addFlag({ - .longName = "ignore-environment", - .shortName = 'i', - .description = "Clear the entire environment (except those specified with `--keep`).", - .handler = {&ignoreEnvironment, true}, - }); - - addFlag({ - .longName = "keep", - .shortName = 'k', - .description = "Keep the environment variable *name*.", - .labels = {"name"}, - .handler = {[&](std::string s) { keep.insert(s); }}, - }); - - addFlag({ - .longName = "unset", - .shortName = 'u', - .description = "Unset the environment variable *name*.", - .labels = {"name"}, - .handler = {[&](std::string s) { unset.insert(s); }}, - }); -} - -void MixEnvironment::setEnviron() { - if (ignoreEnvironment) { - if (!unset.empty()) - throw UsageError("--unset does not make sense with --ignore-environment"); - - for (const auto & var : keep) { - auto val = getenv(var.c_str()); - if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val)); - } - - vectorEnv = stringsToCharPtrs(stringsEnv); - environ = vectorEnv.data(); - } else { - if (!keep.empty()) - throw UsageError("--keep does not make sense without --ignore-environment"); - - for (const auto & var : unset) - unsetenv(var.c_str()); - } -} - } diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 120c832ac23b..8165e6fb3ac9 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -2,102 +2,53 @@ ///@file #include "installable-value.hh" -#include "args.hh" +#include "store-command.hh" #include "common-eval-args.hh" -#include "path.hh" #include "flake/lockfile.hh" -#include - namespace nix { -extern std::string programPath; - -extern char * * savedArgv; - class EvalState; struct Pos; -class Store; - -static constexpr Command::Category catHelp = -1; -static constexpr Command::Category catSecondary = 100; -static constexpr Command::Category catUtility = 101; -static constexpr Command::Category catNixInstallation = 102; - -static constexpr auto installablesCategory = "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)"; -struct NixMultiCommand : virtual MultiCommand, virtual Command +struct HasEvalState : virtual HasDrvStore, MixEvalArgs { - nlohmann::json toJSON() override; -}; - -// For the overloaded run methods -#pragma GCC diagnostic ignored "-Woverloaded-virtual" + bool startReplOnEvalErrors = false; + bool ignoreExceptionsDuringTry = false; -/** - * A command that requires a \ref Store "Nix store". - */ -struct StoreCommand : virtual Command -{ - StoreCommand(); - void run() override; - ref getStore(); - virtual ref createStore(); - /** - * Main entry point, with a `Store` provided - */ - virtual void run(ref) = 0; + HasEvalState(AbstractArgs & args); -private: - std::shared_ptr _store; -}; + ~HasEvalState(); -/** - * A command that copies something between `--from` and `--to` \ref - * Store stores. - */ -struct CopyCommand : virtual StoreCommand -{ - std::string srcUri, dstUri; + ref getDrvStore() override; - CopyCommand(); + ref getEvalState(); - ref createStore() override; +private: - ref getDstStore(); + std::shared_ptr evalState; }; /** * A command that needs to evaluate Nix language expressions. */ -struct EvalCommand : virtual StoreCommand, MixEvalArgs +struct EvalCommand : virtual DrvCommand, virtual HasEvalState { - bool startReplOnEvalErrors = false; - bool ignoreExceptionsDuringTry = false; - - EvalCommand(); - - ~EvalCommand(); - - ref getEvalStore(); - - ref getEvalState(); - -private: - std::shared_ptr evalStore; - - std::shared_ptr evalState; + EvalCommand() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + { } }; /** * A mixin class for commands that process flakes, adding a few standard * flake-related options/flags. */ -struct MixFlakeOptions : virtual Args, EvalCommand +struct MixFlakeOptions : virtual HasEvalState { flake::LockFlags lockFlags; - MixFlakeOptions(); + MixFlakeOptions(AbstractArgs & args); /** * The completion for some of these flags depends on the flake(s) in @@ -111,219 +62,56 @@ struct MixFlakeOptions : virtual Args, EvalCommand { return {}; } }; -struct SourceExprCommand : virtual Args, MixFlakeOptions -{ - std::optional file; - std::optional expr; - - SourceExprCommand(); - - Installables parseInstallables( - ref store, std::vector ss); - - ref parseInstallable( - ref store, const std::string & installable); - - virtual Strings getDefaultFlakeAttrPaths(); - - virtual Strings getDefaultFlakeAttrPathPrefixes(); - - /** - * Complete an installable from the given prefix. - */ - void completeInstallable(AddCompletions & completions, std::string_view prefix); - - /** - * Convenience wrapper around the underlying function to make setting the - * callback easier. - */ - CompleterClosure getCompleteInstallable(); -}; - /** - * A mixin class for commands that need a read-only flag. - * - * What exactly is "read-only" is unspecified, but it will usually be - * the \ref Store "Nix store". - */ -struct MixReadOnlyOption : virtual Args -{ - MixReadOnlyOption(); -}; - -/** - * Like InstallablesCommand but the installables are not loaded. - * - * This is needed by `CmdRepl` which wants to load (and reload) the - * installables itself. + * A class for parsing all installable, both low level + * InstallableDerivedPath and high level InstallableValue and its + * subclassses. */ -struct RawInstallablesCommand : virtual Args, SourceExprCommand +struct ParseInstallableValueArgs : virtual ParseInstallableArgs, virtual MixFlakeOptions { - RawInstallablesCommand(); + GetRawInstallables & args; - virtual void run(ref store, std::vector && rawInstallables) = 0; + ParseInstallableValueArgs(GetRawInstallables & args); - void run(ref store) override; - - // FIXME make const after `CmdRepl`'s override is fixed up - virtual void applyDefaultInstallables(std::vector & rawInstallables); - - bool readFromStdIn = false; - - std::vector getFlakeRefsForCompletion() override; - -private: + std::optional file; + std::optional expr; - std::vector rawInstallables; -}; + virtual Strings getDefaultFlakeAttrPaths(); -/** - * A command that operates on a list of "installables", which can be - * store paths, attribute paths, Nix expressions, etc. - */ -struct InstallablesCommand : RawInstallablesCommand -{ - virtual void run(ref store, Installables && installables) = 0; + virtual Strings getDefaultFlakeAttrPathPrefixes(); - void run(ref store, std::vector && rawInstallables) override; -}; + Installables parseInstallables( + ref store, std::vector ss) override; -/** - * A command that operates on exactly one "installable". - */ -struct InstallableCommand : virtual Args, SourceExprCommand -{ - InstallableCommand(); + ref parseInstallable( + ref store, const std::string & s) override; - virtual void run(ref store, ref installable) = 0; + void applyDefaultInstallables(std::vector & rawInstallables) override; - void run(ref store) override; + void completeInstallable(AddCompletions & completions, std::string_view prefix) override; std::vector getFlakeRefsForCompletion() override; - -private: - - std::string _installable{"."}; }; -struct MixOperateOnOptions : virtual Args +struct SourceExprCommand : virtual EvalCommand, ParseInstallableValueArgs, virtual GetRawInstallables { - OperateOn operateOn = OperateOn::Output; - - MixOperateOnOptions(); + SourceExprCommand() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + , ParseInstallableValueArgs(static_cast(*this)) + { } }; /** - * A command that operates on zero or more extant store paths. + * A mixin class for commands that need a read-only flag. * - * If the argument the user passes is a some sort of recipe for a path - * not yet built, it must be built first. - */ -struct BuiltPathsCommand : InstallablesCommand, virtual MixOperateOnOptions -{ -private: - - bool recursive = false; - bool all = false; - -protected: - - Realise realiseMode = Realise::Derivation; - -public: - - BuiltPathsCommand(bool recursive = false); - - virtual void run(ref store, BuiltPaths && paths) = 0; - - void run(ref store, Installables && installables) override; - - void applyDefaultInstallables(std::vector & rawInstallables) override; -}; - -struct StorePathsCommand : public BuiltPathsCommand -{ - StorePathsCommand(bool recursive = false); - - virtual void run(ref store, StorePaths && storePaths) = 0; - - void run(ref store, BuiltPaths && paths) override; -}; - -/** - * A command that operates on exactly one store path. - */ -struct StorePathCommand : public StorePathsCommand -{ - virtual void run(ref store, const StorePath & storePath) = 0; - - void run(ref store, StorePaths && storePaths) override; -}; - -/** - * A helper class for registering \ref Command commands globally. + * What exactly is "read-only" is unspecified, but it will usually be + * the \ref Store "Nix store". */ -struct RegisterCommand +struct MixReadOnlyOption { - typedef std::map, std::function()>> Commands; - static Commands * commands; - - RegisterCommand(std::vector && name, - std::function()> command) - { - if (!commands) commands = new Commands; - commands->emplace(name, command); - } - - static nix::Commands getCommandsFor(const std::vector & prefix); -}; - -template -static RegisterCommand registerCommand(const std::string & name) -{ - return RegisterCommand({name}, [](){ return make_ref(); }); -} - -template -static RegisterCommand registerCommand2(std::vector && name) -{ - return RegisterCommand(std::move(name), [](){ return make_ref(); }); -} - -struct MixProfile : virtual StoreCommand -{ - std::optional profile; - - MixProfile(); - - /* If 'profile' is set, make it point at 'storePath'. */ - void updateProfile(const StorePath & storePath); - - /* If 'profile' is set, make it point at the store path produced - by 'buildables'. */ - void updateProfile(const BuiltPaths & buildables); -}; - -struct MixDefaultProfile : MixProfile -{ - MixDefaultProfile(); -}; - -struct MixEnvironment : virtual Args { - - StringSet keep, unset; - Strings stringsEnv; - std::vector vectorEnv; - bool ignoreEnvironment; - - MixEnvironment(); - - /*** - * Modify global environ based on `ignoreEnvironment`, `keep`, and - * `unset`. It's expected that exec will be called before this class - * goes out of scope, otherwise `environ` will become invalid. - */ - void setEnviron(); + MixReadOnlyOption(AbstractArgs & args); }; void completeFlakeInputPath( @@ -342,12 +130,4 @@ void completeFlakeRefWithFragment( const Strings & defaultFlakeAttrPaths, std::string_view prefix); -std::string showVersions(const std::set & versions); - -void printClosureDiff( - ref store, - const StorePath & beforePath, - const StorePath & afterPath, - std::string_view indent); - } diff --git a/src/libcmd/common-eval-args.cc b/src/libcmd/common-eval-args.cc index 401acc38e96b..7eeff2e93417 100644 --- a/src/libcmd/common-eval-args.cc +++ b/src/libcmd/common-eval-args.cc @@ -12,9 +12,10 @@ namespace nix { -MixEvalArgs::MixEvalArgs() +MixEvalArgs::MixEvalArgs(AbstractArgs & args) + : MixRepair(args) { - addFlag({ + args.addFlag({ .longName = "arg", .description = "Pass the value *expr* as the argument *name* to Nix functions.", .category = category, @@ -22,7 +23,7 @@ MixEvalArgs::MixEvalArgs() .handler = {[&](std::string name, std::string expr) { autoArgs[name] = 'E' + expr; }} }); - addFlag({ + args.addFlag({ .longName = "argstr", .description = "Pass the string *string* as the argument *name* to Nix functions.", .category = category, @@ -30,7 +31,7 @@ MixEvalArgs::MixEvalArgs() .handler = {[&](std::string name, std::string s) { autoArgs[name] = 'S' + s; }}, }); - addFlag({ + args.addFlag({ .longName = "include", .shortName = 'I', .description = R"( @@ -111,7 +112,7 @@ MixEvalArgs::MixEvalArgs() }} }); - addFlag({ + args.addFlag({ .longName = "impure", .description = "Allow access to mutable paths and repositories.", .category = category, @@ -120,7 +121,7 @@ MixEvalArgs::MixEvalArgs() }}, }); - addFlag({ + args.addFlag({ .longName = "override-flake", .description = "Override the flake registries, redirecting *original-ref* to *resolved-ref*.", .category = category, @@ -137,7 +138,7 @@ MixEvalArgs::MixEvalArgs() }} }); - addFlag({ + args.addFlag({ .longName = "eval-store", .description = R"( diff --git a/src/libcmd/common-eval-args.hh b/src/libcmd/common-eval-args.hh index 4b403d936740..00e326b89a78 100644 --- a/src/libcmd/common-eval-args.hh +++ b/src/libcmd/common-eval-args.hh @@ -13,11 +13,11 @@ class EvalState; class Bindings; struct SourcePath; -struct MixEvalArgs : virtual Args, virtual MixRepair +struct MixEvalArgs : virtual MixRepair { static constexpr auto category = "Common evaluation options"; - MixEvalArgs(); + MixEvalArgs(AbstractArgs & args); Bindings * getAutoArgs(EvalState & state); diff --git a/src/libcmd/installable-attr-path.cc b/src/libcmd/installable-attr-path.cc index 06e507872b51..98f2fedeb91f 100644 --- a/src/libcmd/installable-attr-path.cc +++ b/src/libcmd/installable-attr-path.cc @@ -26,7 +26,7 @@ namespace nix { InstallableAttrPath::InstallableAttrPath( ref state, - SourceExprCommand & cmd, + ParseInstallableValueArgs & cmd, Value * v, const std::string & attrPath, ExtendedOutputsSpec extendedOutputsSpec) @@ -107,7 +107,7 @@ DerivedPathsWithInfo InstallableAttrPath::toDerivedPaths() InstallableAttrPath InstallableAttrPath::parse( ref state, - SourceExprCommand & cmd, + ParseInstallableValueArgs & cmd, Value * v, std::string_view prefix, ExtendedOutputsSpec extendedOutputsSpec) diff --git a/src/libcmd/installable-attr-path.hh b/src/libcmd/installable-attr-path.hh index 86c2f82192c8..473083104cf3 100644 --- a/src/libcmd/installable-attr-path.hh +++ b/src/libcmd/installable-attr-path.hh @@ -27,14 +27,14 @@ namespace nix { class InstallableAttrPath : public InstallableValue { - SourceExprCommand & cmd; + ParseInstallableValueArgs & cmd; RootValue v; std::string attrPath; ExtendedOutputsSpec extendedOutputsSpec; InstallableAttrPath( ref state, - SourceExprCommand & cmd, + ParseInstallableValueArgs & cmd, Value * v, const std::string & attrPath, ExtendedOutputsSpec extendedOutputsSpec); @@ -49,7 +49,7 @@ public: static InstallableAttrPath parse( ref state, - SourceExprCommand & cmd, + ParseInstallableValueArgs & cmd, Value * v, std::string_view prefix, ExtendedOutputsSpec extendedOutputsSpec); diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc index 2f428cb7e4ba..d1222fbc19e1 100644 --- a/src/libcmd/installable-flake.cc +++ b/src/libcmd/installable-flake.cc @@ -68,7 +68,7 @@ static std::string showAttrPaths(const std::vector & paths) } InstallableFlake::InstallableFlake( - SourceExprCommand * cmd, + ParseInstallableValueArgs * cmd, ref state, FlakeRef && flakeRef, std::string_view fragment, diff --git a/src/libcmd/installable-flake.hh b/src/libcmd/installable-flake.hh index 314918c140d2..9151b2af54e9 100644 --- a/src/libcmd/installable-flake.hh +++ b/src/libcmd/installable-flake.hh @@ -29,6 +29,8 @@ struct ExtraPathInfoFlake : ExtraPathInfoValue { } }; +struct ParseInstallableValueArgs; + struct InstallableFlake : InstallableValue { FlakeRef flakeRef; @@ -39,7 +41,7 @@ struct InstallableFlake : InstallableValue mutable std::shared_ptr _lockedFlake; InstallableFlake( - SourceExprCommand * cmd, + ParseInstallableValueArgs * cmd, ref state, FlakeRef && flakeRef, std::string_view fragment, diff --git a/src/libcmd/installable-value.hh b/src/libcmd/installable-value.hh index 3138ce8ecee7..442857dcc01c 100644 --- a/src/libcmd/installable-value.hh +++ b/src/libcmd/installable-value.hh @@ -1,13 +1,13 @@ #pragma once ///@file -#include "installables.hh" +#include "store-installables.hh" #include "flake/flake.hh" namespace nix { struct DrvInfo; -struct SourceExprCommand; +struct ParseInstallableValueArgs; namespace eval_cache { class EvalCache; class AttrCursor; } diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 1c6103020f7f..3dc99632593e 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -1,11 +1,12 @@ #include "globals.hh" -#include "installables.hh" +#include "installable-value.hh" #include "installable-derived-path.hh" #include "installable-attr-path.hh" #include "installable-flake.hh" #include "outputs-spec.hh" #include "users.hh" #include "util.hh" +#include "installable-derived-path.hh" #include "command.hh" #include "attr-path.hh" #include "common-eval-args.hh" @@ -43,25 +44,27 @@ void completeFlakeInputPath( } } -MixFlakeOptions::MixFlakeOptions() +MixFlakeOptions::MixFlakeOptions(AbstractArgs & args) + : MixRepair(args) + , HasEvalState(args) { auto category = "Common flake-related options"; - addFlag({ + args.addFlag({ .longName = "no-update-lock-file", .description = "Do not allow any updates to the flake's lock file.", .category = category, .handler = {&lockFlags.updateLockFile, false} }); - addFlag({ + args.addFlag({ .longName = "no-write-lock-file", .description = "Do not write the flake's newly generated lock file.", .category = category, .handler = {&lockFlags.writeLockFile, false} }); - addFlag({ + args.addFlag({ .longName = "no-registries", .description = "Don't allow lookups in the flake registries. This option is deprecated; use `--no-use-registries`.", @@ -72,14 +75,14 @@ MixFlakeOptions::MixFlakeOptions() }} }); - addFlag({ + args.addFlag({ .longName = "commit-lock-file", .description = "Commit changes to the flake's lock file.", .category = category, .handler = {&lockFlags.commitLockFile, true} }); - addFlag({ + args.addFlag({ .longName = "override-input", .description = "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.", .category = category, @@ -88,7 +91,7 @@ MixFlakeOptions::MixFlakeOptions() lockFlags.writeLockFile = false; lockFlags.inputOverrides.insert_or_assign( flake::parseInputPath(inputPath), - parseFlakeRef(flakeRef, absPath(getCommandBaseDir()), true)); + parseFlakeRef(flakeRef, absPath(args.getCommandBaseDir()), true)); }}, .completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) { if (n == 0) { @@ -99,7 +102,7 @@ MixFlakeOptions::MixFlakeOptions() }} }); - addFlag({ + args.addFlag({ .longName = "reference-lock-file", .description = "Read the given lock file instead of `flake.lock` within the top-level flake.", .category = category, @@ -107,10 +110,10 @@ MixFlakeOptions::MixFlakeOptions() .handler = {[&](std::string lockFilePath) { lockFlags.referenceLockFilePath = lockFilePath; }}, - .completer = completePath + .completer = AbstractArgs::completePath }); - addFlag({ + args.addFlag({ .longName = "output-lock-file", .description = "Write the given lock file instead of `flake.lock` within the top-level flake.", .category = category, @@ -118,10 +121,10 @@ MixFlakeOptions::MixFlakeOptions() .handler = {[&](std::string lockFilePath) { lockFlags.outputLockFilePath = lockFilePath; }}, - .completer = completePath + .completer = AbstractArgs::completePath }); - addFlag({ + args.addFlag({ .longName = "inputs-from", .description = "Use the inputs of the specified flake as registry entries.", .category = category, @@ -130,7 +133,7 @@ MixFlakeOptions::MixFlakeOptions() auto evalState = getEvalState(); auto flake = flake::lockFlake( *evalState, - parseFlakeRef(flakeRef, absPath(getCommandBaseDir())), + parseFlakeRef(flakeRef, absPath(args.getCommandBaseDir())), { .writeLockFile = false }); for (auto & [inputName, input] : flake.lockFile.root->inputs) { auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes @@ -148,9 +151,13 @@ MixFlakeOptions::MixFlakeOptions() }); } -SourceExprCommand::SourceExprCommand() +ParseInstallableValueArgs::ParseInstallableValueArgs(GetRawInstallables & args) + : MixRepair(args) + , HasEvalState(args) + , MixFlakeOptions(args) + , args(args) { - addFlag({ + args.addFlag({ .longName = "file", .shortName = 'f', .description = @@ -160,10 +167,10 @@ SourceExprCommand::SourceExprCommand() .category = installablesCategory, .labels = {"file"}, .handler = {&file}, - .completer = completePath + .completer = AbstractArgs::completePath }); - addFlag({ + args.addFlag({ .longName = "expr", .description = "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.", .category = installablesCategory, @@ -172,9 +179,9 @@ SourceExprCommand::SourceExprCommand() }); } -MixReadOnlyOption::MixReadOnlyOption() +MixReadOnlyOption::MixReadOnlyOption(AbstractArgs & args) { - addFlag({ + args.addFlag({ .longName = "read-only", .description = "Do not instantiate each evaluated derivation. " @@ -184,7 +191,7 @@ MixReadOnlyOption::MixReadOnlyOption() }); } -Strings SourceExprCommand::getDefaultFlakeAttrPaths() +Strings ParseInstallableValueArgs::getDefaultFlakeAttrPaths() { return { "packages." + settings.thisSystem.get() + ".default", @@ -192,7 +199,7 @@ Strings SourceExprCommand::getDefaultFlakeAttrPaths() }; } -Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes() +Strings ParseInstallableValueArgs::getDefaultFlakeAttrPathPrefixes() { return { // As a convenience, look for the attribute in @@ -204,14 +211,7 @@ Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes() }; } -Args::CompleterClosure SourceExprCommand::getCompleteInstallable() -{ - return [this](AddCompletions & completions, size_t, std::string_view prefix) { - completeInstallable(completions, prefix); - }; -} - -void SourceExprCommand::completeInstallable(AddCompletions & completions, std::string_view prefix) +void ParseInstallableValueArgs::completeInstallable(AddCompletions & completions, std::string_view prefix) { try { if (file) { @@ -376,25 +376,6 @@ void completeFlakeRef(AddCompletions & completions, ref store, std::strin } } -DerivedPathWithInfo Installable::toDerivedPath() -{ - auto buildables = toDerivedPaths(); - if (buildables.size() != 1) - throw Error("installable '%s' evaluates to %d derivations, where only one is expected", what(), buildables.size()); - return std::move(buildables[0]); -} - -static StorePath getDeriver( - ref store, - const Installable & i, - const StorePath & drvPath) -{ - auto derivers = store->queryValidDerivers(drvPath); - if (derivers.empty()) - throw Error("'%s' does not have a known deriver", i.what()); - // FIXME: use all derivers? - return *derivers.begin(); -} ref openEvalCache( EvalState & state, @@ -425,7 +406,7 @@ ref openEvalCache( }); } -Installables SourceExprCommand::parseInstallables( +Installables ParseInstallableValueArgs::parseInstallables( ref store, std::vector ss) { Installables result; @@ -445,10 +426,10 @@ Installables SourceExprCommand::parseInstallables( state->eval(e, *vFile); } else if (file) { - state->evalFile(lookupFileArg(*state, *file, CanonPath::fromCwd(getCommandBaseDir())), *vFile); + state->evalFile(lookupFileArg(*state, *file, CanonPath::fromCwd(args.getCommandBaseDir())), *vFile); } else { - CanonPath dir(CanonPath::fromCwd(getCommandBaseDir())); + CanonPath dir(CanonPath::fromCwd(args.getCommandBaseDir())); auto e = state->parseExprFromString(*expr, state->rootPath(dir)); state->eval(e, *vFile); } @@ -484,7 +465,7 @@ Installables SourceExprCommand::parseInstallables( } try { - auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath(getCommandBaseDir())); + auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath(args.getCommandBaseDir())); result.push_back(make_ref( this, getEvalState(), @@ -506,7 +487,7 @@ Installables SourceExprCommand::parseInstallables( return result; } -ref SourceExprCommand::parseInstallable( +ref ParseInstallableValueArgs::parseInstallable( ref store, const std::string & installable) { auto installables = parseInstallables(store, {installable}); @@ -514,235 +495,7 @@ ref SourceExprCommand::parseInstallable( return installables.front(); } -static SingleBuiltPath getBuiltPath(ref evalStore, ref store, const SingleDerivedPath & b) -{ - return std::visit( - overloaded{ - [&](const SingleDerivedPath::Opaque & bo) -> SingleBuiltPath { - return SingleBuiltPath::Opaque { bo.path }; - }, - [&](const SingleDerivedPath::Built & bfd) -> SingleBuiltPath { - auto drvPath = getBuiltPath(evalStore, store, *bfd.drvPath); - // Resolving this instead of `bfd` will yield the same result, but avoid duplicative work. - SingleDerivedPath::Built truncatedBfd { - .drvPath = makeConstantStorePathRef(drvPath.outPath()), - .output = bfd.output, - }; - auto outputPath = resolveDerivedPath(*store, truncatedBfd, &*evalStore); - return SingleBuiltPath::Built { - .drvPath = make_ref(std::move(drvPath)), - .output = { bfd.output, outputPath }, - }; - }, - }, - b.raw()); -} - -std::vector Installable::build( - ref evalStore, - ref store, - Realise mode, - const Installables & installables, - BuildMode bMode) -{ - std::vector res; - for (auto & [_, builtPathWithResult] : build2(evalStore, store, mode, installables, bMode)) - res.push_back(builtPathWithResult); - return res; -} - -std::vector, BuiltPathWithResult>> Installable::build2( - ref evalStore, - ref store, - Realise mode, - const Installables & installables, - BuildMode bMode) -{ - if (mode == Realise::Nothing) - settings.readOnlyMode = true; - - struct Aux - { - ref info; - ref installable; - }; - - std::vector pathsToBuild; - std::map> backmap; - - for (auto & i : installables) { - for (auto b : i->toDerivedPaths()) { - pathsToBuild.push_back(b.path); - backmap[b.path].push_back({.info = b.info, .installable = i}); - } - } - - std::vector, BuiltPathWithResult>> res; - - switch (mode) { - - case Realise::Nothing: - case Realise::Derivation: - printMissing(store, pathsToBuild, lvlError); - - for (auto & path : pathsToBuild) { - for (auto & aux : backmap[path]) { - std::visit(overloaded { - [&](const DerivedPath::Built & bfd) { - auto outputs = resolveDerivedPath(*store, bfd, &*evalStore); - res.push_back({aux.installable, { - .path = BuiltPath::Built { - .drvPath = make_ref(getBuiltPath(evalStore, store, *bfd.drvPath)), - .outputs = outputs, - }, - .info = aux.info}}); - }, - [&](const DerivedPath::Opaque & bo) { - res.push_back({aux.installable, { - .path = BuiltPath::Opaque { bo.path }, - .info = aux.info}}); - }, - }, path.raw()); - } - } - - break; - - case Realise::Outputs: { - if (settings.printMissing) - printMissing(store, pathsToBuild, lvlInfo); - - for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) { - if (!buildResult.success()) - buildResult.rethrow(); - - for (auto & aux : backmap[buildResult.path]) { - std::visit(overloaded { - [&](const DerivedPath::Built & bfd) { - std::map outputs; - for (auto & [outputName, realisation] : buildResult.builtOutputs) - outputs.emplace(outputName, realisation.outPath); - res.push_back({aux.installable, { - .path = BuiltPath::Built { - .drvPath = make_ref(getBuiltPath(evalStore, store, *bfd.drvPath)), - .outputs = outputs, - }, - .info = aux.info, - .result = buildResult}}); - }, - [&](const DerivedPath::Opaque & bo) { - res.push_back({aux.installable, { - .path = BuiltPath::Opaque { bo.path }, - .info = aux.info, - .result = buildResult}}); - }, - }, buildResult.path.raw()); - } - } - - break; - } - - default: - assert(false); - } - - return res; -} - -BuiltPaths Installable::toBuiltPaths( - ref evalStore, - ref store, - Realise mode, - OperateOn operateOn, - const Installables & installables) -{ - if (operateOn == OperateOn::Output) { - BuiltPaths res; - for (auto & p : Installable::build(evalStore, store, mode, installables)) - res.push_back(p.path); - return res; - } else { - if (mode == Realise::Nothing) - settings.readOnlyMode = true; - - BuiltPaths res; - for (auto & drvPath : Installable::toDerivations(store, installables, true)) - res.emplace_back(BuiltPath::Opaque{drvPath}); - return res; - } -} - -StorePathSet Installable::toStorePaths( - ref evalStore, - ref store, - Realise mode, OperateOn operateOn, - const Installables & installables) -{ - StorePathSet outPaths; - for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) { - auto thisOutPaths = path.outPaths(); - outPaths.insert(thisOutPaths.begin(), thisOutPaths.end()); - } - return outPaths; -} - -StorePath Installable::toStorePath( - ref evalStore, - ref store, - Realise mode, OperateOn operateOn, - ref installable) -{ - auto paths = toStorePaths(evalStore, store, mode, operateOn, {installable}); - - if (paths.size() != 1) - throw Error("argument '%s' should evaluate to one store path", installable->what()); - - return *paths.begin(); -} - -StorePathSet Installable::toDerivations( - ref store, - const Installables & installables, - bool useDeriver) -{ - StorePathSet drvPaths; - - for (const auto & i : installables) - for (const auto & b : i->toDerivedPaths()) - std::visit(overloaded { - [&](const DerivedPath::Opaque & bo) { - drvPaths.insert( - bo.path.isDerivation() - ? bo.path - : useDeriver - ? getDeriver(store, *i, bo.path) - : throw Error("argument '%s' did not evaluate to a derivation", i->what())); - }, - [&](const DerivedPath::Built & bfd) { - drvPaths.insert(resolveDerivedPath(*store, *bfd.drvPath)); - }, - }, b.path.raw()); - - return drvPaths; -} - -RawInstallablesCommand::RawInstallablesCommand() -{ - addFlag({ - .longName = "stdin", - .description = "Read installables from the standard input. No default installable applied.", - .handler = {&readFromStdIn, true} - }); - - expectArgs({ - .label = "installables", - .handler = {&rawInstallables}, - .completer = getCompleteInstallable(), - }); -} - -void RawInstallablesCommand::applyDefaultInstallables(std::vector & rawInstallables) +void ParseInstallableValueArgs::applyDefaultInstallables(std::vector & rawInstallables) { if (rawInstallables.empty()) { // FIXME: commands like "nix profile install" should not have a @@ -751,62 +504,16 @@ void RawInstallablesCommand::applyDefaultInstallables(std::vector & } } -std::vector RawInstallablesCommand::getFlakeRefsForCompletion() +std::vector ParseInstallableValueArgs::getFlakeRefsForCompletion() { - applyDefaultInstallables(rawInstallables); std::vector res; - for (auto i : rawInstallables) + for (auto i : args.getRawInstallables()) res.push_back(parseFlakeRefWithFragment( expandTilde(i), - absPath(getCommandBaseDir())).first); + absPath(args.getCommandBaseDir())).first); return res; } -void RawInstallablesCommand::run(ref store) -{ - if (readFromStdIn && !isatty(STDIN_FILENO)) { - std::string word; - while (std::cin >> word) { - rawInstallables.emplace_back(std::move(word)); - } - } else { - applyDefaultInstallables(rawInstallables); - } - run(store, std::move(rawInstallables)); -} - -std::vector InstallableCommand::getFlakeRefsForCompletion() -{ - return { - parseFlakeRefWithFragment( - expandTilde(_installable), - absPath(getCommandBaseDir())).first - }; -} - -void InstallablesCommand::run(ref store, std::vector && rawInstallables) -{ - auto installables = parseInstallables(store, rawInstallables); - run(store, std::move(installables)); -} - -InstallableCommand::InstallableCommand() - : SourceExprCommand() -{ - expectArgs({ - .label = "installable", - .optional = true, - .handler = {&_installable}, - .completer = getCompleteInstallable(), - }); -} - -void InstallableCommand::run(ref store) -{ - auto installable = parseInstallable(store, _installable); - run(store, std::move(installable)); -} - void BuiltPathsCommand::applyDefaultInstallables(std::vector & rawInstallables) { if (rawInstallables.empty() && !all) diff --git a/src/libcmd/local.mk b/src/libcmd/local.mk index 541a7d2bac71..5c4d55851bae 100644 --- a/src/libcmd/local.mk +++ b/src/libcmd/local.mk @@ -6,10 +6,13 @@ libcmd_DIR := $(d) libcmd_SOURCES := $(wildcard $(d)/*.cc) -libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers +libcmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libexpr -I src/libmain -I src/libfetchers -I src/libstore-cmd libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread -libcmd_LIBS = libstore libutil libexpr libmain libfetchers +libcmd_LIBS = libstore libutil libexpr libmain libfetchers libstore-cmd $(eval $(call install-file-in, $(d)/nix-cmd.pc, $(libdir)/pkgconfig, 0644)) + +$(foreach i, $(wildcard $(d)/*.hh), \ + $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) diff --git a/src/libexpr/local.mk b/src/libexpr/local.mk index d243b9cec1d1..91dc8136de3c 100644 --- a/src/libexpr/local.mk +++ b/src/libexpr/local.mk @@ -38,9 +38,13 @@ clean-files += $(d)/parser-tab.cc $(d)/parser-tab.hh $(d)/lexer-tab.cc $(d)/lexe $(eval $(call install-file-in, $(d)/nix-expr.pc, $(libdir)/pkgconfig, 0644)) -$(foreach i, $(wildcard src/libexpr/value/*.hh), \ +$(foreach i, $(wildcard $(d)/*.hh), \ + $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) + +$(foreach i, $(wildcard $(d)/value/*.hh), \ $(eval $(call install-file-in, $(i), $(includedir)/nix/value, 0644))) -$(foreach i, $(wildcard src/libexpr/flake/*.hh), \ + +$(foreach i, $(wildcard $(d)/flake/*.hh), \ $(eval $(call install-file-in, $(i), $(includedir)/nix/flake, 0644))) $(d)/primops.cc: $(d)/imported-drv-to-derivation.nix.gen.hh $(d)/primops/derivation.nix.gen.hh $(d)/fetchurl.nix.gen.hh diff --git a/src/libfetchers/local.mk b/src/libfetchers/local.mk index 2e8869d83fa8..8008cfd81a9a 100644 --- a/src/libfetchers/local.mk +++ b/src/libfetchers/local.mk @@ -11,3 +11,6 @@ libfetchers_CXXFLAGS += -I src/libutil -I src/libstore libfetchers_LDFLAGS += -pthread libfetchers_LIBS = libutil libstore + +$(foreach i, $(wildcard $(d)/*.hh), \ + $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) diff --git a/src/libmain/common-args.hh b/src/libmain/common-args.hh index c35406c3bcc8..2330a2a3064f 100644 --- a/src/libmain/common-args.hh +++ b/src/libmain/common-args.hh @@ -50,13 +50,13 @@ struct MixJSON : virtual Args } }; -struct MixRepair : virtual Args +struct MixRepair { RepairFlag repair = NoRepair; - MixRepair() + MixRepair(AbstractArgs & args) { - addFlag({ + args.addFlag({ .longName = "repair", .description = "During evaluation, rewrite missing or corrupted files in the Nix store. " diff --git a/src/libmain/local.mk b/src/libmain/local.mk index 99da95e27975..95dc6cd9abbf 100644 --- a/src/libmain/local.mk +++ b/src/libmain/local.mk @@ -15,3 +15,6 @@ libmain_LIBS = libstore libutil libmain_ALLOW_UNDEFINED = 1 $(eval $(call install-file-in, $(d)/nix-main.pc, $(libdir)/pkgconfig, 0644)) + +$(foreach i, $(wildcard $(d)/*.hh), \ + $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) diff --git a/src/libcmd/built-path.cc b/src/libstore-cmd/built-path.cc similarity index 100% rename from src/libcmd/built-path.cc rename to src/libstore-cmd/built-path.cc diff --git a/src/libcmd/built-path.hh b/src/libstore-cmd/built-path.hh similarity index 100% rename from src/libcmd/built-path.hh rename to src/libstore-cmd/built-path.hh diff --git a/src/libcmd/installable-derived-path.cc b/src/libstore-cmd/installable-derived-path.cc similarity index 100% rename from src/libcmd/installable-derived-path.cc rename to src/libstore-cmd/installable-derived-path.cc diff --git a/src/libcmd/installable-derived-path.hh b/src/libstore-cmd/installable-derived-path.hh similarity index 86% rename from src/libcmd/installable-derived-path.hh rename to src/libstore-cmd/installable-derived-path.hh index e0b4f18b38be..e7d45df30543 100644 --- a/src/libcmd/installable-derived-path.hh +++ b/src/libstore-cmd/installable-derived-path.hh @@ -1,11 +1,11 @@ #pragma once ///@file -#include "installables.hh" +#include "store-installables.hh" namespace nix { -struct InstallableDerivedPath : Installable +struct InstallableDerivedPath : virtual Installable { ref store; DerivedPath derivedPath; diff --git a/src/libcmd/legacy.cc b/src/libstore-cmd/legacy.cc similarity index 100% rename from src/libcmd/legacy.cc rename to src/libstore-cmd/legacy.cc diff --git a/src/libcmd/legacy.hh b/src/libstore-cmd/legacy.hh similarity index 100% rename from src/libcmd/legacy.hh rename to src/libstore-cmd/legacy.hh diff --git a/src/libstore-cmd/local.mk b/src/libstore-cmd/local.mk new file mode 100644 index 000000000000..167375cf2286 --- /dev/null +++ b/src/libstore-cmd/local.mk @@ -0,0 +1,18 @@ +libraries += libstore-cmd + +libstore-cmd_NAME = libnixstore-cmd + +libstore-cmd_DIR := $(d) + +libstore-cmd_SOURCES := $(wildcard $(d)/*.cc) + +libstore-cmd_CXXFLAGS += -I src/libutil -I src/libstore -I src/libmain + +libstore-cmd_LDFLAGS += $(LOWDOWN_LIBS) -pthread + +libstore-cmd_LIBS = libstore libutil libmain + +$(eval $(call install-file-in, $(d)/nix-store-cmd.pc, $(libdir)/pkgconfig, 0644)) + +$(foreach i, $(wildcard $(d)/*.hh), \ + $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) diff --git a/src/libcmd/markdown.cc b/src/libstore-cmd/markdown.cc similarity index 100% rename from src/libcmd/markdown.cc rename to src/libstore-cmd/markdown.cc diff --git a/src/libcmd/markdown.hh b/src/libstore-cmd/markdown.hh similarity index 100% rename from src/libcmd/markdown.hh rename to src/libstore-cmd/markdown.hh diff --git a/src/libstore-cmd/nix-store-cmd.pc.in b/src/libstore-cmd/nix-store-cmd.pc.in new file mode 100644 index 000000000000..6f2ea40fd7a0 --- /dev/null +++ b/src/libstore-cmd/nix-store-cmd.pc.in @@ -0,0 +1,9 @@ +prefix=@prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Nix +Description: Nix Package Manager +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lnixstore-cmd +Cflags: -I${includedir}/nix -std=c++17 diff --git a/src/libstore-cmd/store-command.cc b/src/libstore-cmd/store-command.cc index de9f546fc701..3522812625c8 100644 --- a/src/libstore-cmd/store-command.cc +++ b/src/libstore-cmd/store-command.cc @@ -1,10 +1,8 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" #include "local-fs-store.hh" #include "derivations.hh" -#include "nixexpr.hh" #include "profiles.hh" -#include "repl.hh" #include @@ -34,18 +32,14 @@ nlohmann::json NixMultiCommand::toJSON() return MultiCommand::toJSON(); } -StoreCommand::StoreCommand() -{ -} - -ref StoreCommand::getStore() +ref HasStore::getStore() { if (!_store) _store = createStore(); return ref(_store); } -ref StoreCommand::createStore() +ref HasStore::createStore() { return openStore(); } @@ -85,54 +79,16 @@ ref CopyCommand::getDstStore() return dstUri.empty() ? openStore() : openStore(dstUri); } -EvalCommand::EvalCommand() -{ - addFlag({ - .longName = "debugger", - .description = "Start an interactive environment if evaluation fails.", - .category = MixEvalArgs::category, - .handler = {&startReplOnEvalErrors, true}, - }); -} - -EvalCommand::~EvalCommand() -{ - if (evalState) - evalState->maybePrintStats(); -} - -ref EvalCommand::getEvalStore() +ref HasDrvStore::getDrvStore() { - if (!evalStore) - evalStore = evalStoreUrl ? openStore(*evalStoreUrl) : getStore(); - return ref(evalStore); -} - -ref EvalCommand::getEvalState() -{ - if (!evalState) { - evalState = - #if HAVE_BOEHMGC - std::allocate_shared(traceable_allocator(), - searchPath, getEvalStore(), getStore()) - #else - std::make_shared( - searchPath, getEvalStore(), getStore()) - #endif - ; - - evalState->repair = repair; - - if (startReplOnEvalErrors) { - evalState->debugRepl = &AbstractNixRepl::runSimple; - }; - } - return ref(evalState); + if (!drvStore) + drvStore = getStore(); + return ref(drvStore); } -MixOperateOnOptions::MixOperateOnOptions() +MixOperateOnOptions::MixOperateOnOptions(AbstractArgs & args) { - addFlag({ + args.addFlag({ .longName = "derivation", .description = "Operate on the [store derivation](../../glossary.md#gloss-store-derivation) rather than its outputs.", .category = installablesCategory, @@ -141,7 +97,8 @@ MixOperateOnOptions::MixOperateOnOptions() } BuiltPathsCommand::BuiltPathsCommand(bool recursive) - : recursive(recursive) + : MixOperateOnOptions(static_cast(*this)) + , recursive(recursive) { if (recursive) addFlag({ @@ -177,7 +134,7 @@ void BuiltPathsCommand::run(ref store, Installables && installables) for (auto & p : store->queryAllValidPaths()) paths.emplace_back(BuiltPath::Opaque{p}); } else { - paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables); + paths = Installable::toBuiltPaths(getDrvStore(), store, realiseMode, operateOn, installables); if (recursive) { // XXX: This only computes the store path closure, ignoring // intermediate realisations @@ -319,4 +276,13 @@ void MixEnvironment::setEnviron() { } } +ParseInstallableArgs::MakeDefaultFun * ParseInstallableArgs::makeDefault = nullptr; + +ParseInstallableArgs::RegisterDefault::RegisterDefault(MakeDefaultFun fun) +{ + if (ParseInstallableArgs::makeDefault) + throw Error("Default already registered!"); + makeDefault = fun; +} + } diff --git a/src/libstore-cmd/store-command.hh b/src/libstore-cmd/store-command.hh index 120c832ac23b..023e8587cd52 100644 --- a/src/libstore-cmd/store-command.hh +++ b/src/libstore-cmd/store-command.hh @@ -1,11 +1,9 @@ #pragma once ///@file -#include "installable-value.hh" +#include "store-installables.hh" #include "args.hh" -#include "common-eval-args.hh" #include "path.hh" -#include "flake/lockfile.hh" #include @@ -15,8 +13,6 @@ extern std::string programPath; extern char * * savedArgv; -class EvalState; -struct Pos; class Store; static constexpr Command::Category catHelp = -1; @@ -34,22 +30,25 @@ struct NixMultiCommand : virtual MultiCommand, virtual Command // For the overloaded run methods #pragma GCC diagnostic ignored "-Woverloaded-virtual" +struct HasStore +{ + ref getStore(); + virtual ref createStore(); + +private: + std::shared_ptr _store; +}; + /** * A command that requires a \ref Store "Nix store". */ -struct StoreCommand : virtual Command +struct StoreCommand : virtual Command, virtual HasStore { - StoreCommand(); - void run() override; - ref getStore(); - virtual ref createStore(); /** - * Main entry point, with a `Store` provided + * Main entry point, with a Store provided */ + void run() override; virtual void run(ref) = 0; - -private: - std::shared_ptr _store; }; /** @@ -67,88 +66,94 @@ struct CopyCommand : virtual StoreCommand ref getDstStore(); }; -/** - * A command that needs to evaluate Nix language expressions. - */ -struct EvalCommand : virtual StoreCommand, MixEvalArgs +struct HasDrvStore : virtual HasStore { - bool startReplOnEvalErrors = false; - bool ignoreExceptionsDuringTry = false; - - EvalCommand(); + virtual ref getDrvStore(); - ~EvalCommand(); - - ref getEvalStore(); - - ref getEvalState(); - -private: - std::shared_ptr evalStore; - - std::shared_ptr evalState; +protected: + std::shared_ptr drvStore; }; -/** - * A mixin class for commands that process flakes, adding a few standard - * flake-related options/flags. - */ -struct MixFlakeOptions : virtual Args, EvalCommand +struct DrvCommand : virtual HasDrvStore, virtual StoreCommand { - flake::LockFlags lockFlags; - - MixFlakeOptions(); +}; +struct GetRawInstallables : virtual AbstractArgs +{ /** - * The completion for some of these flags depends on the flake(s) in - * question. + * Get the unparsed installables allociated with this command * - * This method should be implemented to gather all flakerefs the - * command is operating with (presumably specified via some other - * arguments) so that the completions for these flags can use them. + * This is needed for the completions of *other* arguments that + * depends on these. + * + * @return A fresh vector, because the underlying command doesn't + * always store a vector of raw installables. */ - virtual std::vector getFlakeRefsForCompletion() - { return {}; } + virtual std::vector getRawInstallables() = 0; }; -struct SourceExprCommand : virtual Args, MixFlakeOptions +struct ParseInstallableArgs { - std::optional file; - std::optional expr; - - SourceExprCommand(); - - Installables parseInstallables( - ref store, std::vector ss); - - ref parseInstallable( - ref store, const std::string & installable); + virtual Installables parseInstallables( + ref store, std::vector ss) = 0; - virtual Strings getDefaultFlakeAttrPaths(); - - virtual Strings getDefaultFlakeAttrPathPrefixes(); + virtual ref parseInstallable( + ref store, const std::string & installable) = 0; /** * Complete an installable from the given prefix. */ - void completeInstallable(AddCompletions & completions, std::string_view prefix); + virtual void completeInstallable(AddCompletions & completions, std::string_view prefix) + { }; /** * Convenience wrapper around the underlying function to make setting the * callback easier. */ - CompleterClosure getCompleteInstallable(); + AbstractArgs::CompleterClosure getCompleteInstallable(); + + // FIXME make const after CmdRepl's override is fixed up + virtual void applyDefaultInstallables(std::vector & rawInstallables) = 0; + + typedef ref MakeDefaultFun(GetRawInstallables &); + + static MakeDefaultFun * makeDefault; + + struct RegisterDefault + { + RegisterDefault(MakeDefaultFun); + }; }; -/** - * A mixin class for commands that need a read-only flag. - * - * What exactly is "read-only" is unspecified, but it will usually be - * the \ref Store "Nix store". - */ -struct MixReadOnlyOption : virtual Args +struct MixDefaultParseInstallableArgs : virtual ParseInstallableArgs { - MixReadOnlyOption(); + ref def; + + MixDefaultParseInstallableArgs(GetRawInstallables & args) + : def(ParseInstallableArgs::makeDefault(args)) + { } + + Installables parseInstallables( + ref store, std::vector ss) override + { + return def->parseInstallables(store, std::move(ss)); + } + + ref parseInstallable( + ref store, const std::string & installable) override + { + return def->parseInstallable(store, installable); + } + + void completeInstallable(AddCompletions & completions, std::string_view prefix) override + { + return def->completeInstallable(completions, prefix); + } + + virtual void applyDefaultInstallables(std::vector & rawInstallables) override + { + return def->applyDefaultInstallables(rawInstallables); + } }; /** @@ -157,7 +162,7 @@ struct MixReadOnlyOption : virtual Args * This is needed by `CmdRepl` which wants to load (and reload) the * installables itself. */ -struct RawInstallablesCommand : virtual Args, SourceExprCommand +struct RawInstallablesCommand : virtual DrvCommand, virtual GetRawInstallables, virtual ParseInstallableArgs { RawInstallablesCommand(); @@ -165,12 +170,9 @@ struct RawInstallablesCommand : virtual Args, SourceExprCommand void run(ref store) override; - // FIXME make const after `CmdRepl`'s override is fixed up - virtual void applyDefaultInstallables(std::vector & rawInstallables); - bool readFromStdIn = false; - std::vector getFlakeRefsForCompletion() override; + std::vector getRawInstallables() override; private: @@ -181,7 +183,7 @@ private: * A command that operates on a list of "installables", which can be * store paths, attribute paths, Nix expressions, etc. */ -struct InstallablesCommand : RawInstallablesCommand +struct AbstractInstallablesCommand : virtual RawInstallablesCommand { virtual void run(ref store, Installables && installables) = 0; @@ -191,26 +193,41 @@ struct InstallablesCommand : RawInstallablesCommand /** * A command that operates on exactly one "installable". */ -struct InstallableCommand : virtual Args, SourceExprCommand +struct InstallablesCommand : AbstractInstallablesCommand, MixDefaultParseInstallableArgs { - InstallableCommand(); + InstallablesCommand() + : MixDefaultParseInstallableArgs(static_cast(*this)) + { } +}; + +/* A core command that operates on exactly one "installable" */ +struct AbstractInstallableCommand : virtual DrvCommand, virtual GetRawInstallables, virtual ParseInstallableArgs +{ + AbstractInstallableCommand(); virtual void run(ref store, ref installable) = 0; void run(ref store) override; - std::vector getFlakeRefsForCompletion() override; + std::vector getRawInstallables() override final; -private: +protected: std::string _installable{"."}; }; -struct MixOperateOnOptions : virtual Args +struct InstallableCommand : AbstractInstallableCommand, MixDefaultParseInstallableArgs +{ + InstallableCommand() + : MixDefaultParseInstallableArgs(static_cast(*this)) + { } +}; + +struct MixOperateOnOptions { OperateOn operateOn = OperateOn::Output; - MixOperateOnOptions(); + MixOperateOnOptions(AbstractArgs & args); }; /** @@ -219,7 +236,7 @@ struct MixOperateOnOptions : virtual Args * If the argument the user passes is a some sort of recipe for a path * not yet built, it must be built first. */ -struct BuiltPathsCommand : InstallablesCommand, virtual MixOperateOnOptions +struct BuiltPathsCommand : InstallablesCommand, MixOperateOnOptions { private: @@ -326,22 +343,6 @@ struct MixEnvironment : virtual Args { void setEnviron(); }; -void completeFlakeInputPath( - AddCompletions & completions, - ref evalState, - const std::vector & flakeRefs, - std::string_view prefix); - -void completeFlakeRef(AddCompletions & completions, ref store, std::string_view prefix); - -void completeFlakeRefWithFragment( - AddCompletions & completions, - ref evalState, - flake::LockFlags lockFlags, - Strings attrPathPrefixes, - const Strings & defaultFlakeAttrPaths, - std::string_view prefix); - std::string showVersions(const std::set & versions); void printClosureDiff( diff --git a/src/libstore-cmd/store-installables.cc b/src/libstore-cmd/store-installables.cc index 1c6103020f7f..f0095c6c2558 100644 --- a/src/libstore-cmd/store-installables.cc +++ b/src/libstore-cmd/store-installables.cc @@ -1,26 +1,14 @@ #include "globals.hh" -#include "installables.hh" -#include "installable-derived-path.hh" -#include "installable-attr-path.hh" -#include "installable-flake.hh" +#include "store-installables.hh" #include "outputs-spec.hh" #include "users.hh" #include "util.hh" -#include "command.hh" -#include "attr-path.hh" -#include "common-eval-args.hh" -#include "derivations.hh" -#include "eval-inline.hh" -#include "eval.hh" -#include "eval-settings.hh" -#include "get-drvs.hh" +#include "store-command.hh" #include "store-api.hh" +#include "derivations.hh" +#include "build-result.hh" #include "shared.hh" -#include "flake/flake.hh" -#include "eval-cache.hh" #include "url.hh" -#include "registry.hh" -#include "build-result.hh" #include #include @@ -29,353 +17,13 @@ namespace nix { -void completeFlakeInputPath( - AddCompletions & completions, - ref evalState, - const std::vector & flakeRefs, - std::string_view prefix) -{ - for (auto & flakeRef : flakeRefs) { - auto flake = flake::getFlake(*evalState, flakeRef, true); - for (auto & input : flake.inputs) - if (hasPrefix(input.first, prefix)) - completions.add(input.first); - } -} - -MixFlakeOptions::MixFlakeOptions() -{ - auto category = "Common flake-related options"; - - addFlag({ - .longName = "no-update-lock-file", - .description = "Do not allow any updates to the flake's lock file.", - .category = category, - .handler = {&lockFlags.updateLockFile, false} - }); - - addFlag({ - .longName = "no-write-lock-file", - .description = "Do not write the flake's newly generated lock file.", - .category = category, - .handler = {&lockFlags.writeLockFile, false} - }); - - addFlag({ - .longName = "no-registries", - .description = - "Don't allow lookups in the flake registries. This option is deprecated; use `--no-use-registries`.", - .category = category, - .handler = {[&]() { - lockFlags.useRegistries = false; - warn("'--no-registries' is deprecated; use '--no-use-registries'"); - }} - }); - - addFlag({ - .longName = "commit-lock-file", - .description = "Commit changes to the flake's lock file.", - .category = category, - .handler = {&lockFlags.commitLockFile, true} - }); - - addFlag({ - .longName = "override-input", - .description = "Override a specific flake input (e.g. `dwarffs/nixpkgs`). This implies `--no-write-lock-file`.", - .category = category, - .labels = {"input-path", "flake-url"}, - .handler = {[&](std::string inputPath, std::string flakeRef) { - lockFlags.writeLockFile = false; - lockFlags.inputOverrides.insert_or_assign( - flake::parseInputPath(inputPath), - parseFlakeRef(flakeRef, absPath(getCommandBaseDir()), true)); - }}, - .completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) { - if (n == 0) { - completeFlakeInputPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix); - } else if (n == 1) { - completeFlakeRef(completions, getEvalState()->store, prefix); - } - }} - }); - - addFlag({ - .longName = "reference-lock-file", - .description = "Read the given lock file instead of `flake.lock` within the top-level flake.", - .category = category, - .labels = {"flake-lock-path"}, - .handler = {[&](std::string lockFilePath) { - lockFlags.referenceLockFilePath = lockFilePath; - }}, - .completer = completePath - }); - - addFlag({ - .longName = "output-lock-file", - .description = "Write the given lock file instead of `flake.lock` within the top-level flake.", - .category = category, - .labels = {"flake-lock-path"}, - .handler = {[&](std::string lockFilePath) { - lockFlags.outputLockFilePath = lockFilePath; - }}, - .completer = completePath - }); - - addFlag({ - .longName = "inputs-from", - .description = "Use the inputs of the specified flake as registry entries.", - .category = category, - .labels = {"flake-url"}, - .handler = {[&](std::string flakeRef) { - auto evalState = getEvalState(); - auto flake = flake::lockFlake( - *evalState, - parseFlakeRef(flakeRef, absPath(getCommandBaseDir())), - { .writeLockFile = false }); - for (auto & [inputName, input] : flake.lockFile.root->inputs) { - auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes - if (auto input3 = std::dynamic_pointer_cast(input2)) { - overrideRegistry( - fetchers::Input::fromAttrs({{"type","indirect"}, {"id", inputName}}), - input3->lockedRef.input, - {}); - } - } - }}, - .completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) { - completeFlakeRef(completions, getEvalState()->store, prefix); - }} - }); -} - -SourceExprCommand::SourceExprCommand() -{ - addFlag({ - .longName = "file", - .shortName = 'f', - .description = - "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression stored in *file*. " - "If *file* is the character -, then a Nix expression will be read from standard input. " - "Implies `--impure`.", - .category = installablesCategory, - .labels = {"file"}, - .handler = {&file}, - .completer = completePath - }); - - addFlag({ - .longName = "expr", - .description = "Interpret [*installables*](@docroot@/command-ref/new-cli/nix.md#installables) as attribute paths relative to the Nix expression *expr*.", - .category = installablesCategory, - .labels = {"expr"}, - .handler = {&expr} - }); -} - -MixReadOnlyOption::MixReadOnlyOption() -{ - addFlag({ - .longName = "read-only", - .description = - "Do not instantiate each evaluated derivation. " - "This improves performance, but can cause errors when accessing " - "store paths of derivations during evaluation.", - .handler = {&settings.readOnlyMode, true}, - }); -} - -Strings SourceExprCommand::getDefaultFlakeAttrPaths() -{ - return { - "packages." + settings.thisSystem.get() + ".default", - "defaultPackage." + settings.thisSystem.get() - }; -} - -Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes() -{ - return { - // As a convenience, look for the attribute in - // 'outputs.packages'. - "packages." + settings.thisSystem.get() + ".", - // As a temporary hack until Nixpkgs is properly converted - // to provide a clean 'packages' set, look in 'legacyPackages'. - "legacyPackages." + settings.thisSystem.get() + "." - }; -} - -Args::CompleterClosure SourceExprCommand::getCompleteInstallable() +Args::CompleterClosure ParseInstallableArgs::getCompleteInstallable() { return [this](AddCompletions & completions, size_t, std::string_view prefix) { completeInstallable(completions, prefix); }; } -void SourceExprCommand::completeInstallable(AddCompletions & completions, std::string_view prefix) -{ - try { - if (file) { - completions.setType(AddCompletions::Type::Attrs); - - evalSettings.pureEval = false; - auto state = getEvalState(); - Expr *e = state->parseExprFromFile( - resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file))) - ); - - Value root; - state->eval(e, root); - - auto autoArgs = getAutoArgs(*state); - - std::string prefix_ = std::string(prefix); - auto sep = prefix_.rfind('.'); - std::string searchWord; - if (sep != std::string::npos) { - searchWord = prefix_.substr(sep + 1, std::string::npos); - prefix_ = prefix_.substr(0, sep); - } else { - searchWord = prefix_; - prefix_ = ""; - } - - auto [v, pos] = findAlongAttrPath(*state, prefix_, *autoArgs, root); - Value &v1(*v); - state->forceValue(v1, pos); - Value v2; - state->autoCallFunction(*autoArgs, v1, v2); - - if (v2.type() == nAttrs) { - for (auto & i : *v2.attrs) { - std::string name = state->symbols[i.name]; - if (name.find(searchWord) == 0) { - if (prefix_ == "") - completions.add(name); - else - completions.add(prefix_ + "." + name); - } - } - } - } else { - completeFlakeRefWithFragment( - completions, - getEvalState(), - lockFlags, - getDefaultFlakeAttrPathPrefixes(), - getDefaultFlakeAttrPaths(), - prefix); - } - } catch (EvalError&) { - // Don't want eval errors to mess-up with the completion engine, so let's just swallow them - } -} - -void completeFlakeRefWithFragment( - AddCompletions & completions, - ref evalState, - flake::LockFlags lockFlags, - Strings attrPathPrefixes, - const Strings & defaultFlakeAttrPaths, - std::string_view prefix) -{ - /* Look for flake output attributes that match the - prefix. */ - try { - auto hash = prefix.find('#'); - if (hash == std::string::npos) { - completeFlakeRef(completions, evalState->store, prefix); - } else { - completions.setType(AddCompletions::Type::Attrs); - - auto fragment = prefix.substr(hash + 1); - std::string prefixRoot = ""; - if (fragment.starts_with(".")){ - fragment = fragment.substr(1); - prefixRoot = "."; - } - auto flakeRefS = std::string(prefix.substr(0, hash)); - - // TODO: ideally this would use the command base directory instead of assuming ".". - auto flakeRef = parseFlakeRef(expandTilde(flakeRefS), absPath(".")); - - auto evalCache = openEvalCache(*evalState, - std::make_shared(lockFlake(*evalState, flakeRef, lockFlags))); - - auto root = evalCache->getRoot(); - - if (prefixRoot == "."){ - attrPathPrefixes.clear(); - } - /* Complete 'fragment' relative to all the - attrpath prefixes as well as the root of the - flake. */ - attrPathPrefixes.push_back(""); - - for (auto & attrPathPrefixS : attrPathPrefixes) { - auto attrPathPrefix = parseAttrPath(*evalState, attrPathPrefixS); - auto attrPathS = attrPathPrefixS + std::string(fragment); - auto attrPath = parseAttrPath(*evalState, attrPathS); - - std::string lastAttr; - if (!attrPath.empty() && !hasSuffix(attrPathS, ".")) { - lastAttr = evalState->symbols[attrPath.back()]; - attrPath.pop_back(); - } - - auto attr = root->findAlongAttrPath(attrPath); - if (!attr) continue; - - for (auto & attr2 : (*attr)->getAttrs()) { - if (hasPrefix(evalState->symbols[attr2], lastAttr)) { - auto attrPath2 = (*attr)->getAttrPath(attr2); - /* Strip the attrpath prefix. */ - attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size()); - completions.add(flakeRefS + "#" + prefixRoot + concatStringsSep(".", evalState->symbols.resolve(attrPath2))); - } - } - } - - /* And add an empty completion for the default - attrpaths. */ - if (fragment.empty()) { - for (auto & attrPath : defaultFlakeAttrPaths) { - auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath)); - if (!attr) continue; - completions.add(flakeRefS + "#" + prefixRoot); - } - } - } - } catch (Error & e) { - warn(e.msg()); - } -} - -void completeFlakeRef(AddCompletions & completions, ref store, std::string_view prefix) -{ - if (!experimentalFeatureSettings.isEnabled(Xp::Flakes)) - return; - - if (prefix == "") - completions.add("."); - - Args::completeDir(completions, 0, prefix); - - /* Look for registry entries that match the prefix. */ - for (auto & registry : fetchers::getRegistries(store)) { - for (auto & entry : registry->entries) { - auto from = entry.from.to_string(); - if (!hasPrefix(prefix, "flake:") && hasPrefix(from, "flake:")) { - std::string from2(from, 6); - if (hasPrefix(from2, prefix)) - completions.add(from2); - } else { - if (hasPrefix(from, prefix)) - completions.add(from); - } - } - } -} - DerivedPathWithInfo Installable::toDerivedPath() { auto buildables = toDerivedPaths(); @@ -396,124 +44,6 @@ static StorePath getDeriver( return *derivers.begin(); } -ref openEvalCache( - EvalState & state, - std::shared_ptr lockedFlake) -{ - auto fingerprint = lockedFlake->getFingerprint(); - return make_ref( - evalSettings.useEvalCache && evalSettings.pureEval - ? std::optional { std::cref(fingerprint) } - : std::nullopt, - state, - [&state, lockedFlake]() - { - /* For testing whether the evaluation cache is - complete. */ - if (getEnv("NIX_ALLOW_EVAL").value_or("1") == "0") - throw Error("not everything is cached, but evaluation is not allowed"); - - auto vFlake = state.allocValue(); - flake::callFlake(state, *lockedFlake, *vFlake); - - state.forceAttrs(*vFlake, noPos, "while parsing cached flake data"); - - auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs")); - assert(aOutputs); - - return aOutputs->value; - }); -} - -Installables SourceExprCommand::parseInstallables( - ref store, std::vector ss) -{ - Installables result; - - if (file || expr) { - if (file && expr) - throw UsageError("'--file' and '--expr' are exclusive"); - - // FIXME: backward compatibility hack - if (file) evalSettings.pureEval = false; - - auto state = getEvalState(); - auto vFile = state->allocValue(); - - if (file == "-") { - auto e = state->parseStdin(); - state->eval(e, *vFile); - } - else if (file) { - state->evalFile(lookupFileArg(*state, *file, CanonPath::fromCwd(getCommandBaseDir())), *vFile); - } - else { - CanonPath dir(CanonPath::fromCwd(getCommandBaseDir())); - auto e = state->parseExprFromString(*expr, state->rootPath(dir)); - state->eval(e, *vFile); - } - - for (auto & s : ss) { - auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s); - result.push_back( - make_ref( - InstallableAttrPath::parse( - state, *this, vFile, std::move(prefix), std::move(extendedOutputsSpec)))); - } - - } else { - - for (auto & s : ss) { - std::exception_ptr ex; - - auto [prefix_, extendedOutputsSpec_] = ExtendedOutputsSpec::parse(s); - // To avoid clang's pedantry - auto prefix = std::move(prefix_); - auto extendedOutputsSpec = std::move(extendedOutputsSpec_); - - if (prefix.find('/') != std::string::npos) { - try { - result.push_back(make_ref( - InstallableDerivedPath::parse(store, prefix, extendedOutputsSpec.raw))); - continue; - } catch (BadStorePath &) { - } catch (...) { - if (!ex) - ex = std::current_exception(); - } - } - - try { - auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath(getCommandBaseDir())); - result.push_back(make_ref( - this, - getEvalState(), - std::move(flakeRef), - fragment, - std::move(extendedOutputsSpec), - getDefaultFlakeAttrPaths(), - getDefaultFlakeAttrPathPrefixes(), - lockFlags)); - continue; - } catch (...) { - ex = std::current_exception(); - } - - std::rethrow_exception(ex); - } - } - - return result; -} - -ref SourceExprCommand::parseInstallable( - ref store, const std::string & installable) -{ - auto installables = parseInstallables(store, {installable}); - assert(installables.size() == 1); - return installables.front(); -} - static SingleBuiltPath getBuiltPath(ref evalStore, ref store, const SingleDerivedPath & b) { return std::visit( @@ -742,26 +272,6 @@ RawInstallablesCommand::RawInstallablesCommand() }); } -void RawInstallablesCommand::applyDefaultInstallables(std::vector & rawInstallables) -{ - if (rawInstallables.empty()) { - // FIXME: commands like "nix profile install" should not have a - // default, probably. - rawInstallables.push_back("."); - } -} - -std::vector RawInstallablesCommand::getFlakeRefsForCompletion() -{ - applyDefaultInstallables(rawInstallables); - std::vector res; - for (auto i : rawInstallables) - res.push_back(parseFlakeRefWithFragment( - expandTilde(i), - absPath(getCommandBaseDir())).first); - return res; -} - void RawInstallablesCommand::run(ref store) { if (readFromStdIn && !isatty(STDIN_FILENO)) { @@ -775,23 +285,26 @@ void RawInstallablesCommand::run(ref store) run(store, std::move(rawInstallables)); } -std::vector InstallableCommand::getFlakeRefsForCompletion() +std::vector RawInstallablesCommand::getRawInstallables() { - return { - parseFlakeRefWithFragment( - expandTilde(_installable), - absPath(getCommandBaseDir())).first - }; + applyDefaultInstallables(rawInstallables); + return rawInstallables; +} + +std::vector AbstractInstallableCommand::getRawInstallables() +{ + // FIXME don't leak + return { _installable }; } -void InstallablesCommand::run(ref store, std::vector && rawInstallables) +void AbstractInstallablesCommand::run(ref store, std::vector && rawInstallables) { auto installables = parseInstallables(store, rawInstallables); run(store, std::move(installables)); } -InstallableCommand::InstallableCommand() - : SourceExprCommand() +AbstractInstallableCommand::AbstractInstallableCommand() + : ParseInstallableArgs() { expectArgs({ .label = "installable", @@ -801,7 +314,7 @@ InstallableCommand::InstallableCommand() }); } -void InstallableCommand::run(ref store) +void AbstractInstallableCommand::run(ref store) { auto installable = parseInstallable(store, _installable); run(store, std::move(installable)); diff --git a/src/libstore/local.mk b/src/libstore/local.mk index 0be0bf310589..42aaee09a165 100644 --- a/src/libstore/local.mk +++ b/src/libstore/local.mk @@ -61,8 +61,11 @@ clean-files += $(d)/schema.sql.gen.hh $(d)/ca-specific-schema.sql.gen.hh $(eval $(call install-file-in, $(d)/nix-store.pc, $(libdir)/pkgconfig, 0644)) -$(foreach i, $(wildcard src/libstore/builtins/*.hh), \ +$(foreach i, $(wildcard $(d)/*.hh), \ + $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) + +$(foreach i, $(wildcard $(d)/builtins/*.hh), \ $(eval $(call install-file-in, $(i), $(includedir)/nix/builtins, 0644))) -$(foreach i, $(wildcard src/libstore/build/*.hh), \ +$(foreach i, $(wildcard $(d)/build/*.hh), \ $(eval $(call install-file-in, $(i), $(includedir)/nix/build, 0644))) diff --git a/src/libutil/args.cc b/src/libutil/args.cc index 876d11142e26..be6246192a84 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -597,12 +597,12 @@ static void _completePath(AddCompletions & completions, std::string_view prefix, globfree(&globbuf); } -void Args::completePath(AddCompletions & completions, size_t, std::string_view prefix) +void AbstractArgs::completePath(AddCompletions & completions, size_t, std::string_view prefix) { _completePath(completions, prefix, false); } -void Args::completeDir(AddCompletions & completions, size_t, std::string_view prefix) +void AbstractArgs::completeDir(AddCompletions & completions, size_t, std::string_view prefix) { _completePath(completions, prefix, true); } diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 7af82b17884c..bffbfb5ba602 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -22,41 +22,15 @@ class RootArgs; class AddCompletions; -class Args +struct AbstractArgs { -public: - - /** - * Return a short one-line description of the command. - */ - virtual std::string description() { return ""; } - - virtual bool forceImpureByDefault() { return false; } - - /** - * Return documentation about this command, in Markdown format. - */ - virtual std::string doc() { return ""; } - - /** - * @brief Get the base directory for the command. - * - * @return Generally the working directory, but in case of a shebang - * interpreter, returns the directory of the script. - * - * This only returns the correct value after parseCmdline() has run. - */ - virtual Path getCommandBaseDir() const; - -protected: - /** * The largest `size_t` is used to indicate the "any" arity, for * handlers/flags/arguments that accept an arbitrary number of * arguments. */ - static const size_t ArityAny = std::numeric_limits::max(); + static constexpr size_t ArityAny = std::numeric_limits::max(); /** * Arguments (flags/options and positional) have a "handler" which is @@ -179,6 +153,57 @@ protected: static Flag mkHashTypeOptFlag(std::string && longName, std::optional * oht); }; + virtual void addFlag(Flag && flag) = 0; + + /** + * Description of positional arguments + * + * These are arguments that do not start with a `-`, and for which + * the order does matter. + */ + struct ExpectedArg + { + std::string label; + bool optional = false; + Handler handler; + CompleterClosure completer; + }; + + virtual void expectArgs(ExpectedArg && arg) = 0; + + /** + * @brief Get the base directory for the command. + * + * @return Generally the working directory, but in case of a shebang + * interpreter, returns the directory of the script. + * + * This only returns the correct value after parseCmdline() has run. + */ + virtual Path getCommandBaseDir() const = 0; + + static CompleterFun completePath; + + static CompleterFun completeDir; +}; + +class Args : public virtual AbstractArgs +{ +public: + + /** + * Return a short one-line description of the command. + */ + virtual std::string description() { return ""; } + + virtual bool forceImpureByDefault() { return false; } + + /** + * Return documentation about this command, in Markdown format. + */ + virtual std::string doc() { return ""; } + +protected: + /** * Index of all registered "long" flag descriptions (flags like * `--long`). @@ -197,20 +222,6 @@ protected: */ virtual bool processFlag(Strings::iterator & pos, Strings::iterator end); - /** - * Description of positional arguments - * - * These are arguments that do not start with a `-`, and for which - * the order does matter. - */ - struct ExpectedArg - { - std::string label; - bool optional = false; - Handler handler; - CompleterClosure completer; - }; - /** * Queue of expected positional argument forms. * @@ -223,11 +234,11 @@ protected: std::list expectedArgs; /** * List of processed positional argument forms. - * + * * All items removed from `expectedArgs` are added here. After all * arguments were processed, this list should be exactly the same as * `expectedArgs` was before. - * + * * This list is used to extend the lifetime of the argument forms. * If this is not done, some closures that reference the command * itself will segfault. @@ -256,15 +267,17 @@ protected: public: - void addFlag(Flag && flag); + void addFlag(Flag && flag) override; void removeFlag(const std::string & longName); - void expectArgs(ExpectedArg && arg) + void expectArgs(ExpectedArg && arg) override final { expectedArgs.emplace_back(std::move(arg)); } + virtual Path getCommandBaseDir() const override; + /** * Expect a string argument. */ @@ -288,10 +301,6 @@ public: }); } - static CompleterFun completePath; - - static CompleterFun completeDir; - virtual nlohmann::json toJSON(); friend class MultiCommand; diff --git a/src/libutil/local.mk b/src/libutil/local.mk index 81efaafeca85..34b543c68d86 100644 --- a/src/libutil/local.mk +++ b/src/libutil/local.mk @@ -16,3 +16,6 @@ $(foreach i, $(wildcard $(d)/args/*.hh), \ ifeq ($(HAVE_LIBCPUID), 1) libutil_LDFLAGS += -lcpuid endif + +$(foreach i, $(wildcard $(d)/*.hh), \ + $(eval $(call install-file-in, $(i), $(includedir)/nix, 0644))) diff --git a/src/nix-build/nix-build.cc b/src/nix-build/nix-build.cc index 75ce12a8c3e5..eed82c8639c3 100644 --- a/src/nix-build/nix-build.cc +++ b/src/nix-build/nix-build.cc @@ -152,7 +152,12 @@ static void main_nix_build(int argc, char * * argv) struct MyArgs : LegacyArgs, MixEvalArgs { - using LegacyArgs::LegacyArgs; + MyArgs(const std::string & programName, + std::function parseArg) + : MixRepair(static_cast(*this)) + , LegacyArgs(programName, parseArg) + , MixEvalArgs(static_cast(*this)) + { } }; MyArgs myArgs(myName, [&](Strings::iterator & arg, const Strings::iterator & end) { diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 213a20d933c9..d589e38f61cd 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1422,7 +1422,12 @@ static int main_nix_env(int argc, char * * argv) struct MyArgs : LegacyArgs, MixEvalArgs { - using LegacyArgs::LegacyArgs; + MyArgs(const std::string & programName, + std::function parseArg) + : MixRepair(static_cast(*this)) + , LegacyArgs(programName, parseArg) + , MixEvalArgs(static_cast(*this)) + { } }; MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) { diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index c67409e89e1c..db9b1e4ac420 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -104,7 +104,12 @@ static int main_nix_instantiate(int argc, char * * argv) struct MyArgs : LegacyArgs, MixEvalArgs { - using LegacyArgs::LegacyArgs; + MyArgs(const std::string & programName, + std::function parseArg) + : MixRepair(static_cast(*this)) + , LegacyArgs(programName, parseArg) + , MixEvalArgs(static_cast(*this)) + { } }; MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) { diff --git a/src/nix/add-file.md b/src/nix/common/add-file.md similarity index 100% rename from src/nix/add-file.md rename to src/nix/common/add-file.md diff --git a/src/nix/add-path.md b/src/nix/common/add-path.md similarity index 100% rename from src/nix/add-path.md rename to src/nix/common/add-path.md diff --git a/src/nix/add-to-store.cc b/src/nix/common/add-to-store.cc similarity index 98% rename from src/nix/add-to-store.cc rename to src/nix/common/add-to-store.cc index 39e5cc99dd2f..6c080e124cab 100644 --- a/src/nix/add-to-store.cc +++ b/src/nix/common/add-to-store.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include "store-api.hh" #include "archive.hh" diff --git a/src/nix/build.cc b/src/nix/common/build.cc similarity index 97% rename from src/nix/build.cc rename to src/nix/common/build.cc index 479100186597..330f066e7ec0 100644 --- a/src/nix/build.cc +++ b/src/nix/common/build.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include "shared.hh" #include "store-api.hh" @@ -65,13 +65,14 @@ static void createOutLinks(const Path& outLink, const std::vector(*this)) { addFlag({ .longName = "out-link", @@ -131,7 +132,7 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile } auto buildables = Installable::build( - getEvalStore(), store, + getDrvStore(), store, Realise::Outputs, installables, repair ? bmRepair : buildMode); diff --git a/src/nix/build.md b/src/nix/common/build.md similarity index 100% rename from src/nix/build.md rename to src/nix/common/build.md diff --git a/src/nix/cat.cc b/src/nix/common/cat.cc similarity index 98% rename from src/nix/cat.cc rename to src/nix/common/cat.cc index 6e5a736f2abe..0c4ea47fd6ff 100644 --- a/src/nix/cat.cc +++ b/src/nix/common/cat.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" #include "nar-accessor.hh" diff --git a/src/nix/copy.cc b/src/nix/common/copy.cc similarity index 98% rename from src/nix/copy.cc rename to src/nix/common/copy.cc index 151d282772f2..8be3e280642f 100644 --- a/src/nix/copy.cc +++ b/src/nix/common/copy.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" diff --git a/src/nix/copy.md b/src/nix/common/copy.md similarity index 100% rename from src/nix/copy.md rename to src/nix/common/copy.md diff --git a/src/nix/daemon.cc b/src/nix/common/daemon.cc similarity index 99% rename from src/nix/daemon.cc rename to src/nix/common/daemon.cc index 373dedf7cbc8..2585cff68b2b 100644 --- a/src/nix/daemon.cc +++ b/src/nix/common/daemon.cc @@ -2,7 +2,7 @@ #include "signals.hh" #include "unix-domain-socket.hh" -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "local-store.hh" #include "remote-store.hh" diff --git a/src/nix/daemon.md b/src/nix/common/daemon.md similarity index 100% rename from src/nix/daemon.md rename to src/nix/common/daemon.md diff --git a/src/nix/derivation-add.cc b/src/nix/common/derivation-add.cc similarity index 97% rename from src/nix/derivation-add.cc rename to src/nix/common/derivation-add.cc index 4d91d4538001..18191fd8df5b 100644 --- a/src/nix/derivation-add.cc +++ b/src/nix/common/derivation-add.cc @@ -1,6 +1,6 @@ // FIXME: rename to 'nix plan add' or 'nix derivation add'? -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include "store-api.hh" #include "archive.hh" diff --git a/src/nix/derivation-add.md b/src/nix/common/derivation-add.md similarity index 100% rename from src/nix/derivation-add.md rename to src/nix/common/derivation-add.md diff --git a/src/nix/derivation-show.cc b/src/nix/common/derivation-show.cc similarity index 98% rename from src/nix/derivation-show.cc rename to src/nix/common/derivation-show.cc index bf637246d83c..c06f5fd9baa8 100644 --- a/src/nix/derivation-show.cc +++ b/src/nix/common/derivation-show.cc @@ -1,7 +1,7 @@ // FIXME: integrate this with nix path-info? // FIXME: rename to 'nix store derivation show' or 'nix debug derivation show'? -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include "store-api.hh" #include "archive.hh" diff --git a/src/nix/derivation-show.md b/src/nix/common/derivation-show.md similarity index 100% rename from src/nix/derivation-show.md rename to src/nix/common/derivation-show.md diff --git a/src/nix/derivation.cc b/src/nix/common/derivation.cc similarity index 95% rename from src/nix/derivation.cc rename to src/nix/common/derivation.cc index cd3975a4f397..bacb74bb3503 100644 --- a/src/nix/derivation.cc +++ b/src/nix/common/derivation.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" using namespace nix; diff --git a/src/nix/diff-closures.cc b/src/nix/common/diff-closures.cc similarity index 87% rename from src/nix/diff-closures.cc rename to src/nix/common/diff-closures.cc index c7c37b66fbe9..fbd177e3a49b 100644 --- a/src/nix/diff-closures.cc +++ b/src/nix/common/diff-closures.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" #include "common-args.hh" @@ -106,11 +106,13 @@ void printClosureDiff( using namespace nix; -struct CmdDiffClosures : SourceExprCommand, MixOperateOnOptions +struct CmdDiffClosures : virtual DrvCommand, GetRawInstallables, MixDefaultParseInstallableArgs, MixOperateOnOptions { std::string _before, _after; CmdDiffClosures() + : MixDefaultParseInstallableArgs(static_cast(*this)) + , MixOperateOnOptions(static_cast(*this)) { expectArg("before", &_before); expectArg("after", &_after); @@ -128,12 +130,17 @@ struct CmdDiffClosures : SourceExprCommand, MixOperateOnOptions ; } + std::vector getRawInstallables() override + { + return { _before, _after }; + } + void run(ref store) override { auto before = parseInstallable(store, _before); - auto beforePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, before); + auto beforePath = Installable::toStorePath(getDrvStore(), store, Realise::Outputs, operateOn, before); auto after = parseInstallable(store, _after); - auto afterPath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, after); + auto afterPath = Installable::toStorePath(getDrvStore(), store, Realise::Outputs, operateOn, after); printClosureDiff(store, beforePath, afterPath, ""); } }; diff --git a/src/nix/diff-closures.md b/src/nix/common/diff-closures.md similarity index 100% rename from src/nix/diff-closures.md rename to src/nix/common/diff-closures.md diff --git a/src/nix/dump-path.cc b/src/nix/common/dump-path.cc similarity index 97% rename from src/nix/dump-path.cc rename to src/nix/common/dump-path.cc index c4edc894b896..352fa269b88c 100644 --- a/src/nix/dump-path.cc +++ b/src/nix/common/dump-path.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" #include "archive.hh" diff --git a/src/nix/hash.cc b/src/nix/common/hash.cc similarity index 99% rename from src/nix/hash.cc rename to src/nix/common/hash.cc index d6595dcca059..a99ee84cde46 100644 --- a/src/nix/hash.cc +++ b/src/nix/common/hash.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "hash.hh" #include "content-address.hh" #include "legacy.hh" diff --git a/src/nix/help-stores.md b/src/nix/common/help-stores.md similarity index 100% rename from src/nix/help-stores.md rename to src/nix/common/help-stores.md diff --git a/src/nix/key-convert-secret-to-public.md b/src/nix/common/key-convert-secret-to-public.md similarity index 100% rename from src/nix/key-convert-secret-to-public.md rename to src/nix/common/key-convert-secret-to-public.md diff --git a/src/nix/key-generate-secret.md b/src/nix/common/key-generate-secret.md similarity index 100% rename from src/nix/key-generate-secret.md rename to src/nix/common/key-generate-secret.md diff --git a/src/nix/log.cc b/src/nix/common/log.cc similarity index 98% rename from src/nix/log.cc rename to src/nix/common/log.cc index 9a9bd30f9619..dea76343b898 100644 --- a/src/nix/log.cc +++ b/src/nix/common/log.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include "shared.hh" #include "store-api.hh" diff --git a/src/nix/log.md b/src/nix/common/log.md similarity index 100% rename from src/nix/log.md rename to src/nix/common/log.md diff --git a/src/nix/ls.cc b/src/nix/common/ls.cc similarity index 99% rename from src/nix/ls.cc rename to src/nix/common/ls.cc index 231456c9c6c2..1bc349d269fe 100644 --- a/src/nix/ls.cc +++ b/src/nix/common/ls.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" #include "nar-accessor.hh" #include "common-args.hh" diff --git a/src/nix/make-content-addressed.cc b/src/nix/common/make-content-addressed.cc similarity index 98% rename from src/nix/make-content-addressed.cc rename to src/nix/common/make-content-addressed.cc index d9c988a9f5d9..a6634e83e7f4 100644 --- a/src/nix/make-content-addressed.cc +++ b/src/nix/common/make-content-addressed.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" #include "make-content-addressed.hh" #include "common-args.hh" diff --git a/src/nix/make-content-addressed.md b/src/nix/common/make-content-addressed.md similarity index 100% rename from src/nix/make-content-addressed.md rename to src/nix/common/make-content-addressed.md diff --git a/src/nix/nar-cat.md b/src/nix/common/nar-cat.md similarity index 100% rename from src/nix/nar-cat.md rename to src/nix/common/nar-cat.md diff --git a/src/nix/nar-dump-path.md b/src/nix/common/nar-dump-path.md similarity index 100% rename from src/nix/nar-dump-path.md rename to src/nix/common/nar-dump-path.md diff --git a/src/nix/nar-ls.md b/src/nix/common/nar-ls.md similarity index 100% rename from src/nix/nar-ls.md rename to src/nix/common/nar-ls.md diff --git a/src/nix/nar.cc b/src/nix/common/nar.cc similarity index 95% rename from src/nix/nar.cc rename to src/nix/common/nar.cc index 9815410cfc00..8fbf3349410d 100644 --- a/src/nix/nar.cc +++ b/src/nix/common/nar.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" using namespace nix; diff --git a/src/nix/nar.md b/src/nix/common/nar.md similarity index 100% rename from src/nix/nar.md rename to src/nix/common/nar.md diff --git a/src/nix/optimise-store.cc b/src/nix/common/optimise-store.cc similarity index 95% rename from src/nix/optimise-store.cc rename to src/nix/common/optimise-store.cc index 985006e5a544..9325ddd0db95 100644 --- a/src/nix/optimise-store.cc +++ b/src/nix/common/optimise-store.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" diff --git a/src/nix/optimise-store.md b/src/nix/common/optimise-store.md similarity index 100% rename from src/nix/optimise-store.md rename to src/nix/common/optimise-store.md diff --git a/src/nix/path-from-hash-part.cc b/src/nix/common/path-from-hash-part.cc similarity index 96% rename from src/nix/path-from-hash-part.cc rename to src/nix/common/path-from-hash-part.cc index 7f7cda8d3d38..d95397fd510c 100644 --- a/src/nix/path-from-hash-part.cc +++ b/src/nix/common/path-from-hash-part.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" using namespace nix; diff --git a/src/nix/path-from-hash-part.md b/src/nix/common/path-from-hash-part.md similarity index 100% rename from src/nix/path-from-hash-part.md rename to src/nix/common/path-from-hash-part.md diff --git a/src/nix/path-info.cc b/src/nix/common/path-info.cc similarity index 99% rename from src/nix/path-info.cc rename to src/nix/common/path-info.cc index 23198a12087d..154fcee34cf6 100644 --- a/src/nix/path-info.cc +++ b/src/nix/common/path-info.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" #include "common-args.hh" diff --git a/src/nix/path-info.md b/src/nix/common/path-info.md similarity index 100% rename from src/nix/path-info.md rename to src/nix/common/path-info.md diff --git a/src/nix/realisation.cc b/src/nix/common/realisation.cc similarity index 98% rename from src/nix/realisation.cc rename to src/nix/common/realisation.cc index e19e9321910f..c43863015a06 100644 --- a/src/nix/realisation.cc +++ b/src/nix/common/realisation.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include diff --git a/src/nix/realisation/info.md b/src/nix/common/realisation/info.md similarity index 100% rename from src/nix/realisation/info.md rename to src/nix/common/realisation/info.md diff --git a/src/nix/sigs.cc b/src/nix/common/sigs.cc similarity index 99% rename from src/nix/sigs.cc rename to src/nix/common/sigs.cc index a68616355072..2ecd87b44af4 100644 --- a/src/nix/sigs.cc +++ b/src/nix/common/sigs.cc @@ -1,5 +1,5 @@ #include "signals.hh" -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" #include "thread-pool.hh" diff --git a/src/nix/store-cat.md b/src/nix/common/store-cat.md similarity index 100% rename from src/nix/store-cat.md rename to src/nix/common/store-cat.md diff --git a/src/nix/store-copy-log.cc b/src/nix/common/store-copy-log.cc similarity index 89% rename from src/nix/store-copy-log.cc rename to src/nix/common/store-copy-log.cc index a6e8aeff7cb7..0b4f9b95120d 100644 --- a/src/nix/store-copy-log.cc +++ b/src/nix/common/store-copy-log.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" #include "store-cast.hh" @@ -31,7 +31,7 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand auto dstStore = getDstStore(); auto & dstLogStore = require(*dstStore); - for (auto & drvPath : Installable::toDerivations(getEvalStore(), installables, true)) { + for (auto & drvPath : Installable::toDerivations(getDrvStore(), installables, true)) { if (auto log = srcLogStore.getBuildLog(drvPath)) dstLogStore.addBuildLog(drvPath, *log); else diff --git a/src/nix/store-copy-log.md b/src/nix/common/store-copy-log.md similarity index 100% rename from src/nix/store-copy-log.md rename to src/nix/common/store-copy-log.md diff --git a/src/nix/store-delete.cc b/src/nix/common/store-delete.cc similarity index 97% rename from src/nix/store-delete.cc rename to src/nix/common/store-delete.cc index 6719227dfe70..b5fabac6a61a 100644 --- a/src/nix/store-delete.cc +++ b/src/nix/common/store-delete.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include "shared.hh" #include "store-api.hh" diff --git a/src/nix/store-delete.md b/src/nix/common/store-delete.md similarity index 100% rename from src/nix/store-delete.md rename to src/nix/common/store-delete.md diff --git a/src/nix/store-dump-path.md b/src/nix/common/store-dump-path.md similarity index 100% rename from src/nix/store-dump-path.md rename to src/nix/common/store-dump-path.md diff --git a/src/nix/store-gc.cc b/src/nix/common/store-gc.cc similarity index 97% rename from src/nix/store-gc.cc rename to src/nix/common/store-gc.cc index 8b9b5d1642a8..c5b68464f91c 100644 --- a/src/nix/store-gc.cc +++ b/src/nix/common/store-gc.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" #include "shared.hh" #include "store-api.hh" diff --git a/src/nix/store-gc.md b/src/nix/common/store-gc.md similarity index 100% rename from src/nix/store-gc.md rename to src/nix/common/store-gc.md diff --git a/src/nix/store-info.cc b/src/nix/common/store-info.cc similarity index 98% rename from src/nix/store-info.cc rename to src/nix/common/store-info.cc index a7c59576146d..2e18b0a70420 100644 --- a/src/nix/store-info.cc +++ b/src/nix/common/store-info.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" #include "finally.hh" diff --git a/src/nix/store-info.md b/src/nix/common/store-info.md similarity index 100% rename from src/nix/store-info.md rename to src/nix/common/store-info.md diff --git a/src/nix/store-ls.md b/src/nix/common/store-ls.md similarity index 100% rename from src/nix/store-ls.md rename to src/nix/common/store-ls.md diff --git a/src/nix/store-repair.cc b/src/nix/common/store-repair.cc similarity index 94% rename from src/nix/store-repair.cc rename to src/nix/common/store-repair.cc index 895e39685070..251fabaf1048 100644 --- a/src/nix/store-repair.cc +++ b/src/nix/common/store-repair.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" using namespace nix; diff --git a/src/nix/store-repair.md b/src/nix/common/store-repair.md similarity index 100% rename from src/nix/store-repair.md rename to src/nix/common/store-repair.md diff --git a/src/nix/store.cc b/src/nix/common/store.cc similarity index 94% rename from src/nix/store.cc rename to src/nix/common/store.cc index 2879e03b350a..226a02651b14 100644 --- a/src/nix/store.cc +++ b/src/nix/common/store.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" using namespace nix; diff --git a/src/nix/verify.cc b/src/nix/common/verify.cc similarity index 99% rename from src/nix/verify.cc rename to src/nix/common/verify.cc index 78cb765ce172..3032d356d0a6 100644 --- a/src/nix/verify.cc +++ b/src/nix/common/verify.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "shared.hh" #include "store-api.hh" #include "sync.hh" diff --git a/src/nix/verify.md b/src/nix/common/verify.md similarity index 100% rename from src/nix/verify.md rename to src/nix/common/verify.md diff --git a/src/nix/why-depends.cc b/src/nix/common/why-depends.cc similarity index 94% rename from src/nix/why-depends.cc rename to src/nix/common/why-depends.cc index aecf65922220..b009b05a55f1 100644 --- a/src/nix/why-depends.cc +++ b/src/nix/common/why-depends.cc @@ -1,4 +1,4 @@ -#include "command.hh" +#include "store-command.hh" #include "store-api.hh" #include "progress-bar.hh" #include "source-accessor.hh" @@ -27,13 +27,15 @@ static std::string filterPrintable(const std::string & s) return res; } -struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions +struct CmdWhyDepends : virtual DrvCommand, GetRawInstallables, MixDefaultParseInstallableArgs, MixOperateOnOptions { std::string _package, _dependency; bool all = false; bool precise = false; CmdWhyDepends() + : MixDefaultParseInstallableArgs(static_cast(*this)) + , MixOperateOnOptions(static_cast(*this)) { expectArgs({ .label = "package", @@ -75,10 +77,15 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions Category category() override { return catSecondary; } + std::vector getRawInstallables() override + { + return { _package, _dependency }; + } + void run(ref store) override { auto package = parseInstallable(store, _package); - auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package); + auto packagePath = Installable::toStorePath(getDrvStore(), store, Realise::Outputs, operateOn, package); /* We don't need to build `dependency`. We try to get the store * path if it's already known, and if not, then it's not a dependency. @@ -93,7 +100,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions auto dependency = parseInstallable(store, _dependency); auto optDependencyPath = [&]() -> std::optional { try { - return {Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency)}; + return {Installable::toStorePath(getDrvStore(), store, Realise::Derivation, operateOn, dependency)}; } catch (MissingRealisation &) { return std::nullopt; } diff --git a/src/nix/why-depends.md b/src/nix/common/why-depends.md similarity index 100% rename from src/nix/why-depends.md rename to src/nix/common/why-depends.md diff --git a/src/nix/app.cc b/src/nix/full/app.cc similarity index 99% rename from src/nix/app.cc rename to src/nix/full/app.cc index 935ed18ecbaa..4b36a1ebbc73 100644 --- a/src/nix/app.cc +++ b/src/nix/full/app.cc @@ -1,4 +1,4 @@ -#include "installables.hh" +#include "installable-value.hh" #include "installable-derived-path.hh" #include "installable-value.hh" #include "store-api.hh" diff --git a/src/nix/bundle.cc b/src/nix/full/bundle.cc similarity index 96% rename from src/nix/bundle.cc rename to src/nix/full/bundle.cc index 54cc6a17f364..c378c423ef40 100644 --- a/src/nix/bundle.cc +++ b/src/nix/full/bundle.cc @@ -14,6 +14,9 @@ struct CmdBundle : InstallableValueCommand std::optional outLink; CmdBundle() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) { addFlag({ .longName = "bundler", diff --git a/src/nix/bundle.md b/src/nix/full/bundle.md similarity index 100% rename from src/nix/bundle.md rename to src/nix/full/bundle.md diff --git a/src/nix/full/command.cc b/src/nix/full/command.cc new file mode 100644 index 000000000000..b71d9f55bff5 --- /dev/null +++ b/src/nix/full/command.cc @@ -0,0 +1,24 @@ +#include "command.hh" + +namespace nix { + +struct ParseInstallableValueAdapter : ParseInstallableValueArgs +{ + ParseInstallableValueAdapter(GetRawInstallables & args) + : MixRepair(args) + , HasEvalState(args) + , MixFlakeOptions(args) + , ParseInstallableValueArgs(args) + { } + + virtual ~ParseInstallableValueAdapter() = default; +}; + +ParseInstallableValueAdapter::RegisterDefault rParseInstallableValueAdapter { + [](GetRawInstallables & args) -> ref + { + return make_ref(args); + } +}; + +} diff --git a/src/nix/develop.cc b/src/nix/full/develop.cc similarity index 96% rename from src/nix/develop.cc rename to src/nix/full/develop.cc index 38482ed42a46..cc731616fa34 100644 --- a/src/nix/develop.cc +++ b/src/nix/full/develop.cc @@ -283,7 +283,7 @@ static StorePath getDerivationEnvironment(ref store, ref evalStore throw Error("get-env.sh failed to produce an environment"); } -struct Common : InstallableCommand, MixProfile +struct Common : AbstractInstallableCommand, SourceExprCommand, virtual MixProfile { std::set ignoreVars{ "BASHOPTS", @@ -373,7 +373,7 @@ struct Common : InstallableCommand, MixProfile auto dir = absPath(dir_); auto installable = parseInstallable(store, installable_); auto builtPaths = Installable::toStorePaths( - getEvalStore(), store, Realise::Nothing, OperateOn::Output, {installable}); + getDrvStore(), store, Realise::Nothing, OperateOn::Output, {installable}); for (auto & path: builtPaths) { auto from = store->printStorePath(path); if (script.find(from) == std::string::npos) @@ -459,7 +459,7 @@ struct Common : InstallableCommand, MixProfile auto & drvPath = *drvs.begin(); - return getDerivationEnvironment(store, getEvalStore(), drvPath); + return getDerivationEnvironment(store, getDrvStore(), drvPath); } } @@ -484,6 +484,9 @@ struct CmdDevelop : Common, MixEnvironment std::optional phase; CmdDevelop() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) { addFlag({ .longName = "command", @@ -627,7 +630,7 @@ struct CmdDevelop : Common, MixEnvironment bool found = false; - for (auto & path : Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, {bashInstallable})) { + for (auto & path : Installable::toStorePaths(getDrvStore(), store, Realise::Outputs, OperateOn::Output, {bashInstallable})) { auto s = store->printStorePath(path) + "/bin/bash"; if (pathExists(s)) { shell = s; @@ -668,6 +671,12 @@ struct CmdDevelop : Common, MixEnvironment struct CmdPrintDevEnv : Common, MixJSON { + CmdPrintDevEnv() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + { } + std::string description() override { return "print shell code that can be sourced by bash to reproduce the build environment of a derivation"; diff --git a/src/nix/develop.md b/src/nix/full/develop.md similarity index 100% rename from src/nix/develop.md rename to src/nix/full/develop.md diff --git a/src/nix/doctor.cc b/src/nix/full/doctor.cc similarity index 100% rename from src/nix/doctor.cc rename to src/nix/full/doctor.cc diff --git a/src/nix/edit.cc b/src/nix/full/edit.cc similarity index 88% rename from src/nix/edit.cc rename to src/nix/full/edit.cc index 9cbab230b0ff..4cd5a6fcd9b9 100644 --- a/src/nix/edit.cc +++ b/src/nix/full/edit.cc @@ -12,6 +12,12 @@ using namespace nix; struct CmdEdit : InstallableValueCommand { + CmdEdit() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + { } + std::string description() override { return "open the Nix expression of a Nix package in $EDITOR"; diff --git a/src/nix/edit.md b/src/nix/full/edit.md similarity index 100% rename from src/nix/edit.md rename to src/nix/full/edit.md diff --git a/src/nix/eval.cc b/src/nix/full/eval.cc similarity index 93% rename from src/nix/eval.cc rename to src/nix/full/eval.cc index b34af34e0eb1..4f8b83cf640d 100644 --- a/src/nix/eval.cc +++ b/src/nix/full/eval.cc @@ -17,7 +17,12 @@ struct CmdEval : MixJSON, InstallableValueCommand, MixReadOnlyOption std::optional apply; std::optional writeTo; - CmdEval() : InstallableValueCommand() + CmdEval() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + , InstallableValueCommand() + , MixReadOnlyOption(static_cast(*this)) { addFlag({ .longName = "raw", diff --git a/src/nix/eval.md b/src/nix/full/eval.md similarity index 100% rename from src/nix/eval.md rename to src/nix/full/eval.md diff --git a/src/nix/flake-archive.md b/src/nix/full/flake-archive.md similarity index 100% rename from src/nix/flake-archive.md rename to src/nix/full/flake-archive.md diff --git a/src/nix/flake-check.md b/src/nix/full/flake-check.md similarity index 100% rename from src/nix/flake-check.md rename to src/nix/full/flake-check.md diff --git a/src/nix/flake-clone.md b/src/nix/full/flake-clone.md similarity index 100% rename from src/nix/flake-clone.md rename to src/nix/full/flake-clone.md diff --git a/src/nix/flake-init.md b/src/nix/full/flake-init.md similarity index 100% rename from src/nix/flake-init.md rename to src/nix/full/flake-init.md diff --git a/src/nix/flake-lock.md b/src/nix/full/flake-lock.md similarity index 100% rename from src/nix/flake-lock.md rename to src/nix/full/flake-lock.md diff --git a/src/nix/flake-metadata.md b/src/nix/full/flake-metadata.md similarity index 100% rename from src/nix/flake-metadata.md rename to src/nix/full/flake-metadata.md diff --git a/src/nix/flake-new.md b/src/nix/full/flake-new.md similarity index 100% rename from src/nix/flake-new.md rename to src/nix/full/flake-new.md diff --git a/src/nix/flake-prefetch.md b/src/nix/full/flake-prefetch.md similarity index 100% rename from src/nix/flake-prefetch.md rename to src/nix/full/flake-prefetch.md diff --git a/src/nix/flake-show.md b/src/nix/full/flake-show.md similarity index 100% rename from src/nix/flake-show.md rename to src/nix/full/flake-show.md diff --git a/src/nix/flake-update.md b/src/nix/full/flake-update.md similarity index 100% rename from src/nix/flake-update.md rename to src/nix/full/flake-update.md diff --git a/src/nix/flake.cc b/src/nix/full/flake.cc similarity index 97% rename from src/nix/flake.cc rename to src/nix/full/flake.cc index 38938f09ead4..23d01be1ba54 100644 --- a/src/nix/flake.cc +++ b/src/nix/full/flake.cc @@ -25,8 +25,7 @@ using namespace nix; using namespace nix::flake; using json = nlohmann::json; -struct CmdFlakeUpdate; -class FlakeCommand : virtual Args, public MixFlakeOptions +class FlakeCommand : virtual Args, public MixFlakeOptions, public virtual EvalCommand { protected: std::string flakeUrl = "."; @@ -34,6 +33,9 @@ class FlakeCommand : virtual Args, public MixFlakeOptions public: FlakeCommand() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) { expectArgs({ .label = "flake-url", @@ -74,6 +76,8 @@ struct CmdFlakeUpdate : FlakeCommand } CmdFlakeUpdate() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { expectedArgs.clear(); addFlag({ @@ -132,6 +136,8 @@ struct CmdFlakeLock : FlakeCommand } CmdFlakeLock() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { /* Remove flags that don't make sense. */ removeFlag("no-write-lock-file"); @@ -182,6 +188,11 @@ static void enumerateOutputs(EvalState & state, Value & vFlake, struct CmdFlakeMetadata : FlakeCommand, MixJSON { + CmdFlakeMetadata() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + { } + std::string description() override { return "show flake metadata"; @@ -291,6 +302,11 @@ struct CmdFlakeMetadata : FlakeCommand, MixJSON struct CmdFlakeInfo : CmdFlakeMetadata { + CmdFlakeInfo() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + { } + void run(nix::ref store) override { warn("'nix flake info' is a deprecated alias for 'nix flake metadata'"); @@ -304,6 +320,8 @@ struct CmdFlakeCheck : FlakeCommand bool checkAllSystems = false; CmdFlakeCheck() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { addFlag({ .longName = "no-build", @@ -786,6 +804,8 @@ struct CmdFlakeInitCommon : virtual Args, EvalCommand const LockFlags lockFlags{ .writeLockFile = false }; CmdFlakeInitCommon() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { addFlag({ .longName = "template", @@ -911,6 +931,8 @@ struct CmdFlakeInit : CmdFlakeInitCommon } CmdFlakeInit() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { destDir = "."; } @@ -931,6 +953,8 @@ struct CmdFlakeNew : CmdFlakeInitCommon } CmdFlakeNew() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { expectArgs({ .label = "dest-dir", @@ -957,6 +981,8 @@ struct CmdFlakeClone : FlakeCommand } CmdFlakeClone() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { addFlag({ .longName = "dest", @@ -981,6 +1007,8 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun std::string dstUri; CmdFlakeArchive() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { addFlag({ .longName = "to", @@ -1058,6 +1086,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON bool showAllSystems = false; CmdFlakeShow() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { addFlag({ .longName = "legacy", @@ -1352,6 +1382,8 @@ struct CmdFlakeShow : FlakeCommand, MixJSON struct CmdFlakePrefetch : FlakeCommand, MixJSON { CmdFlakePrefetch() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { } diff --git a/src/nix/flake.md b/src/nix/full/flake.md similarity index 100% rename from src/nix/flake.md rename to src/nix/full/flake.md diff --git a/src/nix/fmt.cc b/src/nix/full/fmt.cc similarity index 79% rename from src/nix/fmt.cc rename to src/nix/full/fmt.cc index c85eacded1cd..671571416770 100644 --- a/src/nix/fmt.cc +++ b/src/nix/full/fmt.cc @@ -7,7 +7,11 @@ using namespace nix; struct CmdFmt : SourceExprCommand { std::vector args; - CmdFmt() { expectArgs({.label = "args", .handler = {&args}}); } + CmdFmt() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + { expectArgs({.label = "args", .handler = {&args}}); } std::string description() override { return "reformat your code in the standard style"; @@ -27,10 +31,15 @@ struct CmdFmt : SourceExprCommand { Strings getDefaultFlakeAttrPathPrefixes() override { return Strings{}; } + std::vector getRawInstallables() override + { + return { "." }; + } + void run(ref store) override { auto evalState = getEvalState(); - auto evalStore = getEvalStore(); + auto evalStore = getDrvStore(); auto installable_ = parseInstallable(store, "."); auto & installable = InstallableValue::require(*installable_); diff --git a/src/nix/fmt.md b/src/nix/full/fmt.md similarity index 100% rename from src/nix/fmt.md rename to src/nix/full/fmt.md diff --git a/src/nix/get-env.sh b/src/nix/full/get-env.sh similarity index 100% rename from src/nix/get-env.sh rename to src/nix/full/get-env.sh diff --git a/src/nix/help.md b/src/nix/full/help.md similarity index 100% rename from src/nix/help.md rename to src/nix/full/help.md diff --git a/src/nix/main.cc b/src/nix/full/main.cc similarity index 99% rename from src/nix/main.cc rename to src/nix/full/main.cc index 73641f6d231a..bf2ec8bdafbf 100644 --- a/src/nix/main.cc +++ b/src/nix/full/main.cc @@ -296,7 +296,7 @@ struct CmdHelpStores : Command std::string doc() override { return - #include "help-stores.md" + #include "../common/help-stores.md" ; } diff --git a/src/nix/nix.md b/src/nix/full/nix.md similarity index 100% rename from src/nix/nix.md rename to src/nix/full/nix.md diff --git a/src/nix/prefetch.cc b/src/nix/full/prefetch.cc similarity index 96% rename from src/nix/prefetch.cc rename to src/nix/full/prefetch.cc index 3ed7946a8b84..b7eb57cbf5ff 100644 --- a/src/nix/prefetch.cc +++ b/src/nix/full/prefetch.cc @@ -145,7 +145,12 @@ static int main_nix_prefetch_url(int argc, char * * argv) struct MyArgs : LegacyArgs, MixEvalArgs { - using LegacyArgs::LegacyArgs; + MyArgs(const std::string & programName, + std::function parseArg) + : MixRepair(static_cast(*this)) + , LegacyArgs(programName, parseArg) + , MixEvalArgs(static_cast(*this)) + { } }; MyArgs myArgs(std::string(baseNameOf(argv[0])), [&](Strings::iterator & arg, const Strings::iterator & end) { diff --git a/src/nix/print-dev-env.md b/src/nix/full/print-dev-env.md similarity index 100% rename from src/nix/print-dev-env.md rename to src/nix/full/print-dev-env.md diff --git a/src/nix/profile-diff-closures.md b/src/nix/full/profile-diff-closures.md similarity index 100% rename from src/nix/profile-diff-closures.md rename to src/nix/full/profile-diff-closures.md diff --git a/src/nix/profile-history.md b/src/nix/full/profile-history.md similarity index 100% rename from src/nix/profile-history.md rename to src/nix/full/profile-history.md diff --git a/src/nix/profile-install.md b/src/nix/full/profile-install.md similarity index 100% rename from src/nix/profile-install.md rename to src/nix/full/profile-install.md diff --git a/src/nix/profile-list.md b/src/nix/full/profile-list.md similarity index 100% rename from src/nix/profile-list.md rename to src/nix/full/profile-list.md diff --git a/src/nix/profile-remove.md b/src/nix/full/profile-remove.md similarity index 100% rename from src/nix/profile-remove.md rename to src/nix/full/profile-remove.md diff --git a/src/nix/profile-rollback.md b/src/nix/full/profile-rollback.md similarity index 100% rename from src/nix/profile-rollback.md rename to src/nix/full/profile-rollback.md diff --git a/src/nix/profile-upgrade.md b/src/nix/full/profile-upgrade.md similarity index 100% rename from src/nix/profile-upgrade.md rename to src/nix/full/profile-upgrade.md diff --git a/src/nix/profile-wipe-history.md b/src/nix/full/profile-wipe-history.md similarity index 100% rename from src/nix/profile-wipe-history.md rename to src/nix/full/profile-wipe-history.md diff --git a/src/nix/profile.cc b/src/nix/full/profile.cc similarity index 95% rename from src/nix/profile.cc rename to src/nix/full/profile.cc index 476ddcd609b5..7afcf7426239 100644 --- a/src/nix/profile.cc +++ b/src/nix/full/profile.cc @@ -304,11 +304,15 @@ builtPathsPerInstallable( return res; } -struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile +struct CmdProfileInstall : AbstractInstallablesCommand, virtual SourceExprCommand, MixDefaultProfile { std::optional priority; - CmdProfileInstall() { + CmdProfileInstall() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + { addFlag({ .longName = "priority", .description = "The priority of the package to install.", @@ -335,7 +339,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile auto builtPaths = builtPathsPerInstallable( Installable::build2( - getEvalStore(), store, Realise::Outputs, installables, bmNormal)); + getDrvStore(), store, Realise::Outputs, installables, bmNormal)); for (auto & installable : installables) { ProfileElement element; @@ -365,7 +369,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile : defaultPriority; }); - element.updateStorePaths(getEvalStore(), store, res); + element.updateStorePaths(getDrvStore(), store, res); manifest.elements.push_back(std::move(element)); } @@ -483,6 +487,11 @@ class MixProfileElementMatchers : virtual Args struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElementMatchers { + CmdProfileRemove() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + { } + std::string description() override { return "remove packages from a profile"; @@ -535,6 +544,12 @@ struct CmdProfileRemove : virtual EvalCommand, MixDefaultProfile, MixProfileElem struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProfileElementMatchers { + CmdProfileUpgrade() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + { } + std::string description() override { return "upgrade packages using their most recent flake"; @@ -547,6 +562,11 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf ; } + std::vector getRawInstallables() override + { + return { }; + } + void run(ref store) override { ProfileManifest manifest(*getEvalState(), *profile); @@ -618,13 +638,13 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf auto builtPaths = builtPathsPerInstallable( Installable::build2( - getEvalStore(), store, Realise::Outputs, installables, bmNormal)); + getDrvStore(), 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(), + getDrvStore(), store, builtPaths.find(&*installable)->second.first); } @@ -635,6 +655,11 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf struct CmdProfileList : virtual EvalCommand, virtual StoreCommand, MixDefaultProfile, MixJSON { + CmdProfileList() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + { } + std::string description() override { return "list installed packages"; @@ -710,6 +735,11 @@ struct CmdProfileDiffClosures : virtual StoreCommand, MixDefaultProfile struct CmdProfileHistory : virtual StoreCommand, EvalCommand, MixDefaultProfile { + CmdProfileHistory() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + { } + std::string description() override { return "show all versions of a profile"; diff --git a/src/nix/profile.md b/src/nix/full/profile.md similarity index 100% rename from src/nix/profile.md rename to src/nix/full/profile.md diff --git a/src/nix/registry-add.md b/src/nix/full/registry-add.md similarity index 100% rename from src/nix/registry-add.md rename to src/nix/full/registry-add.md diff --git a/src/nix/registry-list.md b/src/nix/full/registry-list.md similarity index 100% rename from src/nix/registry-list.md rename to src/nix/full/registry-list.md diff --git a/src/nix/registry-pin.md b/src/nix/full/registry-pin.md similarity index 100% rename from src/nix/registry-pin.md rename to src/nix/full/registry-pin.md diff --git a/src/nix/registry-remove.md b/src/nix/full/registry-remove.md similarity index 100% rename from src/nix/registry-remove.md rename to src/nix/full/registry-remove.md diff --git a/src/nix/registry.cc b/src/nix/full/registry.cc similarity index 96% rename from src/nix/registry.cc rename to src/nix/full/registry.cc index f509ccae8403..32ed4e42a54c 100644 --- a/src/nix/registry.cc +++ b/src/nix/full/registry.cc @@ -102,6 +102,8 @@ struct CmdRegistryAdd : MixEvalArgs, Command, RegistryCommand } CmdRegistryAdd() + : MixRepair(static_cast(*this)) + , MixEvalArgs(static_cast(*this)) { expectArg("from-url", &fromUrl); expectArg("to-url", &toUrl); @@ -168,6 +170,8 @@ struct CmdRegistryPin : RegistryCommand, EvalCommand } CmdRegistryPin() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) { expectArg("url", &url); diff --git a/src/nix/registry.md b/src/nix/full/registry.md similarity index 100% rename from src/nix/registry.md rename to src/nix/full/registry.md diff --git a/src/nix/repl.cc b/src/nix/full/repl.cc similarity index 92% rename from src/nix/repl.cc rename to src/nix/full/repl.cc index 63fe3044bb23..1e2bc4538efc 100644 --- a/src/nix/repl.cc +++ b/src/nix/full/repl.cc @@ -7,9 +7,13 @@ namespace nix { -struct CmdRepl : RawInstallablesCommand +struct CmdRepl : virtual RawInstallablesCommand, virtual SourceExprCommand { - CmdRepl() { + CmdRepl() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) + { evalSettings.pureEval = false; } diff --git a/src/nix/repl.md b/src/nix/full/repl.md similarity index 100% rename from src/nix/repl.md rename to src/nix/full/repl.md diff --git a/src/nix/run.cc b/src/nix/full/run.cc similarity index 95% rename from src/nix/run.cc rename to src/nix/full/run.cc index ea0a1789711a..39f5c9b52f60 100644 --- a/src/nix/run.cc +++ b/src/nix/full/run.cc @@ -100,7 +100,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment void run(ref store, Installables && installables) override { - auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); + auto outPaths = Installable::toStorePaths(getDrvStore(), store, Realise::Outputs, OperateOn::Output, installables); auto accessor = store->getFSAccessor(); @@ -140,11 +140,12 @@ static auto rCmdShell = registerCommand("shell"); struct CmdRun : InstallableValueCommand { - using InstallableCommand::run; - std::vector args; CmdRun() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) { expectArgs({ .label = "args", @@ -189,7 +190,7 @@ struct CmdRun : InstallableValueCommand auto state = getEvalState(); lockFlags.applyNixConfig = true; - auto app = installable->toApp(*state).resolve(getEvalStore(), store); + auto app = installable->toApp(*state).resolve(getDrvStore(), store); Strings allArgs{app.program}; for (auto & i : args) allArgs.push_back(i); diff --git a/src/nix/run.hh b/src/nix/full/run.hh similarity index 100% rename from src/nix/run.hh rename to src/nix/full/run.hh diff --git a/src/nix/run.md b/src/nix/full/run.md similarity index 100% rename from src/nix/run.md rename to src/nix/full/run.md diff --git a/src/nix/search.cc b/src/nix/full/search.cc similarity index 97% rename from src/nix/search.cc rename to src/nix/full/search.cc index ef0139e093f8..9f6c33590a0b 100644 --- a/src/nix/search.cc +++ b/src/nix/full/search.cc @@ -29,6 +29,9 @@ struct CmdSearch : InstallableValueCommand, MixJSON std::vector excludeRes; CmdSearch() + : MixRepair(static_cast(*this)) + , HasEvalState(static_cast(*this)) + , MixFlakeOptions(static_cast(*this)) { expectArgs("regex", &res); addFlag(Flag { diff --git a/src/nix/search.md b/src/nix/full/search.md similarity index 100% rename from src/nix/search.md rename to src/nix/full/search.md diff --git a/src/nix/shell.md b/src/nix/full/shell.md similarity index 100% rename from src/nix/shell.md rename to src/nix/full/shell.md diff --git a/src/nix/show-config.cc b/src/nix/full/show-config.cc similarity index 100% rename from src/nix/show-config.cc rename to src/nix/full/show-config.cc diff --git a/src/nix/store-prefetch-file.md b/src/nix/full/store-prefetch-file.md similarity index 100% rename from src/nix/store-prefetch-file.md rename to src/nix/full/store-prefetch-file.md diff --git a/src/nix/upgrade-nix.cc b/src/nix/full/upgrade-nix.cc similarity index 100% rename from src/nix/upgrade-nix.cc rename to src/nix/full/upgrade-nix.cc diff --git a/src/nix/upgrade-nix.md b/src/nix/full/upgrade-nix.md similarity index 100% rename from src/nix/upgrade-nix.md rename to src/nix/full/upgrade-nix.md diff --git a/src/nix/local.mk b/src/nix/local.mk index 57f8259c45ee..29c55da1ecba 100644 --- a/src/nix/local.mk +++ b/src/nix/local.mk @@ -1,40 +1,66 @@ -programs += nix +programs += nix mini-nix -nix_DIR := $(d) +define common-exe + $(1)_SOURCES = \ + $$(wildcard $(d)/common/*.cc) \ + $$(wildcard src/build-remote/*.cc) \ + $$(wildcard src/nix-daemon/*.cc) \ + $$(wildcard src/nix-store/*.cc) -nix_SOURCES := \ - $(wildcard $(d)/*.cc) \ - $(wildcard src/build-remote/*.cc) \ + $(1)_CXXFLAGS += -I src/libutil -I src/libstore -I src/libmain -I src/libstore-cmd -I doc/manual + + $(1)_LIBS = libmain libstore libutil libstore-cmd + + $(1)_LDFLAGS = -pthread $$(SODIUM_LIBS) $$(EDITLINE_LIBS) $$(BOOST_LDFLAGS) $$(LOWDOWN_LIBS) +endef + +$(eval $(call common-exe,mini-nix)) + +mini-nix_DIR := $(d)/store + +mini-nix_SOURCES += \ + $(wildcard $(mini-nix_DIR)/*.cc) + +ifeq ($(NIX_FULL), 1) + +$(eval $(call common-exe,nix)) + +nix_DIR := $(d)/full + +nix_SOURCES += \ + $(wildcard $(nix_DIR)/*.cc) \ $(wildcard src/nix-build/*.cc) \ $(wildcard src/nix-channel/*.cc) \ $(wildcard src/nix-collect-garbage/*.cc) \ $(wildcard src/nix-copy-closure/*.cc) \ - $(wildcard src/nix-daemon/*.cc) \ $(wildcard src/nix-env/*.cc) \ - $(wildcard src/nix-instantiate/*.cc) \ - $(wildcard src/nix-store/*.cc) \ - -nix_CXXFLAGS += -I src/libutil -I src/libstore -I src/libfetchers -I src/libexpr -I src/libmain -I src/libcmd -I doc/manual + $(wildcard src/nix-instantiate/*.cc) -nix_LIBS = libexpr libmain libfetchers libstore libutil libcmd +nix_CXXFLAGS += -I src/libfetchers -I src/libexpr -I src/libcmd -nix_LDFLAGS = -pthread $(SODIUM_LIBS) $(EDITLINE_LIBS) $(BOOST_LDFLAGS) $(LOWDOWN_LIBS) +nix_LIBS += libexpr libfetchers libcmd $(foreach name, \ - nix-build nix-channel nix-collect-garbage nix-copy-closure nix-daemon nix-env nix-hash nix-instantiate nix-prefetch-url nix-shell nix-store, \ + nix-build nix-channel nix-collect-garbage nix-copy-closure nix-env nix-hash nix-instantiate nix-prefetch-url nix-shell, \ $(eval $(call install-symlink, nix, $(bindir)/$(name)))) -$(eval $(call install-symlink, $(bindir)/nix, $(libexecdir)/nix/build-remote)) src/nix-env/user-env.cc: src/nix-env/buildenv.nix.gen.hh -src/nix/develop.cc: src/nix/get-env.sh.gen.hh +src/nix/full/develop.cc: src/nix/full/get-env.sh.gen.hh src/nix-channel/nix-channel.cc: src/nix-channel/unpack-channel.nix.gen.hh -src/nix/main.cc: doc/manual/generate-manpage.nix.gen.hh doc/manual/utils.nix.gen.hh doc/manual/generate-settings.nix.gen.hh doc/manual/generate-store-info.nix.gen.hh +src/nix/full/main.cc: doc/manual/generate-manpage.nix.gen.hh doc/manual/utils.nix.gen.hh doc/manual/generate-settings.nix.gen.hh doc/manual/generate-store-info.nix.gen.hh -src/nix/doc/files/%.md: doc/manual/src/command-ref/files/%.md +src/nix/full/doc/files/%.md: doc/manual/src/command-ref/files/%.md @mkdir -p $$(dirname $@) @cp $< $@ -src/nix/profile.cc: src/nix/profile.md src/nix/doc/files/profiles.md.gen.hh +src/nix/full/profile.cc: src/nix/full/profile.md src/nix/full/doc/files/profiles.md.gen.hh + +endif + +$(foreach name, \ + nix-daemon nix-store, \ + $(eval $(call install-symlink, nix, $(bindir)/$(name)))) +$(eval $(call install-symlink, $(bindir)/nix, $(libexecdir)/nix/build-remote)) diff --git a/src/nix/store/command.cc b/src/nix/store/command.cc new file mode 100644 index 000000000000..34615eed4a9b --- /dev/null +++ b/src/nix/store/command.cc @@ -0,0 +1,64 @@ +#include "store-command.hh" +#include "installable-derived-path.hh" + +namespace nix { + +struct ParseStoreInstallableCommmand : ParseInstallableArgs +{ + AbstractArgs & args; + + ParseStoreInstallableCommmand(AbstractArgs & args) + : args(args) + { + } + virtual ~ParseStoreInstallableCommmand() = default; + + Installables parseInstallables( + ref store, std::vector ss) override; + + ref parseInstallable( + ref store, const std::string & installable) override; + + void completeInstallable(AddCompletions & completions, std::string_view prefix) override; + + void applyDefaultInstallables(std::vector & rawInstallables) override; +}; + +Installables ParseStoreInstallableCommmand::parseInstallables( + ref store, std::vector ss) +{ + Installables result; + + for (auto & s : ss) + result.push_back(parseInstallable(store, s)); + + return result; +} + +ref ParseStoreInstallableCommmand::parseInstallable( + ref store, const std::string & installable) +{ + auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(installable); + return make_ref( + InstallableDerivedPath::parse(store, prefix, extendedOutputsSpec)); +} + +void ParseStoreInstallableCommmand::applyDefaultInstallables(std::vector & rawInstallables) +{ + +} + +void ParseStoreInstallableCommmand::completeInstallable(AddCompletions & completions, std::string_view prefix) +{ + +} + +ParseInstallableArgs::RegisterDefault rParseStoreInstallableCommmand { + + [](GetRawInstallables & args) -> ref + { + return make_ref(args); + } +}; + +} diff --git a/src/nix/store/help.md b/src/nix/store/help.md new file mode 100644 index 000000000000..1f53de386ccc --- /dev/null +++ b/src/nix/store/help.md @@ -0,0 +1,17 @@ +R""( + +# Examples + +* Show help about `nix` in general: + + ```console + # nix help + ``` + +* Show help about a particular subcommand: + + ```console + # nix help daemon + ``` + +)"" diff --git a/src/nix/store/main.cc b/src/nix/store/main.cc index 73641f6d231a..8013863a7a66 100644 --- a/src/nix/store/main.cc +++ b/src/nix/store/main.cc @@ -3,10 +3,8 @@ #include "args/root.hh" #include "current-process.hh" #include "namespaces.hh" -#include "command.hh" +#include "store-command.hh" #include "common-args.hh" -#include "eval.hh" -#include "eval-settings.hh" #include "globals.hh" #include "legacy.hh" #include "shared.hh" @@ -15,7 +13,6 @@ #include "finally.hh" #include "loggers.hh" #include "markdown.hh" -#include "memory-input-accessor.hh" #include #include @@ -26,10 +23,6 @@ #include -extern std::string chrootHelperName; - -void chrootHelper(int argc, char * * argv); - namespace nix { /* Check if we have a non-loopback/link-local network interface. */ @@ -67,7 +60,7 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs bool helpRequested = false; bool showVersion = false; - NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("nix") + NixArgs() : MultiCommand(RegisterCommand::getCommandsFor({})), MixCommonArgs("mini-nix") { categories.clear(); categories[catHelp] = "Help commands"; @@ -191,7 +184,6 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs j["experimentalFeature"] = storeConfig->experimentalFeature(); } res["stores"] = std::move(stores); - res["fetchers"] = fetchers::dumpRegisterInputSchemeInfo(); return res.dump(); } @@ -201,44 +193,11 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs, virtual RootArgs lowdown. */ static void showHelp(std::vector subcommand, NixArgs & toplevel) { - auto mdName = subcommand.empty() ? "nix" : fmt("nix3-%s", concatStringsSep("-", subcommand)); - - evalSettings.restrictEval = false; - evalSettings.pureEval = false; - EvalState state({}, openStore("dummy://")); - - auto vGenerateManpage = state.allocValue(); - state.eval(state.parseExprFromString( - #include "generate-manpage.nix.gen.hh" - , state.rootPath(CanonPath::root)), *vGenerateManpage); - - state.corepkgsFS->addFile( - CanonPath("utils.nix"), - #include "utils.nix.gen.hh" - ); - - state.corepkgsFS->addFile( - CanonPath("/generate-settings.nix"), - #include "generate-settings.nix.gen.hh" - ); - - state.corepkgsFS->addFile( - CanonPath("/generate-store-info.nix"), - #include "generate-store-info.nix.gen.hh" - ); + auto mdName = subcommand.empty() ? "mini-nix" : fmt("mini-nix3-%s", concatStringsSep("-", subcommand)); - auto vDump = state.allocValue(); - vDump->mkString(toplevel.dumpCli()); + throw UsageError("Nix has no subcommand '%s'", concatStringsSep("", subcommand)); - auto vRes = state.allocValue(); - state.callFunction(*vGenerateManpage, state.getBuiltin("false"), *vRes, noPos); - state.callFunction(*vRes, *vDump, *vRes, noPos); - - auto attr = vRes->attrs->get(state.symbols.create(mdName + ".md")); - if (!attr) - throw UsageError("Nix has no subcommand '%s'", concatStringsSep("", subcommand)); - - auto markdown = state.forceString(*attr->value, noPos, "while evaluating the lowdown help text"); + auto markdown = ""; RunPager pager; std::cout << renderMarkdownToTerminal(markdown) << "\n"; @@ -296,7 +255,7 @@ struct CmdHelpStores : Command std::string doc() override { return - #include "help-stores.md" + #include "../common/help-stores.md" ; } @@ -314,15 +273,7 @@ void mainWrapped(int argc, char * * argv) { savedArgv = argv; - /* The chroot helper needs to be run before any threads have been - started. */ - if (argc > 0 && argv[0] == chrootHelperName) { - chrootHelper(argc, argv); - return; - } - initNix(); - initGC(); #if __linux__ if (getuid() == 0) { @@ -334,23 +285,14 @@ void mainWrapped(int argc, char * * argv) } #endif - Finally f([] { logger->stop(); }); - programPath = argv[0]; auto programName = std::string(baseNameOf(programPath)); - if (argc > 1 && std::string_view(argv[1]) == "__build-remote") { - programName = "build-remote"; - argv++; argc--; - } - { auto legacy = (*RegisterLegacyCommand::commands)[programName]; if (legacy) return legacy(argc, argv); } - evalSettings.pureEval = true; - setLogFormat("bar"); settings.verboseBuild = false; if (isatty(STDERR_FILENO)) { @@ -359,6 +301,8 @@ void mainWrapped(int argc, char * * argv) verbosity = lvlInfo; } + Finally f([] { logger->stop(); }); + NixArgs args; if (argc == 2 && std::string(argv[1]) == "__dump-cli") { @@ -366,47 +310,6 @@ void mainWrapped(int argc, char * * argv) return; } - if (argc == 2 && std::string(argv[1]) == "__dump-language") { - experimentalFeatureSettings.experimentalFeatures = { - Xp::Flakes, - Xp::FetchClosure, - Xp::DynamicDerivations, - }; - evalSettings.pureEval = false; - EvalState state({}, openStore("dummy://")); - auto res = nlohmann::json::object(); - res["builtins"] = ({ - auto builtinsJson = nlohmann::json::object(); - auto builtins = state.baseEnv.values[0]->attrs; - for (auto & builtin : *builtins) { - auto b = nlohmann::json::object(); - if (!builtin.value->isPrimOp()) continue; - auto primOp = builtin.value->primOp; - if (!primOp->doc) continue; - b["arity"] = primOp->arity; - b["args"] = primOp->args; - b["doc"] = trim(stripIndentation(primOp->doc)); - b["experimental-feature"] = primOp->experimentalFeature; - builtinsJson[state.symbols[builtin.name]] = std::move(b); - } - std::move(builtinsJson); - }); - res["constants"] = ({ - auto constantsJson = nlohmann::json::object(); - for (auto & [name, info] : state.constantInfos) { - auto c = nlohmann::json::object(); - if (!info.doc) continue; - c["doc"] = trim(stripIndentation(info.doc)); - c["type"] = showType(info.type, false); - c["impure-only"] = info.impureOnly; - constantsJson[name] = std::move(c); - } - std::move(constantsJson); - }); - logger->cout("%s", res); - return; - } - if (argc == 2 && std::string(argv[1]) == "__dump-xp-features") { logger->cout(documentExperimentalFeatures().dump()); return; @@ -486,9 +389,6 @@ void mainWrapped(int argc, char * * argv) settings.ttlPositiveNarInfoCache = 0; } - if (args.command->second->forceImpureByDefault() && !evalSettings.pureEval.overridden) { - evalSettings.pureEval = false; - } args.command->second->run(); } diff --git a/src/nix/store/nix.md b/src/nix/store/nix.md new file mode 100644 index 000000000000..106e37e95f82 --- /dev/null +++ b/src/nix/store/nix.md @@ -0,0 +1,44 @@ +R""( + +# Description + +Nix is a tool for building software, configurations and other +artifacts in a reproducible and declarative way. For more information, +see the [Nix homepage](https://nixos.org/) or the [Nix +manual](https://nixos.org/manual/nix/stable/). + +# Installables + +Many `nix` subcommands operate on one or more *installables*. These are +command line arguments that represent something that can be built in +the Nix store. Here are the recognised types of installables: + +* **Store paths**: `/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10` + + These are paths inside the Nix store, or symlinks that resolve to a + path in the Nix store. + +* **Store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv` + + Store derivations are store paths with extension `.drv` and are a + low-level representation of a build-time dependency graph used + internally by Nix. By default, if you pass a store derivation to a + `nix` subcommand, it will operate on the *output paths* of the + derivation. For example, `nix path-info` prints information about + the output paths: + + ```console + # nix path-info --json /nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv + [{"path":"/nix/store/v5sv61sszx301i0x6xysaqzla09nksnd-hello-2.10",…}] + ``` + + If you want to operate on the store derivation itself, pass the + `--derivation` flag. + +# Nix stores + +Most `nix` subcommands operate on a *Nix store*. + +TODO: list store types, options + +)""