go-systemd icon indicating copy to clipboard operation
go-systemd copied to clipboard

Troubles with Go modules and version mismatches

Open theory opened this issue 4 years ago • 15 comments

I was just converting a project to a Go module, and was pleased to see #307 merged and v22.0.0 tagged. So I was trying to rely on the go-systemd module, but ran into an error:

github.com/coreos/go-systemd/journal: no matching versions for query "latest"

I can trigger this error with this simple program:

package main
import _ "github.com/coreos/go-systemd/journal"
func main() {}

I can fix it by changing the import to github.com/coreos/go-systemd/v22/journal; however, that doesn't help when I try to import, say, etcd, which gives me this error:

$  go mod tidy
go: finding golang.org/x/net latest
go: finding github.com/coreos/pkg latest
go: finding github.com/tmc/grpc-websocket-proxy latest
go: finding golang.org/x/time latest
go: finding github.com/xiang90/probing latest
go: finding github.com/golang/groupcache latest
go: finding github.com/coreos/go-systemd/journal latest
go: finding github.com/coreos/go-systemd latest
example.com/try imports
	go.etcd.io/etcd/embed imports
	github.com/coreos/pkg/capnslog imports
	github.com/coreos/go-systemd/journal: no matching versions for query "latest"

I guess this can be fixed by capnslog adding v22 to its import, but I don't think that package has been modularized, yet. Is there some other way I can get go mod and friends to find v22 as the latest?

theory avatar Nov 11 '19 21:11 theory

Thanks for the report. I fear you are hitting intrinsic UX issues with the whole Go module machinery, and I don't think there is much I can do as a maintainer of this library.

For the standalone example, see https://github.com/coreos/go-systemd/issues/320#issuecomment-552499085 which explains the Go module switch.

For the etcd case, I think you can ask the etcd maintainers to bump the dependency on their side, or stick to use the same go-systemd version they pinned.

lucab avatar Nov 11 '19 23:11 lucab

I Add this in my go.mod

replace (
  github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 latest
)

then go mod tidy, and I made it.

It will become

require (
 github.com/coreos/go-systemd v0.0.0-00010101000000-000000000000 // indirect
)

jarsaccount avatar Nov 12 '19 05:11 jarsaccount

For the standalone example, see #320 (comment) which explains the Go module switch.

Yes, I was aware of the switch, to Go Modules in v22.0.0, which is great. I don't know enough about modules yet, though, to properly understand the source of or reaseon this error, though.

For the etcd case, I think you can ask the etcd maintainers to bump the dependency on their side, or stick to use the same go-systemd version they pinned.

Or capnslog I guess. How do I pin the version? Or is it better to follow @jarsaccount's suggestion? I added

replace github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 v22.0.0

To my go.mod and now go mod tidy doesn't complain anymore.

theory avatar Nov 12 '19 19:11 theory

actually, i can not load this package when i use go get whih proxy url. who have good solution ?

zhaojingtao avatar Nov 13 '19 02:11 zhaojingtao

@theory to the best of my understanding, the "versionless replace" hack should work as long as the versioned and non-versioned releases of this library have no API-breaking changes.

lucab avatar Nov 18 '19 11:11 lucab

Looks like capnslog does not pin a version of go-systemd, etcd does, so presumably if I copy that line it will continue to work. Would be nice to have a way to say "Pin whatever version this other module pins".

theory avatar Nov 18 '19 21:11 theory

For casual readers landing here, Go modules require semver-imports as explained in the official docs: https://github.com/golang/go/wiki/Modules#semantic-import-versioning.

This means that the proper way to consume this library is via versioned imports as shown in the original bug-report here and in examples: https://github.com/coreos/go-systemd/blob/2d78030078ef61b3cae27f42ad6d0e46db51b339/examples/activation/activation.go#L24

That also means that, in the future, updating to new API-breaking releases will require updating all import paths (e.g. from github.com/coreos/go-systemd/v22/foo to github.com/coreos/go-systemd/v23/foo, once v23 is released).

As an unfortunate side-effect of Go module design, mixing imports from modular and non-modular versions results in some pain (as shown above) and requires some hacks via replace. This is hopefully just a transient mess which will self-resolve as soon as all consumers migrate to Go modules.

lucab avatar Dec 13 '19 09:12 lucab

Yes, but note that I demonstrated the issue with no dependencies, using nothing more than

