mirror of
https://github.com/NixOS/nix
synced 2025-06-24 18:01:16 +02:00
Expose flake directory to nix fmt as PRJ_ROOT env var
This was discussed in https://github.com/NixOS/nix/issues/8034. I personally like `PRJ_ROOT`, which hopefully avoids some ambiguity around with subflakes. I only implemented this for `nix fmt` because it doesn't let you point at a flake not on your filesystem. macOS compilation fixes
This commit is contained in:
parent
76a4d4c291
commit
17eb2e8400
6 changed files with 88 additions and 13 deletions
|
@ -8,6 +8,10 @@ Flags can be forwarded to the formatter by using `--` followed by the flags.
|
|||
|
||||
Any arguments will be forwarded to the formatter. Typically these are the files to format.
|
||||
|
||||
The environment variable `PRJ_ROOT` (according to [prj-spec](https://github.com/numtide/prj-spec))
|
||||
will be set to the absolute path to the directory containing the closest parent `flake.nix`
|
||||
relative to the current directory.
|
||||
|
||||
|
||||
# Example
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "nix/cmd/command.hh"
|
||||
#include "nix/cmd/installable-flake.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 "nix/util/environment-variables.hh"
|
||||
#include "run.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
@ -72,10 +74,14 @@ struct CmdFormatterRun : MixFormatter, MixJSON
|
|||
auto evalState = getEvalState();
|
||||
auto evalStore = getEvalStore();
|
||||
|
||||
auto installable_ = parseInstallable(store, ".");
|
||||
auto installable_ = parseInstallable(store, ".").cast<InstallableFlake>();
|
||||
auto & installable = InstallableValue::require(*installable_);
|
||||
auto app = installable.toApp(*evalState).resolve(evalStore, store);
|
||||
|
||||
auto maybeFlakeDir = installable_->flakeRef.input.getSourcePath();
|
||||
assert(maybeFlakeDir.has_value());
|
||||
auto flakeDir = maybeFlakeDir.value();
|
||||
|
||||
Strings programArgs{app.program};
|
||||
|
||||
// Propagate arguments from the CLI
|
||||
|
@ -83,11 +89,22 @@ struct CmdFormatterRun : MixFormatter, MixJSON
|
|||
programArgs.push_back(i);
|
||||
}
|
||||
|
||||
// Add the path to the flake as an environment variable. This enables formatters to format the entire flake even
|
||||
// if run from a subdirectory.
|
||||
StringMap env = getEnv();
|
||||
env["PRJ_ROOT"] = flakeDir;
|
||||
|
||||
// Release our references to eval caches to ensure they are persisted to disk, because
|
||||
// we are about to exec out of this process without running C++ destructors.
|
||||
evalState->evalCaches.clear();
|
||||
|
||||
execProgramInStore(store, UseLookupPath::DontUse, app.program, programArgs);
|
||||
execProgramInStore(
|
||||
store,
|
||||
UseLookupPath::DontUse,
|
||||
app.program,
|
||||
programArgs,
|
||||
std::nullopt, // Use default system
|
||||
env);
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "nix/util/finally.hh"
|
||||
#include "nix/util/source-accessor.hh"
|
||||
#include "nix/expr/eval.hh"
|
||||
#include "nix/util/util.hh"
|
||||
#include <filesystem>
|
||||
|
||||
#ifdef __linux__
|
||||
|
@ -19,6 +20,8 @@
|
|||
|
||||
#include <queue>
|
||||
|
||||
extern char ** environ __attribute__((weak));
|
||||
|
||||
namespace nix::fs { using namespace std::filesystem; }
|
||||
|
||||
using namespace nix;
|
||||
|
@ -27,14 +30,37 @@ std::string chrootHelperName = "__run_in_chroot";
|
|||
|
||||
namespace nix {
|
||||
|
||||
/* Convert `env` to a list of strings suitable for `execve`'s `envp` argument. */
|
||||
Strings toEnvp(StringMap env)
|
||||
{
|
||||
Strings envStrs;
|
||||
for (auto & i : env) {
|
||||
envStrs.push_back(i.first + "=" + i.second);
|
||||
}
|
||||
|
||||
return envStrs;
|
||||
}
|
||||
|
||||
void execProgramInStore(ref<Store> store,
|
||||
UseLookupPath useLookupPath,
|
||||
const std::string & program,
|
||||
const Strings & args,
|
||||
std::optional<std::string_view> system)
|
||||
std::optional<std::string_view> system,
|
||||
std::optional<StringMap> env)
|
||||
{
|
||||
logger->stop();
|
||||
|
||||
char **envp;
|
||||
Strings envStrs;
|
||||
std::vector<char *> envCharPtrs;
|
||||
if (env.has_value()) {
|
||||
envStrs = toEnvp(env.value());
|
||||
envCharPtrs = stringsToCharPtrs(envStrs);
|
||||
envp = envCharPtrs.data();
|
||||
} else {
|
||||
envp = environ;
|
||||
}
|
||||
|
||||
restoreProcessContext();
|
||||
|
||||
/* If this is a diverted store (i.e. its "logical" location
|
||||
|
@ -54,7 +80,7 @@ void execProgramInStore(ref<Store> store,
|
|||
Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), std::string(system.value_or("")), program };
|
||||
for (auto & arg : args) helperArgs.push_back(arg);
|
||||
|
||||
execv(getSelfExe().value_or("nix").c_str(), stringsToCharPtrs(helperArgs).data());
|
||||
execve(getSelfExe().value_or("nix").c_str(), stringsToCharPtrs(helperArgs).data(), envp);
|
||||
|
||||
throw SysError("could not execute chroot helper");
|
||||
}
|
||||
|
@ -64,10 +90,12 @@ void execProgramInStore(ref<Store> store,
|
|||
linux::setPersonality(*system);
|
||||
#endif
|
||||
|
||||
if (useLookupPath == UseLookupPath::Use)
|
||||
if (useLookupPath == UseLookupPath::Use) {
|
||||
// We have to set `environ` by hand because there is no `execvpe` on macOS.
|
||||
environ = envp;
|
||||
execvp(program.c_str(), stringsToCharPtrs(args).data());
|
||||
else
|
||||
execv(program.c_str(), stringsToCharPtrs(args).data());
|
||||
} else
|
||||
execve(program.c_str(), stringsToCharPtrs(args).data(), envp);
|
||||
|
||||
throw SysError("unable to execute '%s'", program);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ void execProgramInStore(ref<Store> store,
|
|||
UseLookupPath useLookupPath,
|
||||
const std::string & program,
|
||||
const Strings & args,
|
||||
std::optional<std::string_view> system = std::nullopt);
|
||||
std::optional<std::string_view> system = std::nullopt,
|
||||
std::optional<StringMap> env = std::nullopt);
|
||||
|
||||
}
|
||||
|
|
|
@ -34,13 +34,38 @@ cat << EOF > flake.nix
|
|||
}
|
||||
EOF
|
||||
|
||||
mkdir subflake
|
||||
cp ./simple.nix ./simple.builder.sh ./formatter.simple.sh "${config_nix}" "$TEST_HOME/subflake"
|
||||
|
||||
cat << EOF > subflake/flake.nix
|
||||
{
|
||||
outputs = _: {
|
||||
formatter.$system =
|
||||
with import ./config.nix;
|
||||
mkDerivation {
|
||||
name = "formatter";
|
||||
buildCommand = ''
|
||||
mkdir -p \$out/bin
|
||||
echo "#! ${shell}" > \$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):" ]]
|
||||
[[ "$(nix fmt)" = "PRJ_ROOT=$TEST_HOME Formatting(0):" ]]
|
||||
[[ "$(nix formatter run)" = "PRJ_ROOT=$TEST_HOME Formatting(0):" ]]
|
||||
|
||||
# Argument forwarding check
|
||||
nix fmt ./file ./folder | grep 'Formatting(2): ./file ./folder'
|
||||
nix formatter run ./file ./folder | grep 'Formatting(2): ./file ./folder'
|
||||
nix fmt ./file ./folder | grep "PRJ_ROOT=$TEST_HOME Formatting(2): ./file ./folder"
|
||||
nix formatter run ./file ./folder | grep "PRJ_ROOT=$TEST_HOME Formatting(2): ./file ./folder"
|
||||
|
||||
# test subflake
|
||||
cd subflake
|
||||
nix fmt ./file | grep "PRJ_ROOT=$TEST_HOME/subflake Formatting(1): ./file"
|
||||
|
||||
# Build checks
|
||||
## Defaults to a ./result.
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
#!/usr/bin/env bash
|
||||
echo "Formatting(${#}):" "${@}"
|
||||
echo "PRJ_ROOT=$PRJ_ROOT Formatting(${#}):" "${@}"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue