Fix handling of relative paths

In particular, 'path:..' got turned into 'path:.' because isRelative()
returned a CanonPath, which cannot represent '..'.

Reported by @erikarvstedt.
This commit is contained in:
Eelco Dolstra 2022-10-10 18:56:19 +02:00
parent 7317196807
commit 511590976c
5 changed files with 7 additions and 6 deletions

View file

@ -434,7 +434,7 @@ LockedFlake lockFlake(
if (auto relativePath = input.ref->input.isRelative()) { if (auto relativePath = input.ref->input.isRelative()) {
SourcePath inputSourcePath { SourcePath inputSourcePath {
overridenSourcePath.accessor, overridenSourcePath.accessor,
*overridenSourcePath.path.parent() + *relativePath CanonPath(*relativePath, *overridenSourcePath.path.parent())
}; };
return readFlake(state, *input.ref, *input.ref, *input.ref, inputSourcePath, inputPath); return readFlake(state, *input.ref, *input.ref, *input.ref, inputSourcePath, inputPath);
} else } else

View file

@ -95,7 +95,7 @@ bool Input::isLocked() const
return scheme && scheme->isLocked(*this); return scheme && scheme->isLocked(*this);
} }
std::optional<CanonPath> Input::isRelative() const std::optional<std::string> Input::isRelative() const
{ {
assert(scheme); assert(scheme);
return scheme->isRelative(*this); return scheme->isRelative(*this);

View file

@ -53,7 +53,7 @@ public:
/* Only for relative path flakes, i.e. 'path:./foo', returns the /* Only for relative path flakes, i.e. 'path:./foo', returns the
relative path, i.e. './foo'. */ relative path, i.e. './foo'. */
std::optional<CanonPath> isRelative() const; std::optional<std::string> isRelative() const;
bool operator ==(const Input & other) const; bool operator ==(const Input & other) const;
@ -138,7 +138,7 @@ struct InputScheme
virtual bool isLocked(const Input & input) const virtual bool isLocked(const Input & input) const
{ return false; } { return false; }
virtual std::optional<CanonPath> isRelative(const Input & input) const virtual std::optional<std::string> isRelative(const Input & input) const
{ return std::nullopt; } { return std::nullopt; }
virtual std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const; virtual std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const;

View file

@ -78,13 +78,13 @@ struct PathInputScheme : InputScheme
}; };
} }
std::optional<CanonPath> isRelative(const Input & input) const override std::optional<std::string> isRelative(const Input & input) const override
{ {
auto path = getStrAttr(input.attrs, "path"); auto path = getStrAttr(input.attrs, "path");
if (hasPrefix(path, "/")) if (hasPrefix(path, "/"))
return std::nullopt; return std::nullopt;
else else
return CanonPath(path); return path;
} }
bool isLocked(const Input & input) const override bool isLocked(const Input & input) const override

View file

@ -61,6 +61,7 @@ CanonPath CanonPath::operator + (const CanonPath & x) const
void CanonPath::push(std::string_view c) void CanonPath::push(std::string_view c)
{ {
assert(c.find('/') == c.npos); assert(c.find('/') == c.npos);
assert(c != "." && c != "..");
if (!isRoot()) path += '/'; if (!isRoot()) path += '/';
path += c; path += c;
} }