diff --git a/src/nix/formatter-build.md b/src/nix/formatter-build.md new file mode 100644 index 000000000..fbb6adb1c --- /dev/null +++ b/src/nix/formatter-build.md @@ -0,0 +1,23 @@ +R""( + +# Description + +`nix formatter build` builds the formatter specified in the flake. + +Similar to [`nix build`](@docroot@/command-ref/new-cli/nix3-build.md), +unless `--no-link` is specified, after a successful +build, it creates a symlink to the store path of the formatter. This symlink is +named `./result` by default; this can be overridden using the +`--out-link` option. + +It always prints the command to standard output. + +# Examples + +* Build the formatter: + + ```console + # nix formatter build + /nix/store/cb9w44vkhk2x4adfxwgdkkf5gjmm856j-treefmt/bin/treefmt + ``` +)"" diff --git a/src/nix/formatter.cc b/src/nix/formatter.cc index 80ce64d28..0f915e7c9 100644 --- a/src/nix/formatter.cc +++ b/src/nix/formatter.cc @@ -1,6 +1,8 @@ #include "nix/cmd/command.hh" #include "nix/cmd/installable-value.hh" #include "nix/expr/eval.hh" +#include "nix/store/local-fs-store.hh" +#include "nix/cmd/installable-derived-path.hh" #include "run.hh" using namespace nix; @@ -25,7 +27,7 @@ struct CmdFormatter : NixMultiCommand static auto rCmdFormatter = registerCommand("formatter"); -struct CmdFormatterRun : SourceExprCommand +struct CmdFormatterRun : SourceExprCommand, MixJSON { std::vector args; @@ -87,6 +89,80 @@ struct CmdFormatterRun : SourceExprCommand static auto rFormatterRun = registerCommand2({"formatter", "run"}); +struct CmdFormatterBuild : SourceExprCommand +{ + Path outLink = "result"; + + CmdFormatterBuild() + { + addFlag({ + .longName = "out-link", + .shortName = 'o', + .description = "Use *path* as prefix for the symlink to the build result. It defaults to `result`.", + .labels = {"path"}, + .handler = {&outLink}, + .completer = completePath, + }); + + addFlag({ + .longName = "no-link", + .description = "Do not create symlink to the build results.", + .handler = {&outLink, Path("")}, + }); + } + + std::string description() override + { + return "build the current flake's formatter"; + } + + std::string doc() override + { + return +#include "formatter-build.md" + ; + } + + Category category() override + { + return catSecondary; + } + + Strings getDefaultFlakeAttrPaths() override + { + return Strings{"formatter." + settings.thisSystem.get()}; + } + + Strings getDefaultFlakeAttrPathPrefixes() override + { + return Strings{}; + } + + void run(ref store) override + { + auto evalState = getEvalState(); + auto evalStore = getEvalStore(); + + auto installable_ = parseInstallable(store, "."); + auto & installable = InstallableValue::require(*installable_); + auto unresolvedApp = installable.toApp(*evalState); + auto app = unresolvedApp.resolve(evalStore, store); + + Installables installableContext; + for (auto & ctxElt : unresolvedApp.unresolved.context) + installableContext.push_back(make_ref(store, DerivedPath{ctxElt})); + auto buildables = Installable::build(evalStore, store, Realise::Outputs, installableContext); + + if (outLink != "") + if (auto store2 = store.dynamic_pointer_cast()) + createOutLinks(outLink, toBuiltPaths(buildables), *store2); + + logger->cout("%s", app.program); + }; +}; + +static auto rFormatterBuild = registerCommand2({"formatter", "build"}); + struct CmdFmt : CmdFormatterRun { void run(ref store) override diff --git a/tests/functional/formatter.sh b/tests/functional/formatter.sh index e9bff50d5..ea6f9e1ce 100755 --- a/tests/functional/formatter.sh +++ b/tests/functional/formatter.sh @@ -7,11 +7,14 @@ TODO_NixOS # Provide a `shell` variable. Try not to `export` it, perhaps. clearStoreIfPossible rm -rf "$TEST_HOME"/.cache "$TEST_HOME"/.config "$TEST_HOME"/.local -cp ./simple.nix ./simple.builder.sh ./fmt.simple.sh "${config_nix}" "$TEST_HOME" +cp ./simple.nix ./simple.builder.sh ./formatter.simple.sh "${config_nix}" "$TEST_HOME" cd "$TEST_HOME" -nix fmt --help | grep "forward" +nix formatter --help | grep "build or run the formatter" +nix fmt --help | grep "reformat your code" +nix fmt run --help | grep "reformat your code" +nix fmt build --help | grep "build" cat << EOF > flake.nix { @@ -23,16 +26,37 @@ cat << EOF > flake.nix buildCommand = '' mkdir -p \$out/bin echo "#! ${shell}" > \$out/bin/formatter - cat \${./fmt.simple.sh} >> \$out/bin/formatter + cat \${./formatter.simple.sh} >> \$out/bin/formatter chmod +x \$out/bin/formatter ''; }; }; } EOF + # No arguments check [[ "$(nix fmt)" = "Formatting(0):" ]] +[[ "$(nix formatter run)" = "Formatting(0):" ]] + # Argument forwarding check nix fmt ./file ./folder | grep 'Formatting(2): ./file ./folder' +nix formatter run ./file ./folder | grep 'Formatting(2): ./file ./folder' + +# Build checks +## Defaults to a ./result. +nix formatter build | grep ".\+/bin/formatter" +[[ -L ./result ]] +rm result + +## Can prevent the symlink. +nix formatter build --no-link +[[ ! -e ./result ]] + +## Can change the symlink name. +nix formatter build --out-link my-result | grep ".\+/bin/formatter" +[[ -L ./my-result ]] +rm ./my-result + +# Flake outputs check. nix flake check nix flake show | grep -P "package 'formatter'"