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

proposal: cmd/go: allow "go run ." #22726

Closed
broady opened this issue Nov 15, 2017 · 17 comments
Closed

proposal: cmd/go: allow "go run ." #22726

broady opened this issue Nov 15, 2017 · 17 comments
Labels
DevExp anything around developer experience early-in-cycle A change that should be done early in the 3 month dev cycle. FrozenDueToAge Proposal Proposal-Accepted
Milestone

Comments

@broady
Copy link
Member

broady commented Nov 15, 2017

Currently, go run requires Go files as arguments. It's useful for quickly running Go programs, but has been discouraged by many people because dependent packages are not installed. With the changes to build caching in Go 1.10, I propose we simplify usage of go run to encourage more use of it.

A rundown of use cases and how this change would improve the user experience:

  1. Program with one file (e.g., one-off scripts, go generate scripts)

    • go run script.go
    • After: unchanged
    • Improvement: a little more flexibility if it's the only .go file in the directory.
  2. Program with more than one file, with no tests

    • Before: go run *.go
    • After: go run
    • Improvement: minimal
  3. Program with more than one file, where test files are also in the same directory.

    • Before: go run !(*_test).go or go run main.go a.go b.go
    • After: go run
    • Improvement: huge. I had to look up this glob syntax.
  4. Program that accepts arguments

    • Before: go run main.go arg1 arg2
    • After: go run -- arg1 arg2
    • Improvement: same as 1, 2, 3
    • NOTE: to prevent collisions of flags between cmd/go and the user's program, we should probably require the -- separator when filenames are omitted.
  5. Program that accepts Go filenames as arguments

    • Before: go run main.go other.go -- foo.go
    • After: go run -- foo.go
    • Improvement: same as 1, 2, 3
  6. Program with build tags

    • Before: go build -tags -o a && ./a && rm ./a (go run ignores build tags on the files passed in)
    • After: go run -tags foo
    • Improvement: makes what is basically impossible possible. But this isn't a common use case.

Also, perhaps a package path should be allowed as an argument, which would better mirror go build:

go run golang.org/x/tools/cmd/godoc -http=:6060
@broady broady added DevExp anything around developer experience Proposal labels Nov 15, 2017
@broady broady added this to the Proposal milestone Nov 15, 2017
@cespare
Copy link
Contributor

cespare commented Nov 15, 2017

FWIW, I'm one of those people that discourages the use of go run and my reasoning has little to do with caching dependent packages. From what I've seen, when go run is used for multiple .go files or for any of the more complex use cases like the ones you've listed here, it's generally by new Gophers that haven't really internalized how packages work yet. I don't see how an easier-to-use go run is better than go build/go install for these sorts of things.

  • Before: go run script.go -- foo.go
  • After: go run -- foo.go

How does go run know to run script.go in this case, if there are other .go files?

@broady
Copy link
Member Author

broady commented Nov 15, 2017

I don't see how an easier-to-use go run is better than go build/go install for these sorts of things.

go run is already in many ways better than go build/go install for one-off/ad-hoc invocations.
go build is decent, but requires you to clean up the binary after you're done. go install is even worse: the user must understand that the binary ends up in $GOPATH/bin.

How does go run know to run script.go in this case, if there are other .go files?

Use case 5 is when there are no other Go files. If there are other Go files, that's use case 1. Updated script.go to main.go to clarify.

Here's a concrete example that might help you understand my viewpoint:
https://github.com/GoogleCloudPlatform/golang-samples/tree/master/vision/detect

This program is split across two files, and there's also a test file. There's two choices to help people run this program (note that they may not be experienced Go developers, who fully understand how packages, go build, go install all work).

There are a few choices to tell people how to run the program:

  1. go build && ./detect [args] && rm detect
  2. go install && $GOPATH/bin/detect [args] && rm $GOPATH/bin/detect
  3. go run detect.go main.go [args]

As you can see, I chose the third option. It'd be much nicer for this to simply be go run -- [args], I think.

@myitcv
Copy link
Member

myitcv commented Nov 15, 2017

@broady

go install && $GOPATH/bin/detect [args] && rm $GOPATH/bin/detect

The problem here is when GOPATH is a path list; hence you can't rely on $GOPATH/bin/xyz.

I started a thread on golang-nuts with what I think is similar motivation to this issue:

https://groups.google.com/d/msg/golang-nuts/4C_Rd_JJZVU/UdqRePeMBwAJ

@cznic raised some concerns about overloading the run subcommand which I can understand, hence I sort of morphed the suggestion into a new subcommand exec. But then there wasn't much other interest.

As you point out, with the build caching changes in Go 1.10, I would guess that go exec would be even easier to implement/support?

@rsc
Copy link
Contributor

rsc commented Nov 20, 2017

Related:

I'm pretty sure there's old discussion about whether #! should be ignored in code that played into these too but I can't find the ones that related to go run. (I don't think we should ignore #! lines.)

Potential design based on discussion with proposal review:

go run [go flags] [single-package-or-*.go-list] [subprocess flags]

If you specify a package (even "."), then it's clear how to split the two possible flag lists.
If you don't specify a package, we should probably not repeat 'go test's mistake and try to split the flags magically. So then we have to decide whether

go run -flag

means -flag goes to the go command or to the subprocess (the decision should not depend on exactly which flag it is). For consistency with go build etc we should probably make the default be go flags. That seems less surprising. To specify subprocess flags, fill in [single-package-or-*.go-list] with "." meaning the package in the current directory.

Today:

go run x.go -x # go build -o a.out x.go && ./a.out -x
go run x.go hello # go build -o a.out x.go && ./a.out hello
go run x.go -- -x # go build -o a.out x.go && ./a.out -- -x

Maybe tomorrow:

go run # go build -o a.out . && ./a.out
go run -v # go build -v -o a.out . && ./a.out
go run . -v # go build -o a.out . && ./a.out -v
go run -v . -x # go build -v -o a.out . && ./a.out -x
go run -v -- -x # go build -v -o a.out . && ./a.out -- -x
go run cmd/gofmt -help # go build -o a.out cmd/gofmt && ./a.out -help

This would change @broady's 4 and 5 above to use "." instead of "--", but that's much easier to explain ("." is a valid argument to build, test, etc).

@rsc rsc changed the title Proposal: allow "go run" without arguments proposal: cmd/go: allow "go run" without arguments Nov 20, 2017
@rsc
Copy link
Contributor

rsc commented Nov 20, 2017

Actually the default really must be that without a package list the flags are all for the go command. If they were all for the subprocess then there would be ambiguities due to not knowing which of the subprocess flags took arguments. For example if the subprocess took a -x=string flag, then

go run -x=string

would look like not having a package, but you'd think an equivalent command would be:

go run -x string

which would incorrectly look like a go flag followed by a package name.

Defining that the first flags are always go flags avoids this ambiguity.

@rsc
Copy link
Contributor

rsc commented Nov 27, 2017

Based on discussion with proposal-review again this week, accepting proposal as detailed in #22726 (comment). I will take a look at this for Go 1.11.

@rsc rsc modified the milestones: Proposal, Go1.11 Nov 27, 2017
@rsc rsc added early-in-cycle A change that should be done early in the 3 month dev cycle. Proposal-Accepted labels Nov 27, 2017
@broady
Copy link
Member Author

broady commented Nov 28, 2017

Back from vacation. I had done a little more thinking before you posted the comments above, and came to a similar (but more strict) conclusion: that "go run" should require a package name (or list of files) to remove all ambiguity.

So:

