// HasSubdir reports whether dir is a subdirectory of// (perhaps multiple levels below) root.// If so, HasSubdir sets rel to a slash-separated path that// can be joined to root to produce a path equivalent to dir.// If HasSubdir is nil, Import uses an implementation built on// filepath.EvalSymlinks.HasSubdirfunc(root, dirstring) (relstring, okbool)
What did you expect to see?
Based on the name of the func and the phrase "whether dir is a subdirectory of root", I expected the default implementation (when HasSubdir is nil), which uses filepath.EvalSymlinks, to return false if the directory doesn't exist.
I also asked another person, and that was their understanding of the expected behavior too.
What did you see instead?
After looking into the implementation, I learned that the default implementation (and therefore, all custom implementation that are expected to act in the same way) does not try to ensure that dir is a subdirectory of root.
Instead, it simply reports "whether dir is a path that points to what would be a subdirectory (possibly multiple levels below) of root".
In other words, it does not check that dir is a directory that actually exists. It simply does a lexical path check (also uses filepath.EvalSymlinks to resolve potential symlinks).
This is one of those situations where I'm not completely sure if this is a bug in the implementation, or a case of slightly poor/misleading documentation. Looking more into the history of the relevant code, and the fact that IsDir exists solely to check existence of a directory, I am 80%+ confident the current behavior is correct and this is just a documentation issue.
Update: After spending more time with the code, I am now 97%+ confident the current behavior is correct, and this is just a documentation/naming issue. IsDir exists for checking if a directory exists, so it's not the responsibility of HasSubdir to check that too.
What do other people think about the current phrasing?
I think perhaps it should be clarified that dir does not need to exist for HasSubdir to return true.
Maybe it can be clarified by rewriting it to be something like this (except better)?
// HasSubdir reports whether dir is a path that points to// what would be a subdirectory of (perhaps multiple levels below) root// (but it does not try to check that dir currently exists).// If so, HasSubdir sets rel to a slash-separated path that// can be joined to root to produce a path equivalent to dir.// If HasSubdir is nil, Import uses an implementation built on// filepath.EvalSymlinks.HasSubdirfunc(root, dirstring) (relstring, okbool)
The text was updated successfully, but these errors were encountered:
When calling build.Import, normally, an error is returned if the
directory doesn't exist. However, that didn't happen for local
import paths when build.FindOnly ImportMode was used.
This change fixes that, and adds tests. It also makes the error
value more consistent in all scenarios where it occurs.
When calling build.Import with a local import path, the package
can only exist in a single deterministic directory. That makes
it possible verify that directory exists earlier in the path,
and return a "cannot find package" error if it doesn't.
Previously, this occurred only when build.FindOnly ImportMode
was not set. It occurred quite late, after getting past Found
label, to line that calls ctxt.readDir. Doing so would return
an error like "no such file or directory" when the directory
does not exist.
Updates #17888 (relevant issue I ran into while working on this CL).
Reviewed-by: Ian Lance Taylor <firstname.lastname@example.org>
Run-TryBot: Ian Lance Taylor <email@example.com>
TryBot-Result: Gobot Gobot <firstname.lastname@example.org>