package main
import _ "github.com/coreos/go-systemd/journal"
func main() {}

I think the solution is to either:

  1. Explicitly import the version you want: import github.com/coreos/go-systemd/v22/journal. This will get the proper line in go.mod:

     require github.com/coreos/go-systemd/v22 v22.0.0
    
  2. Or use replace even if you have no other dependencies, so you replace all instances of the non-version-qualified require statement with the versioned one:

     replace github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 v22.0.0
    

    Unfortunately that means the require line won't have the v22 requirement, oddly:

     require github.com/coreos/go-systemd v0.0.0-00010101000000-000000000000
    

Not sure why that is.

theory avatar Dec 15 '19 19:12 theory

@theory to the best of my understanding, the import "github.com/coreos/go-systemd/journal" above is buggy and not valid under Go module importing rules, as stated by the official documentation (emphasis mine):

If the module is version v2 or higher, the major version of the module must be included as a /vN at the end of the module paths used in go.mod files (e.g., module github.com/my/mod/v2, require github.com/my/mod/v2 v2.0.1) and in the package import path (e.g., import "github.com/my/mod/v2/mypkg"). This includes the paths used in go get commands (e.g., go get github.com/my/mod/[email protected]. Note there is both a /v2 and a @v2.0.1 in that example. One way to think about it is that the module name now includes the /v2, so include /v2 whenever you are using the module name).)

Thus, the correct import line would be import "github.com/coreos/go-systemd/vXYZ/journal" (with proper XYZ version replacement). I understand this is catching a lot of consumers off guard, as this new model is a departure from traditional importing rules.

lucab avatar Dec 16 '19 10:12 lucab

Oooh, okay, thanks for the clarification. I guess that makes sense, as it’s more consistently explicit.

theory avatar Dec 16 '19 19:12 theory

~~@dalu please note that your comment tone is overly aggressive, and your reply doesn't bring any new/relevant content to this ticket.~~ EDIT: it looks like the user got banned from GitHub and their comment removed as a whole. For anybody, in order to reduce the amount of noise here, I'll dismiss any further similar ones in the future (as this is not a discussion forum).

Anyway, just to cover the technical side once more:

  • This repository has been tagged on a regular basis since years, way before gomod came and forced semver tags. Tags up to v21 exist but gomod does not accept them. Thus the jump to v22.0.0.
  • The (multiple) breaking changes at v22.0.0 are documented in the changelog. See https://github.com/coreos/go-systemd/pull/307 for more in-depth analysis.
  • Other repositories like github.com/mongodb/mongo-go-driver do not (yet) feel the pain of versioned import because they are at major version <= 1.
  • If you have doubts on how gomod-style imports work, please consult the Golang official documentation. A relevant excerpt has been already quoted here in https://github.com/coreos/go-systemd/issues/321#issuecomment-566004138.

lucab avatar Mar 06 '20 09:03 lucab

I Add this in my go.mod

replace (
  github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 latest
)

then go mod tidy, and I made it.

It will become

require (
 github.com/coreos/go-systemd v0.0.0-00010101000000-000000000000 // indirect
)

this worked for me. thanks @jarsaccount

Bhagyashreek8 avatar Jul 15 '20 17:07 Bhagyashreek8

So. How to use the latest untag version

I Add this in my go.mod

replace (
  github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 latest
)

then go mod tidy, and I made it.

It will become

require (
 github.com/coreos/go-systemd v0.0.0-00010101000000-000000000000 // indirect
)

Just for memo. If someone want use latest untag version. You can change to

replace github.com/coreos/go-systemd => github.com/coreos/go-systemd/v22 v22.1.1-0.20201123092900-87511f396ae9

😂

Abirdcfly avatar Nov 27 '20 10:11 Abirdcfly

For those who don't want to use the import directive: This is how it can be done:

go.mod file:


module foo

go 1.16

require (
	github.com/coreos/go-systemd/v22 v22.3.2 // indirect
)

some go file


import (
	"context"

	"github.com/coreos/go-systemd/v22/dbus"
)

...

guenhter avatar Jun 22 '21 06:06 guenhter

For whatever reason I tripped over this. Adding the version in the import path is the correct solution.

import _ "github.com/coreos/go-systemd/v22/journal"

enocom avatar Sep 18 '23 21:09 enocom