Skip to content

Allow consuming cobra as a library without picking up viper dependencies #1597

Closed
@liggitt

Description

Status

  1. https://github.com/spf13/cobra-cli has been created with an extracted copy of github.com/spf13/cobra/cobra/...
  2. Initialize cobra-cli repo cobra-cli#1 renamed the command to cobra-cli
  3. https://github.com/spf13/cobra-cli/releases/tag/v1.3.0, matching github.com/spf13/cobra v1.3.0 (except for the binary name)
  4. PRs to update public references to cobra/cobra in go imports and scripted references
  5. Remove CLI from this repo and update this repo's readme:

(original description follows)

First, many thanks for such a useful command library. The widespread adoption demonstrates how useful it is. A consequence of being very popular is that any dependencies of this module are picked up as transitive dependencies by a lot of consumers. The github.com/spf13/viper dependency of the cobra command line tool is particularly problematic, as it pulls in large numbers of large dependencies.

It would greatly help downstream consumers if this library could be consumed without picking up the viper dependencies.


History

Relevant existing issues:

There was a prior attempt at isolating the CLI command and viper dependency via a submodule:

That resulted in the following issues:

There were a few problems with the previous attempt:

  • No new tag was created for github.com/spf13/cobra once the submodule was created, so the @latest version of both github.com/spf13/cobra and github.com/spf13/cobra/cobra provided the github.com/spf13/cobra/cobra import path. This caused the "ambiguous import" error
  • The submodule used a local filesystem replace ... => ../ directive, which would break go get github.com/spf13/cobra/cobra and go install github.com/spf13/cobra/cobra@latest

Proposal

2022-03-10 note: rather than the approach proposed here, the Cobra CLI was split to a separate repo at https://github.com/spf13/cobra-cli. See discussion starting at #1597 (comment)

Possible solutions for reorganizing this library to isolate the viper dependency are discussed in #1240. I agree with @spf13 that we should avoid solutions that disrupt current consumers of the github.com/spf13/cobra import path.

I think the previous attempt to create a dedicated module for the cobra command packages (github.com/spf13/cobra/cobra/...) was the right direction, and could resolve the problems with the previous attempt with two changes:

  1. Tag a github.com/spf13/cobra release after adding the sub go.mod so github.com/spf13/cobra@latest resolves to a version that does not provide the github.com/spf13/cobra/cobra package.
  2. Update github.com/spf13/cobra/cobra to refer to the tagged github.com/spf13/cobra release created in step 1 so that it works with go get and go install

Testing

To test this approach, I:

  1. cloned this repo to github.com/liggitt/cobra, and created tags at various points in cobra's history with the import paths renamed (v1.0.0, v1.1.3, and v1.3.0)
  2. created a go.mod file at github.com/liggitt/cobra/cobra, committed and tagged as github.com/liggitt/cobra v1.5.0 - liggitt@0c686b5
  3. updated the go.mod file at github.com/liggitt/cobra/cobra to refer to github.com/liggitt/[email protected], committed and tagged github.com/liggitt/cobra/cobra cobra/v1.5.0 - liggitt@458f3c5

Now, all of the following still work with no complaints about ambiguous import paths:

go get:

go get github.com/liggitt/cobra
go get github.com/liggitt/[email protected]
go get github.com/liggitt/[email protected]
go get github.com/liggitt/cobra@latest
go get -u github.com/liggitt/cobra
go get -u github.com/liggitt/[email protected]
go get -u github.com/liggitt/cobra@latest

go install:

go install github.com/liggitt/cobra/[email protected]
go install github.com/liggitt/cobra/[email protected]
go install github.com/liggitt/cobra/cobra@latest

Impact on library consumers

To see what the impact would be on downstream consumers of this library, I took Kubernetes' use as an example (test commits visible in https://github.com/liggitt/kubernetes/commits/cobra130):

  1. made copies of Kubernetes dependencies that refer to spf13/cobra@{v1.0.0,v1.1.3,v1.3.0}, and adjusted Kubernetes and the dependencies to use liggitt/cobra at the same versions
  2. updated Kubernetes to use liggitt/[email protected]
  3. saw a significant number of transitive dependencies drop out of our dependency graph:
    • cloud.google.com/go/firestore
    • github.com/DataDog/datadog-go
    • github.com/armon/go-metrics
    • github.com/armon/go-radix
    • github.com/bgentry/speakeasy
    • github.com/circonus-labs/circonus-gometrics
    • github.com/circonus-labs/circonusllhist
    • github.com/fatih/color
    • github.com/hashicorp/consul/api
    • github.com/hashicorp/consul/sdk
    • github.com/hashicorp/errwrap
    • github.com/hashicorp/go-cleanhttp
    • github.com/hashicorp/go-hclog
    • github.com/hashicorp/go-immutable-radix
    • github.com/hashicorp/go-msgpack
    • github.com/hashicorp/go-multierror
    • github.com/hashicorp/go-retryablehttp
    • github.com/hashicorp/go-rootcerts
    • github.com/hashicorp/go-sockaddr
    • github.com/hashicorp/go-syslog
    • github.com/hashicorp/go-uuid
    • github.com/hashicorp/golang-lru
    • github.com/hashicorp/hcl
    • github.com/hashicorp/logutils
    • github.com/hashicorp/mdns
    • github.com/hashicorp/memberlist
    • github.com/hashicorp/serf
    • github.com/magiconair/properties
    • github.com/mattn/go-colorable
    • github.com/mattn/go-isatty
    • github.com/miekg/dns
    • github.com/mitchellh/cli
    • github.com/mitchellh/go-homedir
    • github.com/mitchellh/go-testing-interface
    • github.com/pascaldekloe/goe
    • github.com/pelletier/go-toml
    • github.com/posener/complete
    • github.com/ryanuber/columnize
    • github.com/sagikazarmark/crypt
    • github.com/sean-/seed
    • github.com/spf13/cast
    • github.com/spf13/jwalterweatherman
    • github.com/spf13/viper
    • github.com/subosito/gotenv
    • github.com/tv42/httpunix
    • gopkg.in/ini.v1

Impact on library consumers of github.com/spf13/cobra/cobra/...

There don't appear to be very many consumers of these packages (which is not surprising, since their purpose is to support the cobra command line):

Any consumers using these packages beyond v1.3.0 would need to depend on the github.com/spf13/cobra/cobra module instead.


Impact on development

Changes that span the two modules would become more difficult to make, and could not be committed/pushed in a single PR. This is because the two modules are effectively behaving like two distinct modules that happen to live in the same repo, and a release of the library module would be required before the command module could start relying on the changes in it via a publicly referenced version.


Impact on release mechanics

Currently, to release github.com/spf13/cobra:

  1. create and push a v1.x.y git tag

With multiple modules, effectively, two releases would be required (one for the library and one for the command), which would require two tags and a go.mod change:

  1. create and push a v1.x.y git tag
  2. update the github.com/spf13/cobra/cobra/go.mod file to reference that version of the github.com/spf13/cobra library, go mod tidy, commit and push
  3. create and push a cobra/v1.x.y git tag

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions