Closed
Description
The UX model for go mod
is to define what the operation is by setting a flag. This is an odd model that I suspect just fell out of the way the go
command already works. But I find it odd, and it mixes mandatory and optional flags together in odd ways.
It will take some rearchitecting but the operations should be specified as subcommands, not flags, like this:
$ go mod init foo.bar/package
Besides being a better match for the usage, this would enable two important changes: First, a help enabler could be added; today we get
$ go mod -help -init
usage: mod [-v] [maintenance flags]
Run 'go help mod' for details.
$
which is no help at all, really, when we could have
$ go mod help init
The init subcommand does this and that and has these flags...
Similarly, by turning these actual commands into syntactic commands, we open up the possibility of having flags on them, with the usual advantages (and disadvantages) and clarity that results.
Metadata
Metadata
Assignees
Labels
Type
Projects
Relationships
Development
No branches or pull requests
Activity
go help mod
should mentiongo help module
#26597rsc commentedon Jul 26, 2018
I agree go mod is not right as it stands. It's too much of a grab bag.
We don't have any sub-sub-commands today, and I don't particularly want to go there. As the new 'go help mod' text (CL pending) points out:
Too many people think everything about modules is 'go mod', to the point of not including 'go get' in tutorials about how to download dependencies. Subcommands won't help avoid that misperception.
But mod should probably be split into a few different commands.
The bulk of the flags do combine nicely. In particular -init, -module, -require, -exclude, -replace, -droprequire, -dropexclude, -dropreplace all work really well together in a single invocation and would work less well if you had to run the go command repeatedly to effect the same list of those changes. I've been thinking there should be a -n that just shows you the resulting go.mod instead of writing it out. Similarly -json prints the go.mod in json form and maybe -n -json should print it without writing go.mod back. All this was meant to keep the promise in #23966 to make go.mod machine parseable (with -json) and editable (with the others). The -fmt and -fix flags fit into that category too.
The abuses begin with -sync, although even that is a natural thing to do after the edits and before committing the modified go.mod to disk as well. But it ends up being a useful operation by itself enough of the time that maybe it should be kept separate. It is unlike the others mentioned so far in that it looks at Go source files.
Then -vendor, which must do most of the work of -sync to decide what to vendor, and then vendor it.
Then -verify, which doesn't actually look at any packages but does consult go.sum and the download caches.
Then -packages, which can probably just be dropped so I won't say more.
Then -graph, which is quite possibly the most important thing here after -sync. It prints the module graph in a simple text form that allows further analysis, andthat data is hard to extract in any other way.
I also have a CL in progress to add a -pgraph to print the module+package import graph so that you can answer "why does go mod -sync keep such and such module around?". That data is possible to extract in other ways, so maybe it's not as important.
If we're going to split up the mod command, probably the editing operations should stick around as 'go mod'. Another possibility is to split out 'go init' and leave the others as 'go mod'. Then you would have
go init my.module/name
which I think you were going for.But then maybe 'go graph' (package graph), 'go graph -m' (module graph), 'go sync', 'go vendor', 'go verify'?
Happy to brainstorm tomorrow.
mvdan commentedon Jul 26, 2018
What about
go tool <name> <args>
? I realise it's a slightly different case, as that runs separate programs, but to the user it still seems like sub-sub-commands.[-]cmd/go: the mod flags should be subcommands[/-][+]cmd/go: mod is too much of a grab bag[/+]robpike commentedon Jul 27, 2018
I don't think there's any design principle at work here that argues against sub-subcommands, and a compelling argument in favor of them is that they make it much easier to provided targeted, per-operation help from the command line. Another is a similar story for flags.
gopherbot commentedon Jul 29, 2018
Change https://golang.org/cl/126655 mentions this issue:
cmd/go: split go mod into multiple subcommands
rajender commentedon Jul 30, 2018
Cross posting here from the CL 126655.
This seems like less seamless integration to me.
Why all these need to go through mod command?
We don't have go package get. We have go get.
It also seems as it is there are too many commands.
Do we really need fix and tidy commands? Looks like
we can make their functionality part of other commands
like get/build.
Do we really need 'mod edit' part of go command?
May be it can be separate tool. I know you have plans
to make mod file reading a separate package. May be this can be
part of it.
go mod edit => remove, go mod edit -fmt can be part of go fmt
go mod fix => remove and make it's functionality implicit
go mod graph => remove and make it part of go list
go mod init => go init
go mod tidy => remove and make it's functionality implicit
go mod vendor => go vendor
go mod verify => go verify
bcmills commentedon Jul 30, 2018
go mod edit
is extremely useful for unit-testing thego
command itself. It could be factored out, but it needs to be a command-line tool: if it is a compiled-in library, then what happens if thego
command is updated to support a directive that the library doesn't know about?go mod init
is similarly useful as a standalone tool: it makes use of contextual information to infer the module path and applies conversions to existing lock files, so we don't want things that use it to bake in one specific set of functionality.go mod tidy
needs to be an explicit and separate command: the operations it performs (chasing down transitive dependencies with exotic build tags) can be expensive.However,
go mod fix
could perhaps be folded intogo mod tidy
(asgo mod tidy -m
).I agree that
go mod graph
should probably be ago list
flag.I disagree that
go mod vendor
should be a top-level command, as it is already kind of a niche use-case. I think it would work reasonably well as ago get
flag, such asgo get -d=vendor
:go get
already has the job of downloading source code, which is also more-or-less whatgo mod vendor
does.I suspect that
go mod verify
would fit reasonably as a flag ongo list
orgo get
(perhapsgo get -d=verify
or just a normal part ofgo get -d
).kostix commentedon Jul 31, 2018
@bcmills, let me disagree on your
point.
I'm pretty much confident that teams which already make heavy use of vendoring will unlikely be moving away to "the next thing" (borderline package proxies?) anytime soon: there will just not be enough justification to fix what is not broken.
Vendoring solves very real issues in a pretty effective way, and the simplicity of this approach—basically you do not need to deploy and maintain anything "extra" to make it work—is a reasonable selling point of vendoring.
So please do not discount it easily.