Skip to content

Commit a12a6c3

Browse files
committed
Re-implement list
Some options might be missing...
1 parent 2b6dcd6 commit a12a6c3

File tree

7 files changed

+193
-4
lines changed

7 files changed

+193
-4
lines changed

pkg/envtest/setup/env/env.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ package env
33
import (
44
"io/fs"
55

6+
"github.com/go-logr/logr"
67
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/remote"
78
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/store"
89
)
910

11+
const KubebuilderAssetsEnvVar = "KUBEBUILDER_ASSETS"
12+
1013
// Env encapsulates the environment dependencies.
1114
type Env struct {
1215
*store.Store
@@ -54,5 +57,14 @@ func New(options ...Option) (*Env, error) {
5457
env.Store = store.NewAt(dir)
5558
}
5659

60+
if env.Client == nil {
61+
// this is the minimal configuration that won't panic
62+
env.Client = &remote.Client{
63+
Bucket: remote.DefaultBucket,
64+
Server: remote.DefaultServer,
65+
Log: logr.Discard(),
66+
}
67+
}
68+
5769
return env, nil
5870
}

pkg/envtest/setup/list/config.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package list
2+
3+
import (
4+
"cmp"
5+
"os"
6+
"runtime"
7+
8+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/env"
9+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
10+
)
11+
12+
type config struct {
13+
platform versions.Platform
14+
assetPath string
15+
noDownload bool
16+
envOpts []env.Option
17+
}
18+
19+
// Option is a functional option for configuring the list workflow
20+
type Option func(*config)
21+
22+
// WithEnvOption provides an option for the env.Env used by the workflow
23+
func WithEnvOption(o env.Option) Option {
24+
return func(c *config) { c.envOpts = append(c.envOpts, o) }
25+
}
26+
27+
// WithAssetsAt sets the path to the assets directory.
28+
func WithAssetsAt(dir string) Option {
29+
return func(c *config) { c.assetPath = dir }
30+
}
31+
32+
// WithAssetsFromEnv sets the path to the assets directory from the environment.
33+
func WithAssetsFromEnv(useEnv bool) Option {
34+
return func(c *config) {
35+
if useEnv {
36+
c.assetPath = cmp.Or(os.Getenv(env.KubebuilderAssetsEnvVar), c.assetPath)
37+
}
38+
}
39+
}
40+
41+
// WithPlatform sets the target OS and architecture for the download.
42+
func WithPlatform(os string, arch string) Option {
43+
return func(c *config) { c.platform = versions.Platform{OS: os, Arch: arch} }
44+
}
45+
46+
// NoDownload ensures only local versions are considered
47+
func NoDownload(noDownload bool) Option { return func(c *config) { c.noDownload = noDownload } }
48+
49+
func configure(options ...Option) *config {
50+
cfg := &config{}
51+
52+
for _, opt := range options {
53+
opt(cfg)
54+
}
55+
56+
if cfg.platform == (versions.Platform{}) {
57+
cfg.platform = versions.Platform{
58+
OS: runtime.GOOS,
59+
Arch: runtime.GOARCH,
60+
}
61+
}
62+
return cfg
63+
}

pkg/envtest/setup/list/list.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package list
2+
3+
import (
4+
"cmp"
5+
"context"
6+
"fmt"
7+
"slices"
8+
9+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/env"
10+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/store"
11+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
12+
)
13+
14+
// Status indicates whether a version is available locally or remotely
15+
type Status string
16+
17+
const (
18+
// Installed indicates that this version is installed on the local system
19+
Installed Status = "installed"
20+
// Available indicates that this version is available to download
21+
Available Status = "available"
22+
)
23+
24+
// Result encapsulates a single item in the list of versions
25+
type Result struct {
26+
Version versions.Concrete
27+
Platform versions.Platform
28+
Status Status
29+
}
30+
31+
// List lists available versions, local and remote
32+
func List(ctx context.Context, version versions.Spec, options ...Option) ([]Result, error) {
33+
cfg := configure(options...)
34+
env, err := env.New(cfg.envOpts...)
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
if err := env.Store.Initialize(ctx); err != nil {
40+
return nil, err
41+
}
42+
43+
vs, err := env.Store.List(ctx, store.Filter{Version: version, Platform: cfg.platform})
44+
if err != nil {
45+
return nil, fmt.Errorf("list installed versions: %w", err)
46+
}
47+
48+
results := make([]Result, 0, len(vs))
49+
for _, v := range vs {
50+
results = append(results, Result{Version: v.Version, Platform: v.Platform, Status: Installed})
51+
}
52+
53+
if cfg.noDownload {
54+
return results, nil
55+
}
56+
57+
remoteVersions, err := env.Client.ListVersions(ctx)
58+
if err != nil {
59+
return nil, fmt.Errorf("list available versions: %w", err)
60+
}
61+
62+
for _, set := range remoteVersions {
63+
if !version.Matches(set.Version) {
64+
continue
65+
}
66+
slices.SortFunc(set.Platforms, func(a, b versions.PlatformItem) int {
67+
return cmp.Or(cmp.Compare(a.OS, b.OS), cmp.Compare(a.Arch, b.Arch))
68+
})
69+
for _, plat := range set.Platforms {
70+
if cfg.platform.Matches(plat.Platform) {
71+
results = append(results, Result{
72+
Version: set.Version,
73+
Platform: plat.Platform,
74+
Status: Available,
75+
})
76+
}
77+
}
78+
}
79+
80+
return results, nil
81+
}

pkg/envtest/setup/remote/client.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ import (
2020
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
2121
)
2222

23+
const DefaultBucket = "kubebuilder-tools"
24+
const DefaultServer = "storage.googleapis.com"
25+
2326
// objectList is the parts we need of the GCS "list-objects-in-bucket" endpoint.
2427
type objectList struct {
2528
Items []bucketObject `json:"items"`

pkg/envtest/setup/setup-envtest.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@ import (
44
"context"
55
"fmt"
66

7+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/list"
78
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/use"
89
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
910
)
1011

12+
// List implements the list workflow for listing local and remote versions
13+
func List(ctx context.Context, version string, options ...list.Option) ([]list.Result, error) {
14+
spec, err := readSpec(version)
15+
if err != nil {
16+
return nil, err
17+
}
18+
19+
return list.List(ctx, spec, options...)
20+
}
21+
1122
// Use implements the use workflow for selecting and using a version of the environment.
1223
//
1324
// It will download a remote version if required (and options allow), and return the path to the binary asset directory.

pkg/envtest/setup/use/config.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import (
99
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/versions"
1010
)
1111

12-
const kubebuilderAssets = "KUBEBUILDER_ASSETS"
13-
1412
type config struct {
1513
platform versions.Platform
1614
assetPath string
@@ -33,7 +31,7 @@ func WithAssetsAt(dir string) Option {
3331
func WithAssetsFromEnv(useEnv bool) Option {
3432
return func(c *config) {
3533
if useEnv {
36-
c.assetPath = cmp.Or(os.Getenv(kubebuilderAssets), c.assetPath)
34+
c.assetPath = cmp.Or(os.Getenv(env.KubebuilderAssetsEnvVar), c.assetPath)
3735
}
3836
}
3937
}

tools/setup-envtest/main.go

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"fmt"
1010
"os"
1111
"runtime"
12+
"text/tabwriter"
1213

1314
"github.com/go-logr/logr"
1415
"github.com/go-logr/zapr"
@@ -18,6 +19,7 @@ import (
1819

1920
"sigs.k8s.io/controller-runtime/pkg/envtest/setup"
2021
senv "sigs.k8s.io/controller-runtime/pkg/envtest/setup/env"
22+
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/list"
2123
sremote "sigs.k8s.io/controller-runtime/pkg/envtest/setup/remote"
2224
"sigs.k8s.io/controller-runtime/pkg/envtest/setup/use"
2325
envp "sigs.k8s.io/controller-runtime/tools/setup-envtest/env"
@@ -289,7 +291,26 @@ Environment Variables:
289291
result.Path,
290292
)
291293
case "list":
292-
workflows.List{}.Do(env)
294+
results, err := setup.List(
295+
logr.NewContext(context.Background(), globalLog.WithName("list")),
296+
version,
297+
list.WithAssetsFromEnv(*useEnv),
298+
list.NoDownload(*installedOnly),
299+
list.WithEnvOption(senv.WithClient(&sremote.Client{
300+
Bucket: *remoteBucket,
301+
Server: *remoteServer,
302+
Log: globalLog.WithName("remote-client"),
303+
})),
304+
)
305+
if err != nil {
306+
envp.Exit(2, err.Error())
307+
}
308+
309+
w := tabwriter.NewWriter(os.Stdout, 4, 4, 2, ' ', 0)
310+
defer w.Flush()
311+
for _, result := range results {
312+
fmt.Fprintf(w, "(%s)\tv%s\t%s\n", result.Status, result.Version, result.Platform)
313+
}
293314
case "cleanup":
294315
workflows.Cleanup{}.Do(env)
295316
case "sideload":

0 commit comments

Comments
 (0)