Hi all,

This thread is hitting on a fairly important set of topics.

It certainly seems some additional brainstorming and community discussion 
about how things could or should work regarding multi-module workspaces 
would be beneficial.

A file tree with a `go.mod` has been described as something like "a little 
GOPATH", but as has been observed, if you want to edit multiple modules 
simultaneously, you have to decide how you want to wire together those 
multiple "little GOPATHs".

Manually adding `replace` directives is one approach to using local copies 
of related modules that you might be simultaneously editing.

However, that can translate to many manual steps, especially if they are 
frequently added and removed.

If you haven't already, it is definitely worthwhile to look at 
https://github.com/rogpeppe/gohack, which is a new community tool to 
automate and greatly simplify multi-module workflows and related `replace` 
directive workflows. It allows you to very easily modify one of your 
dependencies. For example, `gohack github.com/some/dependency` 
automatically clones the appropriate repository to your local disk and adds 
the necessary `replace` directives to your go.mod so that your build picks 
up the local copy that you can start editing. You could do this as part of 
a one-off investigatory workflow, or you could do `gohack example.com/foo  
example.com/bar  example.com/baz` as part of your normal development setup 
if that makes sense for your workflow. When done, `gohack -u` removes all 
gohack replace statements (which can be done prior to committing).

A related note is that community-based tooling for modules in general is 
starting to emerge. You can see an initial list here:
  
  
https://github.com/golang/go/wiki/Modules#what-community-tooling-exists-for-working-with-modules
  
Overall, it seems clear one of the intents of the modules system is to 
enable one-off or community-based tooling to be built on top of the core 
modules functionality, and often it can be done in a relatively 
straightforward manner. For example, there is whole section of the official 
documentation titled "Edit go.mod from tools or scripts" 
(https://tip.golang.org/cmd/go/#hdr-Edit_go_mod_from_tools_or_scripts).

Some example capabilities for inspecting module configuration (which might 
be used to encode a sanity check, or to automate further tooling):

  *  `go mod edit -json` outputs the current module's `go.mod` file in JSON 
format.

  *  `go mod edit -json <path/to/go.mod>` outputs a particular `go.mod` 
file in JSON format.

  *  `go list -m -json all` gives a JSON representation for the full set of 
modules available to a build, including the path to each `go.mod` file. 
(You can then feed each `go.mod` path to `go mod edit -json 
<path/to/go.mod>` to get the additional details for that `go.mod`).

Some example capabilities for programmatically editing module configuration 
(which for example could support automating adding/removing `replace` 
directives to wire together multiple related modules for simultaneous 
editing of multiple modules):

  *  `go mod edit -replace github.com/my/foo=../foo` adds a `replace` 
statement to use a copy of `foo` on the local disk.

  *  `go mod edit -dropreplace=github.com/my/foo` removes all replacements 
for `foo` from the current `go.mod`.

One of the concerns raised in this thread is that if you use a `replace` 
directive to point a module to a development copy of another module, 
someone might accidentally check that the `go.mod` containing the `replace` 
directive. 

To help guard against that (and as a simple example of one-off tooling that 
could be built on top of 1.11 modules), you could consider some type of 
pre-commit VCS check or CI check to validate that a go.mod does not have 
any development replace directives, such as something along the lines of:
    go mod edit -json | python2.7 -c 'import json, sys; assert 
json.load(sys.stdin)["Replace"] == None'
(Sorry for slipping in a python one-liner; that was just to convey a 
simplified example. Obviously could instead be in Go, bash, jq, or whatever 
your preferred method might be).

There are admittedly many different opinions on how to use git, but another 
approach to add and remove development-specific `replace` directives could 
be via something like the git smudge/clean workflow that lets you tweak 
things on checkout (e.g., add `replace` directives) but then automatically 
reverse the tweak when checking back in (to strip out development `replace` 
directives). Or perhaps something similar could be automated however might 
work best for your current workflows...

A completely different approach could be to make the on-disk organization 
of your multiple modules always be the same in their 
development/environment/test/build/CI environment, and wire that together 
via replace directives that you do check in (in contrast to adding and 
removing replace directives for specifically for development). That is not 
something that would work for all projects, but perhaps something to 
consider. A small number of modules could be manually wired together like 
that via a one-time hand edit of the various `go.mod` files, or the actual 
edits to the `go.mod` files could be automated if there are many modules 
that would need to be touched. 

Overall, and setting aside any particular solution -- there are probably a 
few different timescales to think about regarding the topic of this thread 
and how multi-module workspaces should be set up:

  1. What do people do immediately? (For example, based on manual 
workflows, or via small amounts of automation on top of 1.11 modules).

  2. What might be done in community tools like `gohack` on top of 1.11? 
(For example, hopefully people can contribute ideas or pull requests to 
`gohack` or other existing efforts, or perhaps some people might start 
their own experimental module tooling repo, which might help flesh out a 
few different independent perspectives).

  3. How could and should this all work in a 1.12 time frame?

Part of the nature of the current on-going modules experiment is such that 
hopefully that near-term experience and community experimentation will help 
shape what happens in a 1.12 time frame. 
   
Stepping backing even further, though -- when it comes to multi-module 
projects, one key initial question to ask is how many modules do you want 
to create for a given project, including asking yourself what do you really 
need to version separately (given modules are defined as "the unit of 
source code interchange and versioning"). Especially to start as people 
ramp up on modules and as the community is working out different workflows, 
larger modules are likely easier than finer-grained modules, and one module 
per repo is definitely easier than multiple modules per repo. The official 
modules proposal is predicting "most projects will adopt a workflow in 
which a version-control repository corresponds exactly to a single module" 
(from https://golang.org/design/24301-versioned-go). That said, different 
people will have different preferences.

Sorry for the long-ish comments, but I guess my broadest point would be 
that the topics raised in this thread do seem worthy of some thinking and 
discussion by the overall community...

--thepudds


On Monday, September 3, 2018 at 8:11:13 AM UTC-4, kortschak wrote:
>
> And here we have the problem. Low probability of error events do not 
> scale. 
>
> On Fri, 2018-08-31 at 19:30 -0700, Jim wrote: 
> > Changes from the master/development go.mod will need to be carefully 
> > merged  
> > into release go.mod. 
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to