mirror of
https://github.com/NixOS/nix.git
synced 2025-11-11 04:56:01 +01:00
Add position info to path values
(Actually, this adds a position field to *all* values.)
This allows improving the "inefficient double copy" warning by showing
where the source path came from in the source, e.g.
warning: Performing inefficient double copy of path '/home/eelco/Dev/patchelf/' to the store at /home/eelco/Dev/patchelf/flake.nix:30:17. This can typically be avoided by rewriting an attribute like `src = ./.` to `src = builtins.path { path = ./.; name = "source"; }`.
This commit is contained in:
parent
8ff43c29ef
commit
3e45b40d66
9 changed files with 33 additions and 20 deletions
|
|
@ -149,6 +149,8 @@ PosIdx Value::determinePos(const PosIdx pos) const
|
||||||
// Allow selecting a subset of enum values
|
// Allow selecting a subset of enum values
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
#pragma GCC diagnostic ignored "-Wswitch-enum"
|
||||||
|
if (this->pos != 0)
|
||||||
|
return PosIdx(this->pos);
|
||||||
switch (internalType) {
|
switch (internalType) {
|
||||||
case tAttrs: return attrs()->pos;
|
case tAttrs: return attrs()->pos;
|
||||||
case tLambda: return payload.lambda.fun->pos;
|
case tLambda: return payload.lambda.fun->pos;
|
||||||
|
|
@ -906,7 +908,7 @@ void Value::mkStringMove(const char * s, const NixStringContext & context)
|
||||||
|
|
||||||
void Value::mkPath(const SourcePath & path)
|
void Value::mkPath(const SourcePath & path)
|
||||||
{
|
{
|
||||||
mkPath(&*path.accessor, makeImmutableString(path.path.abs()));
|
mkPath(&*path.accessor, makeImmutableString(path.path.abs()), noPos.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2356,7 +2358,7 @@ BackedStringView EvalState::coerceToString(
|
||||||
// slash, as in /foo/${x}.
|
// slash, as in /foo/${x}.
|
||||||
v.payload.path.path
|
v.payload.path.path
|
||||||
: copyToStore
|
: copyToStore
|
||||||
? store->printStorePath(copyPathToStore(context, v.path()))
|
? store->printStorePath(copyPathToStore(context, v.path(), v.determinePos(pos)))
|
||||||
: ({
|
: ({
|
||||||
auto path = v.path();
|
auto path = v.path();
|
||||||
if (path.accessor == rootFS && store->isInStore(path.path.abs())) {
|
if (path.accessor == rootFS && store->isInStore(path.path.abs())) {
|
||||||
|
|
@ -2434,7 +2436,7 @@ BackedStringView EvalState::coerceToString(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePath & path)
|
StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePath & path, PosIdx pos)
|
||||||
{
|
{
|
||||||
if (nix::isDerivation(path.path.abs()))
|
if (nix::isDerivation(path.path.abs()))
|
||||||
error<EvalError>("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
|
error<EvalError>("file names are not allowed to end in '%1%'", drvExtension).debugThrow();
|
||||||
|
|
@ -2448,7 +2450,7 @@ StorePath EvalState::copyPathToStore(NixStringContext & context, const SourcePat
|
||||||
*store,
|
*store,
|
||||||
path.resolveSymlinks(SymlinkResolution::Ancestors),
|
path.resolveSymlinks(SymlinkResolution::Ancestors),
|
||||||
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
settings.readOnlyMode ? FetchMode::DryRun : FetchMode::Copy,
|
||||||
computeBaseName(path),
|
computeBaseName(path, pos),
|
||||||
ContentAddressMethod::Raw::NixArchive,
|
ContentAddressMethod::Raw::NixArchive,
|
||||||
nullptr,
|
nullptr,
|
||||||
repair);
|
repair);
|
||||||
|
|
|
||||||
|
|
@ -594,7 +594,7 @@ public:
|
||||||
bool coerceMore = false, bool copyToStore = true,
|
bool coerceMore = false, bool copyToStore = true,
|
||||||
bool canonicalizePath = true);
|
bool canonicalizePath = true);
|
||||||
|
|
||||||
StorePath copyPathToStore(NixStringContext & context, const SourcePath & path);
|
StorePath copyPathToStore(NixStringContext & context, const SourcePath & path, PosIdx pos);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -607,7 +607,7 @@ public:
|
||||||
* materialize /nix/store/<hash2>-source though. Still, this
|
* materialize /nix/store/<hash2>-source though. Still, this
|
||||||
* requires reading/hashing the path twice.
|
* requires reading/hashing the path twice.
|
||||||
*/
|
*/
|
||||||
std::string computeBaseName(const SourcePath & path);
|
std::string computeBaseName(const SourcePath & path, PosIdx pos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Path coercion.
|
* Path coercion.
|
||||||
|
|
|
||||||
|
|
@ -138,9 +138,9 @@ struct ExprPath : Expr
|
||||||
ref<SourceAccessor> accessor;
|
ref<SourceAccessor> accessor;
|
||||||
std::string s;
|
std::string s;
|
||||||
Value v;
|
Value v;
|
||||||
ExprPath(ref<SourceAccessor> accessor, std::string s) : accessor(accessor), s(std::move(s))
|
ExprPath(ref<SourceAccessor> accessor, std::string s, PosIdx pos) : accessor(accessor), s(std::move(s))
|
||||||
{
|
{
|
||||||
v.mkPath(&*accessor, this->s.c_str());
|
v.mkPath(&*accessor, this->s.c_str(), pos.get());
|
||||||
}
|
}
|
||||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||||
COMMON_METHODS
|
COMMON_METHODS
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,7 @@ struct Value
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
InternalType internalType = tUninitialized;
|
InternalType internalType = tUninitialized;
|
||||||
|
uint32_t pos{0};
|
||||||
|
|
||||||
friend std::string showType(const Value & v);
|
friend std::string showType(const Value & v);
|
||||||
|
|
||||||
|
|
@ -289,10 +290,11 @@ public:
|
||||||
unreachable();
|
unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void finishValue(InternalType newType, Payload newPayload)
|
inline void finishValue(InternalType newType, Payload newPayload, uint32_t newPos = 0)
|
||||||
{
|
{
|
||||||
payload = newPayload;
|
payload = newPayload;
|
||||||
internalType = newType;
|
internalType = newType;
|
||||||
|
pos = newPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -339,9 +341,9 @@ public:
|
||||||
void mkPath(const SourcePath & path);
|
void mkPath(const SourcePath & path);
|
||||||
void mkPath(std::string_view path);
|
void mkPath(std::string_view path);
|
||||||
|
|
||||||
inline void mkPath(SourceAccessor * accessor, const char * path)
|
inline void mkPath(SourceAccessor * accessor, const char * path, uint32_t pos)
|
||||||
{
|
{
|
||||||
finishValue(tPath, { .path = { .accessor = accessor, .path = path } });
|
finishValue(tPath, { .path = { .accessor = accessor, .path = path } }, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void mkNull()
|
inline void mkNull()
|
||||||
|
|
@ -482,6 +484,9 @@ public:
|
||||||
|
|
||||||
NixFloat fpoint() const
|
NixFloat fpoint() const
|
||||||
{ return payload.fpoint; }
|
{ return payload.fpoint; }
|
||||||
|
|
||||||
|
inline uint32_t getPos() const
|
||||||
|
{ return pos; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -374,8 +374,8 @@ path_start
|
||||||
root filesystem accessor, rather than the accessor of the
|
root filesystem accessor, rather than the accessor of the
|
||||||
current Nix expression. */
|
current Nix expression. */
|
||||||
literal.front() == '/'
|
literal.front() == '/'
|
||||||
? new ExprPath(state->rootFS, std::move(path))
|
? new ExprPath(state->rootFS, std::move(path), CUR_POS)
|
||||||
: new ExprPath(state->basePath.accessor, std::move(path));
|
: new ExprPath(state->basePath.accessor, std::move(path), CUR_POS);
|
||||||
}
|
}
|
||||||
| HPATH {
|
| HPATH {
|
||||||
if (state->settings.pureEval) {
|
if (state->settings.pureEval) {
|
||||||
|
|
@ -385,7 +385,7 @@ path_start
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Path path(getHome() + std::string($1.p + 1, $1.l - 1));
|
Path path(getHome() + std::string($1.p + 1, $1.l - 1));
|
||||||
$$ = new ExprPath(ref<SourceAccessor>(state->rootFS), std::move(path));
|
$$ = new ExprPath(ref<SourceAccessor>(state->rootFS), std::move(path), CUR_POS);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,15 +52,16 @@ std::string EvalState::devirtualize(std::string_view s, const NixStringContext &
|
||||||
return rewriteStrings(std::string(s), rewrites);
|
return rewriteStrings(std::string(s), rewrites);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string EvalState::computeBaseName(const SourcePath & path)
|
std::string EvalState::computeBaseName(const SourcePath & path, PosIdx pos)
|
||||||
{
|
{
|
||||||
if (path.accessor == rootFS) {
|
if (path.accessor == rootFS) {
|
||||||
if (auto storePath = store->maybeParseStorePath(path.path.abs())) {
|
if (auto storePath = store->maybeParseStorePath(path.path.abs())) {
|
||||||
warn(
|
warn(
|
||||||
"Performing inefficient double copy of path '%s' to the store. "
|
"Performing inefficient double copy of path '%s' to the store at %s. "
|
||||||
"This can typically be avoided by rewriting an attribute like `src = ./.` "
|
"This can typically be avoided by rewriting an attribute like `src = ./.` "
|
||||||
"to `src = builtins.path { path = ./.; name = \"source\"; }`.",
|
"to `src = builtins.path { path = ./.; name = \"source\"; }`.",
|
||||||
path);
|
path,
|
||||||
|
positions[pos]);
|
||||||
return std::string(fetchToStore(*store, path, FetchMode::DryRun, storePath->name()).to_string());
|
return std::string(fetchToStore(*store, path, FetchMode::DryRun, storePath->name()).to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2620,7 +2620,7 @@ static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * arg
|
||||||
"while evaluating the second argument (the path to filter) passed to 'builtins.filterSource'");
|
"while evaluating the second argument (the path to filter) passed to 'builtins.filterSource'");
|
||||||
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.filterSource");
|
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.filterSource");
|
||||||
|
|
||||||
addPath(state, pos, state.computeBaseName(path), path, args[0], ContentAddressMethod::Raw::NixArchive, std::nullopt, v, context);
|
addPath(state, pos, state.computeBaseName(path, pos), path, args[0], ContentAddressMethod::Raw::NixArchive, std::nullopt, v, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
static RegisterPrimOp primop_filterSource({
|
static RegisterPrimOp primop_filterSource({
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ json printValueAsJSON(EvalState & state, bool strict,
|
||||||
case nPath:
|
case nPath:
|
||||||
if (copyToStore)
|
if (copyToStore)
|
||||||
out = state.store->printStorePath(
|
out = state.store->printStorePath(
|
||||||
state.copyPathToStore(context, v.path()));
|
state.copyPathToStore(context, v.path(), v.determinePos(pos)));
|
||||||
else
|
else
|
||||||
out = v.path().path.abs();
|
out = v.path().path.abs();
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -15,12 +15,12 @@ class PosIdx
|
||||||
private:
|
private:
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
|
||||||
|
public:
|
||||||
explicit PosIdx(uint32_t id)
|
explicit PosIdx(uint32_t id)
|
||||||
: id(id)
|
: id(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
PosIdx()
|
PosIdx()
|
||||||
: id(0)
|
: id(0)
|
||||||
{
|
{
|
||||||
|
|
@ -45,6 +45,11 @@ public:
|
||||||
{
|
{
|
||||||
return std::hash<uint32_t>{}(id);
|
return std::hash<uint32_t>{}(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t get() const
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline PosIdx noPos = {};
|
inline PosIdx noPos = {};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue