How to import two versions of the same go module?
Asked Answered
A

2

18

I have this problem:

  • Module A imports module X v0.1.0
  • Module B imports module X v0.2.0
  • I import both A and B in my project.

Golang picks out X v0.2.0 and calls it good. But it is not good. v0.1 and v0.2 are different enough that A breaks and my project doesn't compile.

What options do I have to fix this?

The offical go stance seems to be "developers of X were doing it wrong and should've released a major version after breaking changes". But that doesn't help the current situation.

I can't find discussions of practical solutions.


Further information

  • The above is a simplification, A and B have a couple more dependencies that also depend on X.
  • This project needs to be maintainable by a group of people. So updating A and B to new versions is ideally straightforwards.
  • This is security-critical code so subtle bugs from mismatched dependencies are a concern.

Things I've tried:

  • Forking A and X, changing the import paths throughout, and updating A's go.mod. It works but makes updates to those modules slow and error prone.
  • Copy and pasting the required code out of A and X to avoid importing it. Also slow and error prone.
  • Did a deep dive into creative applications of go mod vendor, but couldn't find a solution.
Agricola answered 4/8, 2020 at 20:40 Comment(3)
Unfortunately, the official answer is the answer; you can't import two different versions where the version numbers indicate they should be backward-compatible. Forking is possibly your best solution, or if at all possible, using a different package that isn't managed so poorly.Walkway
As @Walkway says you can't do this when the import path is the same. I was able to do something similar when importing the same package with different import paths - namely github.com/allegro/bigcache and github.com/allegro/bigcache/v2. Using Go interfaces I could switch - via a runtime config - between either version (as v2 was sporadically crashing). Depending on the coverage of the API you are using, an interface may help you do something similar with a "forked" version.Habited
Technically the developers of X are not doing it wrong, because a v0 major version, according to semver, is for initial development. Anything may change at any time. The public API should not be considered stable. Instead it's modules that import libraries in v0 that do so at their own risk.Quire
L
7

You can, for example, create local copies of the both modules and use replace directives along with a pseudo major versions to import multiple versions of the same repo using different tags:

replace moduleX/v1010 => ./src/moduleX/0.1.0

replace moduleX/v1020 => ./src/moduleX/0.2.0

Then in your project would use either of the versions as needed:

import (
  moduleX_010 "moduleX/v1010"
  moduleX_020 "moduleX/v1020"
)
Laruelarum answered 15/11, 2022 at 18:19 Comment(0)
B
2

The ideal solution here is to submit an upstream PR to module A to make it compatible with X v0.2.0, and then update your own module to use the fixed version of module A.

If you need to temporarily slot in a fix to module A while you are waiting for the upstream maintainer to respond to the PR, you can do that using a replace directive. (See https://golang.org/doc/modules/managing-dependencies#tmp_11 for more detail.)

Bopp answered 12/2, 2021 at 21:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.