-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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: allow go.mod.local to contain replace/exclude lines #26640
Comments
Could you clarify what is the purpose of separating the data into two files? So that developers don't commit temporary replace directives by mistake? I'd imagine that there could be tooling to help with that. For example, a tool to add and undo temporary directives, or having CI fail on unexpected replace directives. I'm also worried about adding more special Go module files, even if they are in theory not to be committed into git. |
It's dangerous as you can commit files that use something else than what said in go.mod. |
We certainly do need to address that use-case somehow, but splitting up the module definitions doesn't seem like an appropriate solution: ideally I don't want individual developers to have to edit the module definition to do that. |
I fall into the use case of "building multiple packages concurrently" as well.
I believe that the first option is the best, but I'm interested in reading what direction you guys are learning toward in the interim. |
Hi all, I'm not sure that my approach will help others, but in case it does, (taken from go-nuts) There is a bare bones workaround without local go.mod nor replacements. Suppose you need to work on module A and module B simultaneously (hopefully you set things up to avoid this, but hey, it's inevitable) If you only need to edit one package at a time in at least one of A and B, then you don't need Let B be the module which has only one package to edit, and p the package. Copy p somewhere in A, rename import path to p using existing go imports/ide, In terms of commands and tools, it's very simple: no tools, no replacements, no go.mod.local, no replacements which shouldn't be pushed/commited, no workflow restrictions. Simple "cp -r" and use with editor that understands go imports works fine. Now, thanks to modules, if your edits correspond to releases, it doesn't even matter in what order Yes, it's still a PITA. For me it's much less painful than thinking about workflows and replacements. That said, I do think it would be nice to have the go command do for a set of modules, say go build ./... |
bcmills> "ideally I don't want individual developers to have to edit the module definition to do that." Pondering on how to "merge" I know that knobs breeding is unpopular among core team but consider it, please. |
go.mod.local or similar would also help our use case. We have developers working on service 'A' which relies on library 'B'. Our developers will make changes to both the service and the library and so have a The problem is that each developer will have checked the library out onto their filesystem with a different path so each of them need a different path in the 'replace' statement, meaning version control of go.mod is messy. |
Local dependency is useful when importing from a self-hosted system which does not support go-get(e.g. GitHub Enterprise). |
+1 to go.mod.local or just a separate file based approach. It would provide a clean logical separation and file based will be simple to ignore via .gitignore. Also overriding the mod file location (aka opt-in) during development would provide a sanity check in mitigating the risk of pushing to production. |
We’re using GitHub Enterprise which works for us. What specific issues are you having? |
I was pointed here by @bcmills on slack. Thought it was worth mentioning my use case since I can't see it obviously stated here. I want to be able to do a I have found myself a few times wanting a replace directive without contaminating the |
Not everyone can see that link; if it's important, please copy any context needed into this discussion. |
@SamWhited, the discussion on Slack was literally just a link to this issue. |
An implementation I think could come in handy would be to look up on every parent directory for a |
With GO111MODULE defaulting to on by default in 1.16, it would be nice to address this issue somehow. For clarity, the key problem problem most developers seem to be observing is not the lack of an additional mod file, but the fact there's no way to experiment with changes in local dependencies (for debugging, for example) without hacking on files that need to be skipped on every commit. An additional overriding file that could be ignored would be one way to address it, but it has the disadvantage of being silent about it. Ideally the final solution will make it visible that there are local overrides active during operation. While this issue isn't sorted out upstream, developers may be interested in the
Some git aliases can make this a bit more convenient to use:
This also has the disadvantage of being silent during operation. That's relatively easy to fix by automatically decorating commit messages to remind that go.mod is dirty. |
I recently proposed #44660 with exactly the same issue in mind - I frequently need to use go.mod directives to fiddle with non-VCS packages (or newer code in local than in VCS) but NOT have them in the Someone pointed me at this proposal which has a lot of discussion on it so I decided to close my proposal and add my suggestion here - to reduce the amount of 'duplicate' issues. Suggestion: |
@sabutterworth so you're suggesting that even when I explicitly specify a .mod file by using |
This is common in bootstrap and debug phase.
For experiments go.mod should not be consulted at all. Just we need to tell compiler where our experimental code is. Then - after fiddling there - we may commit and publish new or fixed interdependent modules. |
FYI, in Haskell ecosystem, library authors tend to like Cabal, while application authors tend to like Stack; There is Seems Go doesn't suffer from a split like cabal/stack wrt build tooling, but I kinda feel a similarity that GOPATH leans toward library authors (tend to develop multiple inter-related or even lock-step projects concurrently), while vending/go.mod leans toward application authors (focus on a single So I think Personally I like #44347 |
My impression is the opposite: I think most library authors are using modules at this point, because modules make it easier for their downstream consumers to resolve and manage transitive dependencies, and libraries already have unique import paths (generally beginning with the domain name hosting the library). I think the majority of |
Sure that's the case, private apps are not on my mind previously, I agree they'll have to mass refactoring their import paths for the migration. For typical library authors, I assume one would split functionality toward finer grained lib projects, but he must have some motivating use cases to be prototyped and tested with all those libs, or further plus one or more apps involved. Suppose each lib and each app goes as a separate When you are planning several libs altogether, or to add major, inter-related features affecting multiple libs, they need to be prototyped & tested with WIP branches. Temporarily placing local |
Placing this issue in context with Russ's well-written plea here: #37755 (comment) Yes, go modules are obviously superior to GOPATH. They enable reproducible builds. They allow different components to depend on different versions of the same third-party repository. They solve all the security problems recently highlighted with pip, in triplicate. However, at engineering companies of a certain size, you’ve already had to solve these problems. And, furthermore, you’ve had to solve them for a variety of languages, so your solution is cross-language. Existing processes and tools are defined in terms of this meta-builder, so institutional inertia requires compatibility. It also allows dependencies on specific go and protoc versions. At $dayjob, we have a custom Make-based framework, for Google I’m guessing Bazel / Blaze fills that role, and for a project like Debian its the control files and auto builder network. If you already have such a system, integrating it with GOPATH is easy, just ask that system to form a valid GOPATH with the correct versions in place everywhere (as Debian does). With go modules, it's much, much harder. The official answer as I understand it is to call directly in to go tool compile and go tool link. However, bypassing the high-level go build command means you may need to reimplement editor and tool integrations, which is a very high bar. Even at a conceptual level its hard because now both the go compiler and the overarching tool want to control how dependencies are fulfilled. I haven’t seen a clear story on how to integrate go modules into such a system. I think some participants in this thread (myself included) are attempting to recreate their previous GOPATH workflows using the replace directive. For this use case, the -modfile flag (perhaps encoded in GOFLAGS) is nice, but is still difficult to work with because you need to create an override file for each dependency you pull in to the "workspace", and regardless of whether you pass the -modfile argument as a relative or absolute path it is difficult to select the correct modfile based on the the directory a command is being run in. I believe this is why there is interest in having a single file that defines a "workspace", which overrides the module discovery process for all checked-out modules within it. |
I just realized that Go uses the term "package" for directory of source files, while in more general software engineering context, "package" as in "Package Manager", "Pip - the Package Installer for Python" and etc. refers to something bigger than "module". So now Go has the relative size of "package" and "module" flipped, this will likely to confuse even exclusive Go developers if unaware, for they are likely, e.g. to work with "apt - Advanced Package Tool" day-to-day in using their servers, workstations or laptops. We need to start talking about the concept for the thing bigger than "package" or "Go module" in tooling related issues, currently the data model of Go tooling wrt source project structure lacks a layer of project workspace, so maybe the term "project" or "workspace" or my personal idea "go.farm" will do, just don't stop at Update: cross link #27542 (comment) |
Hi @complyue @gilgad13, You might be interested in #26640 (comment), which is a sketch from a while ago of how a go.workspace or go.space could work to allow working multiple modules simultaneously without needing to do anything manually regarding One question that came up in a prior discussion of that sketch is how would a release happen, including to check if a given module still builds and passes tests using the published versions of the modules in the local workspace. One approach would be to use |
@thepudds I confess I missed your posts (as well as many others') by not thoroughly reading all the discussions, a shame but I don't have too much time/energy available on Go stuff as time being. And I'm glad to know you already sketched the idea and many have discussed about it. With respect to the release concern, I'm no expert at it, but AFAICT, similar concerns had driven a gang of Haskellers to have created Stackage, it recruit curators to work on nightly snapshots of the central registry/repository of Haskell packages (https://hackage.haskell.org), making sure all packages are vetted (compiles, passing test suites, etc.) then regularly release such snapshots as LTS Haskell. Stackage Curators are great people and smart CI tools making all that happen. Back to the release concern we talk about here, I do think it's okay if all modules in a local |
I too have come across this problem, it would be lovely to have go.space for local development! For the time being, couldn't a solution be some sort of bash script which could append the replace directives from another file to the go.mod before building the project in the local development environment? |
I hope this isn't considered off topic, but isn't library development supposed to make as few assumptions about how it's being used as possible, and allow as much flexibility as possible? I haven't been in a situation where I would want to do a replace to a local version of a library for app development. If my app has a feature that seems to fit with the library, usually that starts as just native app code, and migrates to that of library code. A migration though is copy/paste/refactor for flexibility as needed, and then publish (with tag). Following the completion of the lib work, I could rip out the functionality from the app, and point it to the lib. I guess I'd like to understand why folks are doing this kind of "replace" so often that there's this active proposal. It seems that such a workflow is because of tight coupling, and may be a design anti-pattern, and thus should not be encouraged? |
I've reach out to the Kompose project, which is currently "stuck" on 1.13 because of these questions. I certainly don't know the answer. It seems people everywhere are writing off |
After you've published the lib, when someone find the needs to improve/fix-bugs, how can they work on it without "locally-replace" the published version of your code? |
Fix bugs in the library? Pull down the library, write a test that demonstrates the bug, update the implementation, push, tag. |
How is this now different to go.work? Does that solve this issue? |
So every verification test would need a commit (even tag every one?) tripping around the repository, no? |
Personally, I think go.work (#45713) is a better solution to the problems go.mod.local is trying to solve. FWIW, I wrote a comment above early on here in Also, the write up at #45713 includes a short comparison to go.mod.local:
|
I believe we can close this now that workspaces should be widely available |
Hi everyone,
I'm actually using a go.mod file for dependencies in my go project.
I saw that there is a way to use local packages instead of online repo, using the replace() features, which is really cool when developping multiple packages at the same time.
I was wondering if there is a way split in different files the require dependencies and the replace one. Something like that
go_replace.mod => define the replace part.
go.mod => define the module and the required dep, including the go_replace.mod.
the go_replace.mod will not be pushed on git, and each developer will create it if needed.
What version of Go are you using (
go version
)?go version go1.11beta2 windows/amd64
Thanks a lot!
@rsc
The text was updated successfully, but these errors were encountered: