Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: add go get -printdir #18119

Closed
bradfitz opened this issue Nov 30, 2016 · 29 comments
Closed

cmd/go: add go get -printdir #18119

bradfitz opened this issue Nov 30, 2016 · 29 comments
Labels
FrozenDueToAge GoCommand cmd/go help wanted Proposal-Accepted WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Milestone

Comments

@bradfitz
Copy link
Contributor

I'd like a succinct and portable way to get the first element of the user's GOPATH.

Currently:

$ GOPATH=/foo:/bar go env GOPATH
/foo:/bar

Obviously we can't change that.

I propose a -1 flag to go env to only print the first GOPATH element, using https://golang.org/pkg/path/filepath/#SplitList

$ GOPATH=/foo:/bar go env -1 GOPATH
/foo
@bradfitz bradfitz added this to the Proposal milestone Nov 30, 2016
@rsc
Copy link
Contributor

rsc commented Nov 30, 2016

Is there a good reason for it other than explanatory docs? We've always written cd $GOPATH before without worrying about this. Most people don't know it's a list or don't care. There's also very few times I can think of when you definitively want the first GOPATH entry. Usually you want the source for a particular package, which is

cd $(go list -f '{{.Dir}}' my/pkg/import/path)

@bradfitz
Copy link
Contributor Author

bradfitz commented Nov 30, 2016

I often seen docs where people include $GOPATH in bash scripts exactly in ways where it would fail if my GOPATH actually were a list, encouraging people to not make it a list.

I'd like there to be some official answer people could use in docs instead.

$(go list -f '{{.Dir}}' my/pkg/import/path) doesn't work if the directory doesn't yet exist, and it's often mkdir -p $GOPATH/src/github.com/org/private-repo I see in docs, before a git clone into that location.

@rsc
Copy link
Contributor

rsc commented Nov 30, 2016

Maybe this can wait for Go 1.9?

@bradfitz
Copy link
Contributor Author

Indeed. I didn't intend it for Go 1.8.

@rsc
Copy link
Contributor

rsc commented Dec 5, 2016

In general it would be good to express the question we want answered instead of the mechanism. In this case we want to know where a particular package will be installed, without really caring about the fact that GOPATH is how we get there.

Maybe go get -dir import/path prints the directory where go get would put import/path after downloading it (even if it doesn't exist, no network activity, and so on). But "get -dir" is probably suggestive of an operation that's not actually happening as just defined. Better names?

@rsc
Copy link
Contributor

rsc commented Dec 5, 2016

Other possibilities: -where, -printdir, ....

@josharian
Copy link
Contributor

Another possibility is accept a format string. Then this feature could also be used to learn the VCS system that go get would use, the remote url, the destination on disk, the clone command, whether it is a custom import path, etc.

I currently maintain a modified fork of cmd/go just for doing this kind of import path resolution. @rogpeppe does too; see https://go-review.googlesource.com/8725.

@bradfitz
Copy link
Contributor Author

bradfitz commented Dec 12, 2016

$ DIR=$(go get -printdir github.com/org-may-not-exist)
$ echo "Installing to $DIR ..."
Installing to /home/foo/go/github.com/org-may-not-exist ...
$ mkdir -p $DIR && cd $DIR && git clone http://foo/proj.git

@rsc
Copy link
Contributor

rsc commented Dec 12, 2016

OK, so -printdir never does anything but only prints the absolute path of the directory where 'go get' would check out the named package, or where one is already checked out that 'go get -u' would update.

If there are no arguments (packages on command line), then that's an error. There must be at least one. If there are multiple arguments, it prints one line for each.

Must print to standard output.

@rsc rsc changed the title proposal: cmd/go: add -1 flag to go env proposal: cmd/go: add go get -printdir Dec 12, 2016
@rsc rsc changed the title proposal: cmd/go: add go get -printdir cmd/go: add go get -printdir Dec 12, 2016
@rsc rsc modified the milestones: Go1.9Early, Proposal Dec 12, 2016
@bradfitz bradfitz self-assigned this Dec 12, 2016
@josharian
Copy link
Contributor

@bradfitz in your example, go get github.com/org-may-not-exist would fail, not check out a named package, because go get for github requires both an org/user and a repo name. And it can't just using the first arg verbatim (attached to $GOPATH) because that would disagree with 'go get' on custom import paths. At which point you're going through cmd/go's repoRootForImportPath anyway, so we may as well also provide access to the other things it returns--clone url, vcs, isCustom, probably by way of a format string. (Pretty please?)

@bradfitz
Copy link
Contributor Author

The idea was this would be done purely lexically. It would not hit the network or attempt to parse the arguments in any way (including using repoRootForImportPath)

@josharian
Copy link
Contributor

Ok, but to be super clear, then, it is definitely not true that:

-printdir [...] prints the absolute path of the directory where 'go get' would check out the named package, or where one is already checked out that 'go get -u' would update.

@bradfitz
Copy link
Contributor Author

"would attempt to check out" ?

Are you just saying we're missing the words "attempt to" or "try to"?

@josharian
Copy link
Contributor

I guess? In the case of github.com/foo, 'go get' will always fail, it would never attempt anything. But I guess its something like that. Here are more questions. (None of which are to say this is a bad idea. Just probing edge cases.)

What would go get -printdir rsc.io/pdf/... print? The ... reproduced verbatim? Would go get -printdir context print something in $GOROOT or something in the first $GOPATH?

To handle the the "would update" case, does -printdir check to see whether any GOPATH dir contains code, or does it always just return the subdir of the first $GOPATH dir?

@josharian
Copy link
Contributor

As an aside, for the specific mkdir -p && cd && git clone sequence above, you don't need the intermediate dirs to exist. git clone url dest will do a mkdir -p dest for you and put the code in the right place. If that's the primary use case, maybe we don't need github.com/does-not-exist to work?

@bradfitz
Copy link
Contributor Author

Verbatim verbatim.

The code would literally be:

    first := filepath.SplitList(goroot)[0]
    for _, arg := range args {
           fmt.Println(filepath.Join(first, arg))
    }

@rsc
Copy link
Contributor

rsc commented Dec 13, 2016

No, that's the wrong implementation. The whole point of going down this 'go get -printdir' path was because the answer varies by import path. If the target already exists in a later entry in GOPATH, go get will use that one. Josh is right that you really need to give it the actual package you care about. The script is wrong. It should be:

$ DIR=$(go get -printdir github.com/org-may-not-exist/proj)
$ echo "Installing to $DIR ..."
Installing to /home/foo/go/github.com/org-may-not-exist/proj ...
$ mkdir -p $DIR && cd $DIR && git clone http://foo/proj.git .

(note dot at end of final command)

@bradfitz
Copy link
Contributor Author

If the target already exists in a later entry in GOPATH, go get will use that one.

Ah, okay. You can tell how often I use multiple entries in my $GOPATH.

@jimmyfrasche
Copy link
Member

What about a separate command, go dir. (The suggested semantics below apply to a -printdir flag as well but it being on go get seems weird to me, since it never gets anything)

Given no arguments it prints the elements of $GOPATH, one per line (or the default if not set).

Given arguments it assumes they're packages and prints their absolute paths (including /src/), one per line. Failing if any do not exist. This also would allow it work with /... or any of the special names.

If you only care about the first pipe through head -n 1 or sed 1q. You can redirect to /dev/null if you just want to check the exit code. If it's a separate command these could be flags on the command, though there's no need for them on unixy systems, at least.

That seems like it would cover all the cases for shell scripting. The only problem would be something like go dir $EMPTY_VAR, but if it's a separate command no args could be an error and go dir -gopath could print $GOPATH.

@rsc
Copy link
Contributor

rsc commented Dec 13, 2016

Honestly, I think this is a non-issue and we should do nothing at all. But I would argue strongly against any command that exposes what GOPATH is directly. Obviously code that cares can find out. But that's almost always the wrong question to be asking. The appropriate question is "where is the code for this particular import path?"

The reason this is on 'go get' is that if you've already got the code you can use 'go list -f whatever-you-need'. The one case that doesn't handle is where the code is yet to be downloaded, and 'go get -printdir' will tell you where it would put the code after the download.

@myitcv
Copy link
Member

myitcv commented Dec 14, 2016

The one question I often find myself trying to reliably answer with multiple entries in my GOPATH is where go install github.com/my/pkg will install to, so that I can then definitely run the binary (in this case pkg) that is (re-)built, irrespective of the user's PATH. Seems somewhat related (unless I'm missing an obvious solution of course?)

@bradfitz
Copy link
Contributor Author

@myitcv, there's already an answer for that question:

$ go list -f {{.Target}} golang.org/x/build/cmd/coordinator
/home/bradfitz/bin/coordinator

This bug is about a question for which there's no current way to extract an answer.

@myitcv
Copy link
Member

myitcv commented Dec 14, 2016

@bradfitz thanks, and apologies for the noise.

@gopherbot
Copy link

CL https://golang.org/cl/48410 mentions this issue.

@bradfitz
Copy link
Contributor Author

@rsc, could you review https://golang.org/cl/48410 ?

@bradfitz bradfitz modified the milestones: Go1.10, Unplanned Nov 21, 2017
@bradfitz
Copy link
Contributor Author

@rsc said on the CL:

If possible I'd like to hold off introducing this flag. I understand the desire but package management may potentially invalidate things like this. At this point I'd rather wait on any new features until we're sure that they will make sense in the new world.

@bcmills
Copy link
Contributor

bcmills commented Jan 18, 2019

Is this still an issue, particularly given module mode and go list -e?

@agnivade
Copy link
Contributor

ping @rsc

@agnivade agnivade added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Feb 22, 2019
@gopherbot
Copy link

Timed out in state WaitingForInfo. Closing.

(I am just a bot, though. Please speak up if this is a mistake or you have the requested information.)

@golang golang locked and limited conversation to collaborators Mar 21, 2020
@rsc rsc removed their assignment Jun 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge GoCommand cmd/go help wanted Proposal-Accepted WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

8 participants