diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2020-12-03 13:38:29 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-03 13:38:29 +0100 |
commit | 4f25644a130748296326470b0d8000dc2ac46c8f (patch) | |
tree | 903870a101108976e5a138a2cd2bb51950d40dea | |
parent | 7cb341ceb5b55354558fa40080e68e30c2704060 (diff) | |
parent | e2efc63979a5485a96accaa1e49ffec65c353078 (diff) |
Merge pull request #4304 from NixOS/separate-manpages
Separate manpages for 'nix' subcommands
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | doc/manual/generate-manpage.nix | 59 | ||||
-rw-r--r-- | doc/manual/local.mk | 28 | ||||
-rw-r--r-- | doc/manual/src/SUMMARY.md.in (renamed from doc/manual/src/SUMMARY.md) | 2 | ||||
-rw-r--r-- | src/nix/eval.cc | 55 | ||||
-rw-r--r-- | src/nix/main.cc | 44 | ||||
-rw-r--r-- | tests/pure-eval.sh | 8 |
7 files changed, 166 insertions, 33 deletions
diff --git a/.gitignore b/.gitignore index c51582cf0..37aada307 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,8 @@ perl/Makefile.config /doc/manual/nix.json /doc/manual/conf-file.json /doc/manual/builtins.json -/doc/manual/src/command-ref/nix.md +/doc/manual/src/SUMMARY.md +/doc/manual/src/command-ref/new-cli /doc/manual/src/command-ref/conf-file.md /doc/manual/src/expressions/builtins.md diff --git a/doc/manual/generate-manpage.nix b/doc/manual/generate-manpage.nix index db266750a..4a0b0290b 100644 --- a/doc/manual/generate-manpage.nix +++ b/doc/manual/generate-manpage.nix @@ -1,33 +1,40 @@ +command: + with builtins; with import ./utils.nix; let showCommand = - { command, section, def }: - "${section} Name\n\n" + { command, def, filename }: + "# Name\n\n" + "`${command}` - ${def.description}\n\n" - + "${section} Synopsis\n\n" + + "# Synopsis\n\n" + showSynopsis { inherit command; args = def.args; } - + (if def ? doc - then "${section} Description\n\n" + def.doc + "\n\n" - else "") - + (let s = showFlags def.flags; in - if s != "" - then "${section} Flags\n\n${s}" + + (if def.commands or {} != {} + then + "where *subcommand* is one of the following:\n\n" + # FIXME: group by category + + concatStrings (map (name: + "* [`${command} ${name}`](./${appendName filename name}.md) - ${def.commands.${name}.description}\n") + (attrNames def.commands)) + + "\n" else "") + (if def.examples or [] != [] then - "${section} Examples\n\n" + "# Examples\n\n" + concatStrings (map ({ description, command }: "${description}\n\n```console\n${command}\n```\n\n") def.examples) else "") - + (if def.commands or [] != [] - then concatStrings ( - map (name: - "# Subcommand `${command} ${name}`\n\n" - + showCommand { command = command + " " + name; section = "##"; def = def.commands.${name}; }) - (attrNames def.commands)) - else ""); + + (if def ? doc + then "# Description\n\n" + def.doc + "\n\n" + else "") + + (let s = showFlags def.flags; in + if s != "" + then "# Flags\n\n${s}" + else "") + ; + + appendName = filename: name: (if filename == "nix" then "nix3" else filename) + "-" + name; showFlags = flags: concatStrings @@ -48,8 +55,20 @@ let "`${command}` [*flags*...] ${concatStringsSep " " (map (arg: "*${arg.label}*" + (if arg ? arity then "" else "...")) args)}\n\n"; -in + processCommand = { command, def, filename }: + [ { name = filename + ".md"; value = showCommand { inherit command def filename; }; inherit command; } ] + ++ concatMap + (name: processCommand { + filename = appendName filename name; + command = command + " " + name; + def = def.commands.${name}; + }) + (attrNames def.commands or {}); -command: +in -showCommand { command = "nix"; section = "#"; def = command; } +let + manpages = processCommand { filename = "nix"; command = "nix"; def = command; }; + summary = concatStrings (map (manpage: " - [${manpage.command}](command-ref/new-cli/${manpage.name})\n") manpages); +in +(listToAttrs manpages) // { "SUMMARY.md" = summary; } diff --git a/doc/manual/local.mk b/doc/manual/local.mk index bb8b3b60a..b40fa4ed2 100644 --- a/doc/manual/local.mk +++ b/doc/manual/local.mk @@ -4,7 +4,7 @@ MANUAL_SRCS := $(call rwildcard, $(d)/src, *.md) # Generate man pages. man-pages := $(foreach n, \ - nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 nix.1 \ + nix-env.1 nix-build.1 nix-shell.1 nix-store.1 nix-instantiate.1 \ nix-collect-garbage.1 \ nix-prefetch-url.1 nix-channel.1 \ nix-hash.1 nix-copy-closure.1 \ @@ -22,7 +22,7 @@ dummy-env = env -i \ NIX_SSL_CERT_FILE=/dummy/no-ca-bundle.crt \ NIX_STATE_DIR=/dummy -nix-eval = $(dummy-env) $(bindir)/nix eval --experimental-features nix-command -I nix/corepkgs=corepkgs --store dummy:// --impure --raw --expr +nix-eval = $(dummy-env) $(bindir)/nix eval --experimental-features nix-command -I nix/corepkgs=corepkgs --store dummy:// --impure --raw $(d)/%.1: $(d)/src/command-ref/%.md @printf "Title: %s\n\n" "$$(basename $@ .1)" > $^.tmp @@ -42,13 +42,17 @@ $(d)/nix.conf.5: $(d)/src/command-ref/conf-file.md $(trace-gen) lowdown -sT man $^.tmp -o $@ @rm $^.tmp -$(d)/src/command-ref/nix.md: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix - $(trace-gen) $(nix-eval) 'import doc/manual/generate-manpage.nix (builtins.fromJSON (builtins.readFile $<))' > $@.tmp +$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli + $(trace-gen) cat doc/manual/src/SUMMARY.md.in | while IFS= read line; do if [[ $$line = @manpages@ ]]; then cat doc/manual/src/command-ref/new-cli/SUMMARY.md; else echo "$$line"; fi; done > $@.tmp @mv $@.tmp $@ +$(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/generate-manpage.nix $(bindir)/nix + @rm -rf $@ + $(trace-gen) $(nix-eval) --write-to $@ --expr 'import doc/manual/generate-manpage.nix (builtins.fromJSON (builtins.readFile $<))' + $(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/generate-options.nix $(d)/src/command-ref/conf-file-prefix.md $(bindir)/nix @cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp - $(trace-gen) $(nix-eval) 'import doc/manual/generate-options.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp + $(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-options.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp @mv $@.tmp $@ $(d)/nix.json: $(bindir)/nix @@ -61,7 +65,7 @@ $(d)/conf-file.json: $(bindir)/nix $(d)/src/expressions/builtins.md: $(d)/builtins.json $(d)/generate-builtins.nix $(d)/src/expressions/builtins-prefix.md $(bindir)/nix @cat doc/manual/src/expressions/builtins-prefix.md > $@.tmp - $(trace-gen) $(nix-eval) 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp + $(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp @mv $@.tmp $@ $(d)/builtins.json: $(bindir)/nix @@ -71,7 +75,17 @@ $(d)/builtins.json: $(bindir)/nix # Generate the HTML manual. install: $(docdir)/manual/index.html -$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/custom.css $(d)/src/command-ref/nix.md $(d)/src/command-ref/conf-file.md $(d)/src/expressions/builtins.md +# Generate 'nix' manpages. +install: $(d)/src/command-ref/new-cli + for i in doc/manual/src/command-ref/new-cli/*.md; do \ + name=$$(basename $$i .md); \ + if [[ $$name = SUMMARY ]]; then continue; fi; \ + printf "Title: %s\n\n" "$$name" > $$i.tmp; \ + cat $$i >> $$i.tmp; \ + lowdown -sT man $$i.tmp -o $(mandir)/man1/$$name.1; \ + done + +$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/command-ref/conf-file.md $(d)/src/expressions/builtins.md $(trace-gen) mdbook build doc/manual -d $(docdir)/manual @cp doc/manual/highlight.pack.js $(docdir)/manual/highlight.js diff --git a/doc/manual/src/SUMMARY.md b/doc/manual/src/SUMMARY.md.in index 8281f683f..b5ae34cfa 100644 --- a/doc/manual/src/SUMMARY.md +++ b/doc/manual/src/SUMMARY.md.in @@ -62,7 +62,7 @@ - [nix-instantiate](command-ref/nix-instantiate.md) - [nix-prefetch-url](command-ref/nix-prefetch-url.md) - [Experimental Commands](command-ref/experimental-commands.md) - - [nix](command-ref/nix.md) +@manpages@ - [Files](command-ref/files.md) - [nix.conf](command-ref/conf-file.md) - [Glossary](glossary.md) diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 8da81d667..0f02919de 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -3,6 +3,7 @@ #include "shared.hh" #include "store-api.hh" #include "eval.hh" +#include "eval-inline.hh" #include "json.hh" #include "value-to-json.hh" #include "progress-bar.hh" @@ -13,6 +14,7 @@ struct CmdEval : MixJSON, InstallableCommand { bool raw = false; std::optional<std::string> apply; + std::optional<Path> writeTo; CmdEval() { @@ -24,6 +26,13 @@ struct CmdEval : MixJSON, InstallableCommand .labels = {"expr"}, .handler = {&apply}, }); + + addFlag({ + .longName = "write-to", + .description = "write a string or attrset of strings to 'path'", + .labels = {"path"}, + .handler = {&writeTo}, + }); } std::string description() override @@ -66,7 +75,7 @@ struct CmdEval : MixJSON, InstallableCommand auto state = getEvalState(); - auto v = installable->toValue(*state).first; + auto [v, pos] = installable->toValue(*state); PathSet context; if (apply) { @@ -77,13 +86,51 @@ struct CmdEval : MixJSON, InstallableCommand v = vRes; } - if (raw) { + if (writeTo) { + stopProgressBar(); + + if (pathExists(*writeTo)) + throw Error("path '%s' already exists", *writeTo); + + std::function<void(Value & v, const Pos & pos, const Path & path)> recurse; + + recurse = [&](Value & v, const Pos & pos, const Path & path) + { + state->forceValue(v); + if (v.type == tString) + // FIXME: disallow strings with contexts? + writeFile(path, v.string.s); + else if (v.type == tAttrs) { + if (mkdir(path.c_str(), 0777) == -1) + throw SysError("creating directory '%s'", path); + for (auto & attr : *v.attrs) + try { + if (attr.name == "." || attr.name == "..") + throw Error("invalid file name '%s'", attr.name); + recurse(*attr.value, *attr.pos, path + "/" + std::string(attr.name)); + } catch (Error & e) { + e.addTrace(*attr.pos, hintfmt("while evaluating the attribute '%s'", attr.name)); + throw; + } + } + else + throw TypeError("value at '%s' is not a string or an attribute set", pos); + }; + + recurse(*v, pos, *writeTo); + } + + else if (raw) { stopProgressBar(); std::cout << state->coerceToString(noPos, *v, context); - } else if (json) { + } + + else if (json) { JSONPlaceholder jsonOut(std::cout); printValueAsJSON(*state, true, *v, jsonOut, context); - } else { + } + + else { state->forceValueDeep(*v); logger->cout("%s", *v); } diff --git a/src/nix/main.cc b/src/nix/main.cc index 5056ceb78..a75f8ae65 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -149,6 +149,50 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs } }; +static void showHelp(std::vector<std::string> subcommand) +{ + showManPage(subcommand.empty() ? "nix" : fmt("nix3-%s", concatStringsSep("-", subcommand))); +} + +struct CmdHelp : Command +{ + std::vector<std::string> subcommand; + + CmdHelp() + { + expectArgs({ + .label = "subcommand", + .handler = {&subcommand}, + }); + } + + std::string description() override + { + return "show help about 'nix' or a particular subcommand"; + } + + Examples examples() override + { + return { + Example{ + "To show help about 'nix' in general:", + "nix help" + }, + Example{ + "To show help about a particular subcommand:", + "nix help run" + }, + }; + } + + void run() override + { + showHelp(subcommand); + } +}; + +static auto rCmdHelp = registerCommand<CmdHelp>("help"); + void mainWrapped(int argc, char * * argv) { /* The chroot helper needs to be run before any threads have been diff --git a/tests/pure-eval.sh b/tests/pure-eval.sh index 43a765997..561ca53fb 100644 --- a/tests/pure-eval.sh +++ b/tests/pure-eval.sh @@ -16,3 +16,11 @@ nix eval --expr 'assert 1 + 2 == 3; true' [[ $(nix eval --impure --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x") == 123 ]] (! nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; })).x") nix eval --expr "(import (builtins.fetchurl { url = file://$(pwd)/pure-eval.nix; sha256 = \"$(nix hash-file pure-eval.nix --type sha256)\"; })).x" + +rm -rf $TEST_ROOT/eval-out +nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ x = "foo" + "bar"; y = { z = "bla"; }; }' +[[ $(cat $TEST_ROOT/eval-out/x) = foobar ]] +[[ $(cat $TEST_ROOT/eval-out/y/z) = bla ]] + +rm -rf $TEST_ROOT/eval-out +(! nix eval --store dummy:// --write-to $TEST_ROOT/eval-out --expr '{ "." = "bla"; }') |