go run # error, must provide package name or list of files
go run . # go build -o a.out . && ./a.out
go run -v . # go build -v -o a.out . && ./a.out
go run . -v # go build -o a.out . && ./a.out -v
go run -v . -x # go build -v -o a.out . && ./a.out -x
go run -v . -- -x # go build -v -o a.out . && ./a.out -- -x
go run cmd/gofmt -help # go build -o a.out cmd/gofmt && ./a.out -help

I'm not certain that the gain in precision is worth requiring the argument, and think that the rules you described balance ease of use with precision well enough.

@dlsniper
Copy link
Contributor

dlsniper commented Dec 1, 2017

Imho if we want to simplify this for the newbies then go run should really be removed. The new way of running things go run -- -x vs go run -x will be even more confusing for people, especially for those whom never had to deal with -- or coming from other languages. I understand that this is aimed at the CLI users, but imho it doesn't simplify the problem for new users, it just moves it around.

@broady
Copy link
Member Author

broady commented Dec 1, 2017

@dlsniper please read the most recent comments. The proposal for the -- delimiter was rejected.

@docmerlin
Copy link

docmerlin commented Dec 2, 2017

I like the idea for allowing go run of a directory, broady's proposal for how to handle flags makes sense to me, except the -- is awkward.

@rsc
Copy link
Contributor

rsc commented Jan 23, 2018

It's unclear to me that go run cmd/gofmt should work. Maybe the argument should be limited to be a list of .go files or a directory (. being the common one, but any absolute or relative path is fine), but at least for the start exclude import paths as arguments.

@myitcv
Copy link
Member

myitcv commented Feb 9, 2018

Hi @broady - do you hope to get this in for Go 1.11?

I'm 💯 👍the current proposal.

With the changes to build caching in Go 1.10, I propose we simplify usage of go run to encourage more use of it.

Just to check one point: Go 1.10's caching changes do not appear to extend to go run; so presumably the work relating to this issue would also include extending the caching to the run command?

A very nice side effect of doing so would be that we have fast, reproducible "builds" via go run (we already have the latter to be fair, but with this proposal and caching changes we get the "fast" bit and the ability to specify a package name to go run). My intention is to use go run pkg_name in lieu of go install etc in //go:generate directives. One of the critical bits of this pipeline is that I know when code generator itself has changed (much like the build cache changes it forms the input to a hash that is checked vs a code generation cache). With reproducible "builds" I can take the hash of os.Args[0] in the generator itself as my "version".

@myitcv
Copy link
Member

myitcv commented Feb 26, 2018

In light of @rsc's recent points, to make the perhaps obvious point: having vgo run implement this proposal would seem to be a great fit.

@broady
Copy link
Member Author

broady commented Apr 12, 2018

@myitcv I'm keen to implement this, but not comfortable committing to a timeline. (that is, if someone else wants to do it, please do!)

@rsc is there any conflict here with vgo? The main issue I see is that the implementation should probably be pushed upstream to x/vgo after implementing in master.

@myitcv
Copy link
Member

myitcv commented Apr 16, 2018

@broady 👍

The main issue I see is that the implementation should probably be pushed upstream to x/vgo after implementing in master.

Sounds good.

I suspect @rsc will agree with your suggestion given comments in https://go-review.googlesource.com/c/vgo/+/105855

@gopherbot
Copy link

Change https://golang.org/cl/109341 mentions this issue: cmd/go: add support for 'go run pkg' or 'go run .'

@ManPython
Copy link

What is the problem to do some auto/run .go file by Go in 2xClick on .go file and set in windows registry the related icon to .go files?

@golang golang locked and limited conversation to collaborators Apr 4, 2020
@seankhliao seankhliao changed the title proposal: cmd/go: allow "go run" without arguments proposal: cmd/go: allow "go run ." Nov 22, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
DevExp anything around developer experience early-in-cycle A change that should be done early in the 3 month dev cycle. FrozenDueToAge Proposal Proposal-Accepted
Projects
None yet
Development

No branches or pull requests

8 participants