Looking at the kfserving
go.mod
file at v0.5.1
, I see a big block of replace
directives. By design, replace
directives “only apply in the main module's go.mod
file and are ignored in other modules”, so it looks like kfserving
has some technical debt here that they're passing on to you.
I started with an empty go.mod
file and pasted in those replace
directives. Then:
$ go get -d github.com/kubeflow/kfserving/pkg/client/clientset/versioned@v0.5.1
go get: added github.com/PuerkitoBio/purell v1.1.1
…
go get: added sigs.k8s.io/yaml v1.2.0
The .go
source file needed a few fixes for typos and mismatched types. I fudged it to:
package main
import (
"fmt"
kfs "github.com/kubeflow/kfserving/pkg/client/clientset/versioned"
)
func main() {
var clientset *kfs.Clientset
clientset = kfs.NewForConfigOrDie(nil)
fmt.Println(clientset)
}
and then go build .
succeeds:
$ go build -o /dev/null .
Now I'll run go mod tidy
to clean up the go.mod
and go.sum
files:
$ go mod tidy
go: downloading github.com/stretchr/testify v1.5.1
…
go: downloading github.com/jmespath/go-jmespath v0.3.0
But wait! I've still got all of the technical debt from kfserving/go.mod
— without any comments explaining the choice of versions! — and I'm passing that technical debt on to any downstream users. Let's see if I can improve the situation while I'm here.
Go 1.16 handles the exclude
directive a lot better than previous Go versions did, so maybe I can use a couple of targeted exclude
directives instead of the (rather large) replace
hammer.
I'll start by committing the fixes so far. (If nothing else, I want to be able to git diff
the requirements to see what has changed.)
$ git add *.go go.mod go.sum
$ git commit -m 'fixed kfserving build'
[main fd93b1d] fixed kfserving build
3 files changed, 1643 insertions(+), 2 deletions(-)
create mode 100644 go.sum
I notice that all of the replace
directives apply to k8s.io
paths, so I'll list the current versions of those paths to see what needs to be fixed:
$ go list -m k8s.io/...
k8s.io/api v0.19.2 => k8s.io/api v0.19.2
k8s.io/apiextensions-apiserver v0.19.2 => k8s.io/apiextensions-apiserver v0.19.2
k8s.io/apimachinery v0.19.2 => k8s.io/apimachinery v0.19.2
k8s.io/apiserver v0.19.2 => k8s.io/apiserver v0.19.2
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible => k8s.io/client-go v0.19.2
k8s.io/cloud-provider v0.19.2 => k8s.io/cloud-provider v0.19.2
k8s.io/code-generator v0.19.2 => k8s.io/code-generator v0.19.2
k8s.io/component-base v0.19.2 => k8s.io/component-base v0.19.2
k8s.io/csi-translation-lib v0.19.2 => k8s.io/csi-translation-lib v0.19.2
k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14
k8s.io/klog v1.0.0 => k8s.io/klog v1.0.0
k8s.io/klog/v2 v2.2.0
k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6
k8s.io/legacy-cloud-providers v0.17.4 => k8s.io/legacy-cloud-providers v0.19.2
k8s.io/test-infra v0.0.0-20200803112140-d8aa4e063646 => k8s.io/test-infra v0.0.0-20200803112140-d8aa4e063646
k8s.io/utils v0.0.0-20200912215256-4140de9c8800 => k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
Most of those look fine, but there are three mismatched versions:
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible => k8s.io/client-go v0.19.2
…
k8s.io/legacy-cloud-providers v0.17.4 => k8s.io/legacy-cloud-providers v0.19.2
…
k8s.io/utils v0.0.0-20200912215256-4140de9c8800 => k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
legacy-cloud-providers
just needs an upgrade, so that should be easy enough to fix with go get
— but it's not relevant to this package anyway so I can just let it float to whatever version it ends up at. I'll cut down the replace
directives to just the two remaining modules and see how far I get:
replace (
k8s.io/client-go => k8s.io/client-go v0.19.2
k8s.io/utils => k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
)
Now:
$ go mod tidy
$ go build -o /dev/null .
Ok, so the build is still good — I've made incremental progress, so I'll lock that in:
$ git add go.mod go.sum
$ git commit -m 'go.mod: remove irrelevant replacements'
[main cdbc1db] go.mod: remove irrelevant replacements
3 files changed, 456 insertions(+), 43 deletions(-)
rewrite go.mod (85%)
create mode 100755 m
Now let's try notching out the bad client-go
versions with exclude
directives:
$ go mod edit -exclude=k8s.io/client-go@v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
$ go list -m k8s.io/client-go
k8s.io/client-go v9.0.0+incompatible => k8s.io/client-go v0.19.2
$ go mod edit -exclude=k8s.io/client-go@v9.0.0+incompatible
$ go list -m k8s.io/client-go
k8s.io/client-go v0.19.2 => k8s.io/client-go v0.19.2
Now I'm at the client-go
version I needed, so I can drop that replace
directive:
$ go mod edit -dropreplace=k8s.io/client-go
$ go mod tidy
$ go build -o /dev/null .
And again lock it in:
$ git add go.mod go.sum
$ git commit -m 'go.mod: use exclude instead of replace to notch out unwanted client-go versions'
[main de69965] go.mod: use exclude instead of replace to notch out unwanted client-go versions
2 files changed, 21 insertions(+), 3 deletions(-)
Now let's see what's going on with this k8s.io/utils
replacement. I suspect that it isn't really needed — the version will be upgraded a bit, but I'm betting it won't break the build. And, indeed, it seems to be fine:
$ go list -m k8s.io/utils
k8s.io/utils v0.0.0-20200912215256-4140de9c8800 => k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89
$ go mod edit -dropreplace=k8s.io/utils
$ go mod tidy
$ go build -o /dev/null .
$ go list -m k8s.io/utils
k8s.io/utils v0.0.0-20200912215256-4140de9c8800
So now I've successfully reduced that big nest of replace
directives from kfserving
to just a couple of exclude
directives targeted retracted versions of k8s.io/client-go
. Here's my whole go.mod
file at the end of this process:
module example.com/m
go 1.16
exclude (
k8s.io/client-go v11.0.1-0.20190805182717-6502b5e7b1b5+incompatible
k8s.io/client-go v9.0.0+incompatible
)
require github.com/kubeflow/kfserving v0.5.1