-
Notifications
You must be signed in to change notification settings - Fork 1k
dep, internal/gps: Always return an error from Analyzer.DeriveManifestAndLock #595
Conversation
…tAndLock Analyzer.DeriveManifestAndLock returned a nil error when passed a non existant file path. This is rather unidiomatic. Instead, return the error to gps.getManifestAndLock and adjust it to handle this case explicity.
The dep analyzer wasn't passed a non-existent path though. It was given the path to a dependency, and the analyzer checks if it had dep configuration that should be taken into account when solving. |
@carolynvs IsRegular returns |
@@ -47,6 +47,10 @@ func (bs *baseVCSSource) getManifestAndLock(ctx context.Context, pr ProjectRoot, | |||
} | |||
|
|||
m, l, err := an.DeriveManifestAndLock(bs.repo.LocalPath(), pr) | |||
if os.IsNotExist(err) { | |||
return prepManifest(nil), nil, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is essentially guaranteed to be unreachable by a slew of code above it - we shouldn't be able to make it this far if the dir doesn't exist. It should only be reachable under active sabotage (or, ofc, a bug) - e.g., some other process removing the dir within the source cache while a dep
command is running.
Even under such circumstances, it's relatively unlikely this would be the spot that happens to first notice the dir is absent. If it is, though, it's preferable to error out, rather than pass up the "zero" result, as non-error results get cached. If/when that cache becomes persistent across runs (#431), that incorrect information could plague future runs.
So, better to just propagate the error right back out than try to recover.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sdboyer if I remove the special case for os.IsNotExist
then a slew of tests fail in cmd/dep.
http://paste.ubuntu.com/24590545/
I wonder if something is messed up with the logic that lets this path get through to this point. Or maybe the test fixtures are broken?
OH. sorry, i misread the change - I thought this was dealing with the case where the parent dir doesn't exist - not where The logic here is correct as-is. The purpose of |
@sdboyer yup, this change does not change the logic here. It just moves the special handling of IsNotExist up to the caller so gps/Analyzer.DeriveManifestAndLock returns an error rather than relying on a convention of returning nil, nil, nil. |
It doesn't change the outcome, but it violates the intention of the interface. It's not an error condition of gps' internals have no idea how the manifest and lock data are being loaded by the analyzer; this change would remove that abstraction. It's probably reading files from disk, but maybe it's making calls into a database. Maybe it's reading multiple files on disk. Maybe it's searching for files from multiple different tools. Point is, gps doesn't know or care; if it gets back an error from Now, I can certainly see this needing to be a docs improvement, as none of this is written out on the |
Fair enough. Thanks.
…On Wed, 17 May 2017, 13:27 sam boyer ***@***.***> wrote:
It doesn't change the outcome, but it violates the intention of the
interface. It's not an error condition of DeriveManifestAndLock() to not
find any of the files it may want to look for, and thus it should not
return an error.
gps' internals have no idea how the manifest and lock data are being
loaded by the analyzer; this change would remove that abstraction. It's
probably reading files from disk, but maybe it's making calls into a
database. Maybe it's reading multiple files on disk. Maybe it's searching
for files from multiple different tools. Point is, gps doesn't know or
care; if it gets back an error from DeriveManifestAndLock(), the analyzer
is saying that version is *unusable*.
Now, I can certainly see this needing to be a docs improvement, as none of
this is written out on the ProjectAnalyzer.DeriveManifestAndLock() docs 😄
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#595 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAcA9Rro2lGC_3Y5HTyThCxh3NwkGJ9ks5r6mkNgaJpZM4NdSXx>
.
|
But at the risk of wearing out my welcome. A method that returns a nil
error AND nil values is very unusual in Go.
…On Wed, 17 May 2017, 13:27 Dave Cheney ***@***.***> wrote:
Fair enough. Thanks.
On Wed, 17 May 2017, 13:27 sam boyer ***@***.***> wrote:
> It doesn't change the outcome, but it violates the intention of the
> interface. It's not an error condition of DeriveManifestAndLock() to not
> find any of the files it may want to look for, and thus it should not
> return an error.
>
> gps' internals have no idea how the manifest and lock data are being
> loaded by the analyzer; this change would remove that abstraction. It's
> probably reading files from disk, but maybe it's making calls into a
> database. Maybe it's reading multiple files on disk. Maybe it's searching
> for files from multiple different tools. Point is, gps doesn't know or
> care; if it gets back an error from DeriveManifestAndLock(), the
> analyzer is saying that version is *unusable*.
>
> Now, I can certainly see this needing to be a docs improvement, as none
> of this is written out on the ProjectAnalyzer.DeriveManifestAndLock()
> docs 😄
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <#595 (comment)>, or mute
> the thread
> <https://github.com/notifications/unsubscribe-auth/AAAcA9Rro2lGC_3Y5HTyThCxh3NwkGJ9ks5r6mkNgaJpZM4NdSXx>
> .
>
|
No problem - if there's a way of expressing these same semantics that's more idiomatic, I'd be happy to change it (and would welcome the learning opportunity). Just so long as the separation of concerns is maintained 😄 |
Pursuant to discussion in #595.
I believe that is what this change does. It uses an error which passes
through os.IsNotFound to indicate -- the path you asked me to open wasn't
there -- which the single caller inside gps knows how to handle.
…On Wed, 17 May 2017, 13:34 sam boyer ***@***.***> wrote:
No problem - if there's a way of expressing these same semantics that's
more idiomatic, I'd be happy to change it (and would welcome the learning
opportunity). Just so long as the separation of concerns is maintained 😄
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#595 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAAcA6twYjjrC5KURWz6UHkZOpyTHyaFks5r6mqtgaJpZM4NdSXx>
.
|
gps didn't ask it to open |
Right, but if you call a method that returns an error value then the rule
is; if error is not nil, then none of the other values are valid -- they
have no value, not even nil, you cannot touch them.
At the moment DeriveManifestAndLock returns nil, nil, nil if dep.IsRegular
returns false, nil. The comment at
https://github.com/golang/dep/blob/master/analyzer.go#L21 specifically says
that nil is returned on error.
This leads to the situation where the implementation of DeriveManifestAndLock
create https://github.com/golang/dep/blob/master/cmd/dep/init.go#L164 and
https://github.com/golang/dep/blob/master/cmd/dep/status.go#L257 return the
unusual nil, nil, nil when passed an invalid path.
This logic is componded by
https://github.com/golang/dep/blob/master/internal/gps/manifest.go#L148
which returns a SimpleManifest if prepManifest is passed a nil manifest,
which it will be in the case that the path passed to DeriveManifestAndLock
was not valid.
This PR does not change this logic, it just makes it more explicit by
handling the special case of "not found means trigger the logic in
prepManifest" closer to where it occurs.
…On Wed, May 17, 2017 at 1:42 PM, sam boyer ***@***.***> wrote:
gps didn't ask it to open Gopkg.toml, though - that's dep's
implementation detail. It only provided the parent directory in which such
a file might live. And that directory is present.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#595 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AY8dpmy8C1mptLFDRmS9xgPrI1O2c0Anks5r6myVgaJpZM4NdSXx>
.
|
What I meant to say, but hit send to quickly was, in the opposite case where error is nil, the other values are usually assumed to be value -- ie, not nil. But this is not the case here. |
Ah, this is an interesting point. Though I think it actually works against what you're going for - if an invalid path is passed - so, the parent directory, not one of the files - then Also, while we don't support it now - it's also valid to return only lock data, but no manifest. (If we were to do on-the-fly conversion from
Again, the important question here is what "validity" means. The only way the input is invalid is if it's a path that doesn't exist/isn't a dir/etc. We're basically discussing what the meaning of a nonexistent
|
Analyzer.DeriveManifestAndLock returns a nil error when passed a non existent path. This is rather unidiomatic.
Instead, return the error to gps.getManifestAndLock and adjust it to handle this case explicitly.