Making temporary changes to 3rd party modules without breaking go install

419 views
Skip to first unread message

Adrian Hesketh

unread,
Feb 23, 2023, 1:02:47 PM2/23/23
to golang-nuts
I've got a program I maintain that uses a 3rd party module. That module has a bug in it, and I've raised a pull request to fix it.

But... I need to release a new version of my program as soon as possible.

My understanding was that I can use a replace directive in the go.mod file to replace the implementation. So I forked the repo, made my single commit change and put a one-liner in the go.mod file:

replace go.lsp.dev/protocol => github.com/a-h/protocol v0.0.0-20230222141054-e5a15864b7f1

Locally, building the project with `go build` worked perfectly well, so I tagged a release, and called it a day.

However, users started reporting that they can't install the package with `go install` because it's broken with an error message of:

go install github.com/a-h/templ/cmd/templ@latest
go: github.com/a-h/templ/cmd/templ@latest (in github.com/a-h/te...@v0.2.198):
        The go.mod file for the module providing named packages contains one or
        more replace directives. It must not contain directives that would cause
        it to be interpreted differently than if it were the main module.

It was a surprise, because it works perfectly well for me. Reading through various issues (linked below), I see lots of discussion, but no clear guidance on what to do as an author.

I assume it's fairly common to need to patch a 3rd party dependency, so I must be missing something. What's the strategy to employ here?

Adrian Hesketh

unread,
Feb 24, 2023, 12:23:28 PM2/24/23
to golang-nuts
I think I have two choices:

1 - stop recommending the use of `go install`, because it:
  • Doesn't support the replace directive.
  • Had an unexpected failure mode that I don't properly understand even after reading the error message and the big thread.
    • I think it means I'm not allowed to use replace directives at all, and the stuff about "interpreted differently" is irrelevant. I think "it" in the second sentence case means "The go.mod file" - I have no idea what "than if it were the main module" is about.
  • Doesn't set the version number in the binary like my build script does (using ldflags).
2 - work around the limitations of `go install` by forking the library _and_ changing the module name instead of using a redirect.

Not using `go install` is unappealing, because then I'd have to write my own cross-platform installation script, but it would solve people not having the build number (templ version would produce useful output). In addition, people might try to use `go install`, and then I'd have to try and explain why it doesn't work.

Working around the limitations is unappealing, because I have to change the go.mod names, and then package names in all .go filenames both in the fork I need to maintain, _and_ my own software. When the PR gets merged, if the go.mod replace directive is supported, it would only be one line change to the go.mod file to go back to the original package (not my fork), without it, it's a minimum 10 file change to update the package names again, and then to delete my fork, which also invalidates old builds.

Nick Craig-Wood

unread,
Feb 28, 2023, 2:37:53 AM2/28/23
to Adrian Hesketh, golang-nuts
This is super annoying - you'll see me in the bug report you linked!

The way to work around it is to fork the upstream repo into your own repository, apply the one line patch there, then change all the package lines and go.mod to point to your new repo.

After you've done all that then in the client code start using the your forked repo instead of the original.

I've had to do this lots of times with rclone. It works but is is a pain.

When the upstream merges your patch you can abandon your fork and revert the import changes.

Moral of the story - never commit a replace statement in go.mod as it breaks go install and go get.

--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/11d78bec-a188-4474-b05e-9d573b33d788n%40googlegroups.com.

Reply all
Reply to author
Forward
0 new messages