mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +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.
|
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
|
# Example
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#include "nix/cmd/command.hh"
|
#include "nix/cmd/command.hh"
|
||||||
|
#include "nix/cmd/installable-flake.hh"
|
||||||
#include "nix/cmd/installable-value.hh"
|
#include "nix/cmd/installable-value.hh"
|
||||||
#include "nix/expr/eval.hh"
|
#include "nix/expr/eval.hh"
|
||||||
#include "nix/store/local-fs-store.hh"
|
#include "nix/store/local-fs-store.hh"
|
||||||
#include "nix/cmd/installable-derived-path.hh"
|
#include "nix/cmd/installable-derived-path.hh"
|
||||||
|
#include "nix/util/environment-variables.hh"
|
||||||
#include "run.hh"
|
#include "run.hh"
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
@ -72,10 +74,14 @@ struct CmdFormatterRun : MixFormatter, MixJSON
|
||||||
auto evalState = getEvalState();
|
auto evalState = getEvalState();
|
||||||
auto evalStore = getEvalStore();
|
auto evalStore = getEvalStore();
|
||||||
|
|
||||||
auto installable_ = parseInstallable(store, ".");
|
auto installable_ = parseInstallable(store, ".").cast<InstallableFlake>();
|
||||||
auto & installable = InstallableValue::require(*installable_);
|
auto & installable = InstallableValue::require(*installable_);
|
||||||
auto app = installable.toApp(*evalState).resolve(evalStore, store);
|
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};
|
Strings programArgs{app.program};
|
||||||
|
|
||||||
// Propagate arguments from the CLI
|
// Propagate arguments from the CLI
|
||||||
|
@ -83,11 +89,22 @@ struct CmdFormatterRun : MixFormatter, MixJSON
|
||||||
programArgs.push_back(i);
|
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
|
// 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.
|
// we are about to exec out of this process without running C++ destructors.
|
||||||
evalState->evalCaches.clear();
|
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/finally.hh"
|
||||||
#include "nix/util/source-accessor.hh"
|
#include "nix/util/source-accessor.hh"
|
||||||
#include "nix/expr/eval.hh"
|
#include "nix/expr/eval.hh"
|
||||||
|
#include "nix/util/util.hh"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
|
@ -19,6 +20,8 @@
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
extern char ** environ __attribute__((weak));
|
||||||
|
|
||||||
namespace nix::fs { using namespace std::filesystem; }
|
namespace nix::fs { using namespace std::filesystem; }
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
@ -27,14 +30,37 @@ std::string chrootHelperName = "__run_in_chroot";
|
||||||
|
|
||||||
namespace nix {
|
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,
|
void execProgramInStore(ref<Store> store,
|
||||||
UseLookupPath useLookupPath,
|
UseLookupPath useLookupPath,
|
||||||
const std::string & program,
|
const std::string & program,
|
||||||
const Strings & args,
|
const Strings & args,
|
||||||
std::optional<std::string_view> system)
|
std::optional<std::string_view> system,
|
||||||
|
std::optional<StringMap> env)
|
||||||
{
|
{
|
||||||
logger->stop();
|
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();
|
restoreProcessContext();
|
||||||
|
|
||||||
/* If this is a diverted store (i.e. its "logical" location
|
/* 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 };
|
Strings helperArgs = { chrootHelperName, store->storeDir, store2->getRealStoreDir(), std::string(system.value_or("")), program };
|
||||||
for (auto & arg : args) helperArgs.push_back(arg);
|
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");
|
throw SysError("could not execute chroot helper");
|
||||||
}
|
}
|
||||||
|
@ -64,10 +90,12 @@ void execProgramInStore(ref<Store> store,
|
||||||
linux::setPersonality(*system);
|
linux::setPersonality(*system);
|
||||||
#endif
|
#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());
|
execvp(program.c_str(), stringsToCharPtrs(args).data());
|
||||||
else
|
} else
|
||||||
execv(program.c_str(), stringsToCharPtrs(args).data());
|
execve(program.c_str(), stringsToCharPtrs(args).data(), envp);
|
||||||
|
|
||||||
throw SysError("unable to execute '%s'", program);
|
throw SysError("unable to execute '%s'", program);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ void execProgramInStore(ref<Store> store,
|
||||||
UseLookupPath useLookupPath,
|
UseLookupPath useLookupPath,
|
||||||
const std::string & program,
|
const std::string & program,
|
||||||
const Strings & args,
|
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
|
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
|
# No arguments check
|
||||||
[[ "$(nix fmt)" = "Formatting(0):" ]]
|
[[ "$(nix fmt)" = "PRJ_ROOT=$TEST_HOME Formatting(0):" ]]
|
||||||
[[ "$(nix formatter run)" = "Formatting(0):" ]]
|
[[ "$(nix formatter run)" = "PRJ_ROOT=$TEST_HOME Formatting(0):" ]]
|
||||||
|
|
||||||
# Argument forwarding check
|
# Argument forwarding check
|
||||||
nix fmt ./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 '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
|
# Build checks
|
||||||
## Defaults to a ./result.
|
## Defaults to a ./result.
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
echo "Formatting(${#}):" "${@}"
|
echo "PRJ_ROOT=$PRJ_ROOT Formatting(${#}):" "${@}"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue