-
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
proposal: cmd/go: module aliases #70443
Comments
Another approach might be to extend the import path support we already have (see |
related: #26904 but with a replacement pushed up from the dependency. Since the main module needs a new enough version of the old module anyway to be able to use this, I think the module should instead just commit to its new identity, and setup old modules to forward any declarations to the new module. Something like #32816 can later automate the cleanup. |
Are you suggesting that we should start publishing everything under new names and replace the content of the old modules with wrappers of the new modules, using type aliases to ensure compatibility? That would be a lot of work and fragile because functions and global variables cannot be aliased. |
global vars that are modified would be unfortunately left out (all the more reason to avoid them...), but functions can be wrapped, and later inlined to the new functions the wrap, see #32816 (comment) and https://pkg.go.dev/golang.org/x/tools/internal/refactor/inline |
Too late. We already have them. 😢
This changes stack unwinding, which is relevant in a few cases. But the main point is that this is highly unpractical. We would have to support these wrappers across multiple releases until we can be relatively sure that everyone has migrated to the new names. Doing it once manually would already be too much work, doing it repeatedly is out of the question completely unless we can come up with a code generator which does all of this automatically and get it integrated into the release processes of several different repos (yes, plural). |
I am sympathetic to this use-case, but I have a reservation: This seems to amount to a similar effect as a A variation I thought about is to treat this more like a deprecation, where no automatic aliasing occurs but the toolchain announces that the module address has been deprecated during installation, perhaps similar to the current message about a version having been retracted:
This gives a downstream maintainer a notification that this module is being renamed, but doesn't automatically change the meaning of any module addresses already in the program. Instead, it just guides the downstream maintainer toward a solution that they control in their own Adding a This could perhaps be combined with a new rule that prohibits using both the old and the new name in the same With that additional rule it would remain valid to depend only on This does admittedly put some burden on dependents of the module that is being renamed, but that means that they will end up with a clear record in their (in the above I've used "upstream" to mean "a module mentioned in a |
"consider temporarily adopting" might not be strong enough: if a program mixes old and new module, there are bound to be regressions. Definitely the program size increases, but the most common and problematic case will probably be including k8s.io/klog/v2 and k8s.dev/klog/v2. One or the other will not work properly, depending on what gets used by the binary.
That would prevent this problem. If we go down this path, then I think this will be required.
Indeed. To put this into perspective, k8s.io/klog/v2 is imported 16627 times. I believe that's packages, but the list of affected projects and modules is still very long. And that's just one of the affected modules! k8s.io/apimachinery is even worse. Looking at individual projects, some would need 16 (https://github.com/helm/helm/blob/main/go.mod) or 20 (https://github.com/istio/istio/blob/master/go.mod) replace statements. If this is how it needs to be done, it would probably cause quite a bit of work for the entire ecosystem.
Obsolete replace statements do not get removed by |
@ianlancetaylor but that doesn’t work once the old domain goes away does it? what if to gracefully migrate it would be very helpful for the code changes to be done after the domain disappears? |
I have more concerns about this: We currently delegate module identity to DNS. By allowing an identity to be disconnected from that, we potentially introduce a land grab competition for pretty, short names:
This also allows for potentially hostile takeovers of module functionality via supply chain attacks. E.g. In your code:
in some deeply nested dependency that you didn't think to review:
If we were to allow module aliasing, I think it should only be allowed with a replace directive in the main module. (so #26904) |
Probably worth mentioning, that in case of an alias:
The behavior of a program might change slightly (because of import order ( |
@seankhliao: ack, how to do this securely is a problem. The situation that we are facing right now is that we are still in control of the old domain and want to prepare for the transition while we have it. We would start publishing identical content under both domains (or rather, forward to the same Once it's lost, import statements with Perhaps that can be used to make this secure? The alias could trigger only if something imports We may have to consider whether we want to use My original thinking was that we could continue using @mateusz834: right, import order could be relevant. But I'm less worried about that. |
According to https://www.icann.org/en/blogs/details/the-chagos-archipelago-and-the-io-domain-14-11-2024-en, if something needs to be done, we will still have at least 5 years advance notice from the point where we know something needs to be done. Specifically, that page concludes:
We are already discussing how best to handle package migrations (which would suffice to handle module migrations too, since a module is just a set of packages). I don't believe we should design something separate for module migration, and we especially should not design something for a hypothetical that may not actually happen. |
If I understand it right, #60696 is about helping consumers of a package update their go.mod automatically during a dependency update with |
Proposal Details
Importing a Go module is tied to a DNS domain. Should the developer of a module loose ownership of that domain, then the module must be migrated to a different domain. All consumers must follow at the same time, otherwise a binary might end up with a mixture of old and new code under different names, which can cause failures (new module A is used and configured by the binary, old module B used by some dependency is not).
Kubernetes is currently facing that challenge because the
.io
domain might go away and all modules are calledk8s.io/<something>
. It is not certain that anything needs to be done, but if something needs to be done, then it might take years to be ready - so let's discuss now.Can Go support such a transition more gracefully?
One possibility would be to let a module define one or more aliases in its
go.mod
:If such a module gets imported via the alias, the compiler should not complain and treat it as if it had been imported under the official module name. Nothing would change in the
vendor
directory (in particular not some mass renaming of files). In https://pkg.go.dev, the alias could be a redirect to the original name. Deep links into the documentation of a package remain valid.Obviously this only makes sense if the original domain is guaranteed to disappear or not to be used anymore. If the module author transfers a domain, they have to migrate and cannot use the old module name anymore because the new owner of the domain might decide to publish its own modules there. If Go should detect such a conflict is TBD.
The text was updated successfully, but these errors were encountered: