Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚠️ Inject filesystem from CLI instead of creating several per command #2080

Merged
merged 1 commit into from
Mar 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (c CLI) bindCreateAPI(ctx plugin.Context, cmd *cobra.Command) {
return
}

cfg, err := config.LoadInitialized()
cfg, err := config.LoadInitialized(c.fs)
if err != nil {
cmdErr(cmd, err)
return
Expand All @@ -88,6 +88,6 @@ func (c CLI) bindCreateAPI(ctx plugin.Context, cmd *cobra.Command) {
subcommand.UpdateContext(&ctx)
cmd.Long = ctx.Description
cmd.Example = ctx.Examples
cmd.RunE = runECmdFunc(cfg, subcommand,
cmd.RunE = runECmdFunc(c.fs, cfg, subcommand,
fmt.Sprintf("failed to create API with %q", plugin.KeyFor(createAPIPlugin)))
}
12 changes: 9 additions & 3 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ import (
"os"
"strings"

"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/spf13/pflag"

internalconfig "sigs.k8s.io/kubebuilder/v3/pkg/cli/internal/config"
"sigs.k8s.io/kubebuilder/v3/pkg/config"
cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)

Expand Down Expand Up @@ -88,6 +90,9 @@ type CLI struct { //nolint:maligned

// Root command.
cmd *cobra.Command

// Underlying fs
fs machinery.Filesystem
}

// New creates a new CLI instance.
Expand Down Expand Up @@ -131,6 +136,7 @@ func newCLI(options ...Option) (*CLI, error) {
defaultProjectVersion: cfgv3.Version,
defaultPlugins: make(map[config.Version][]string),
plugins: make(map[string]plugin.Plugin),
fs: machinery.Filesystem{FS: afero.NewOsFs()},
}

// Apply provided options.
Expand Down Expand Up @@ -188,9 +194,9 @@ func (c *CLI) getInfoFromFlags() (string, []string, error) {
}

// getInfoFromConfigFile obtains the project version and plugin keys from the project config file.
func getInfoFromConfigFile() (config.Version, []string, error) {
func (c CLI) getInfoFromConfigFile() (config.Version, []string, error) {
// Read the project configuration file
projectConfig, err := internalconfig.Read()
projectConfig, err := internalconfig.Read(c.fs)
switch {
case err == nil:
case os.IsNotExist(err):
Expand Down Expand Up @@ -294,7 +300,7 @@ func (c *CLI) getInfo() error {
return err
}
// Get project version and plugin info from project configuration file
cfgProjectVersion, cfgPlugins, _ := getInfoFromConfigFile()
cfgProjectVersion, cfgPlugins, _ := c.getInfoFromConfigFile()
// We discard the error because not being able to read a project configuration file
// is not fatal for some commands. The ones that require it need to check its existence.

Expand Down
3 changes: 3 additions & 0 deletions pkg/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ import (

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/spf13/afero"
"github.com/spf13/cobra"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2"
cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)

Expand Down Expand Up @@ -585,6 +587,7 @@ var _ = Describe("CLI", func() {
defaultPlugins: map[config.Version][]string{
projectVersion: pluginKeys,
},
fs: machinery.Filesystem{FS: afero.NewMemMapFs()},
}
c.cmd = c.newRootCmd()
Expect(c.getInfo()).To(Succeed())
Expand Down
4 changes: 3 additions & 1 deletion pkg/cli/cmd_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/spf13/cobra"

"sigs.k8s.io/kubebuilder/v3/pkg/cli/internal/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)

Expand All @@ -48,12 +49,13 @@ func errCmdFunc(err error) func(*cobra.Command, []string) error {
// runECmdFunc returns a cobra RunE function that runs subcommand and saves the
// config, which may have been modified by subcommand.
func runECmdFunc(
fs machinery.Filesystem,
c *config.Config,
subcommand plugin.Subcommand,
msg string,
) func(*cobra.Command, []string) error {
return func(*cobra.Command, []string) error {
if err := subcommand.Run(); err != nil {
if err := subcommand.Run(fs); err != nil {
return fmt.Errorf("%s: %v", msg, err)
}
return c.Save()
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (c CLI) bindEdit(ctx plugin.Context, cmd *cobra.Command) {
return
}

cfg, err := config.LoadInitialized()
cfg, err := config.LoadInitialized(c.fs)
if err != nil {
cmdErr(cmd, err)
return
Expand All @@ -88,6 +88,6 @@ func (c CLI) bindEdit(ctx plugin.Context, cmd *cobra.Command) {
subcommand.UpdateContext(&ctx)
cmd.Long = ctx.Description
cmd.Example = ctx.Examples
cmd.RunE = runECmdFunc(cfg, subcommand,
cmd.RunE = runECmdFunc(c.fs, cfg, subcommand,
fmt.Sprintf("failed to edit project with %q", plugin.KeyFor(editPlugin)))
}
6 changes: 3 additions & 3 deletions pkg/cli/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (c CLI) bindInit(ctx plugin.Context, cmd *cobra.Command) {
return
}

cfg, err := internalconfig.New(c.projectVersion, internalconfig.DefaultPath)
cfg, err := internalconfig.New(c.fs, c.projectVersion, internalconfig.DefaultPath)
if err != nil {
cmdErr(cmd, fmt.Errorf("unable to initialize the project configuration: %w", err))
return
Expand All @@ -151,11 +151,11 @@ func (c CLI) bindInit(ctx plugin.Context, cmd *cobra.Command) {
cmd.RunE = func(*cobra.Command, []string) error {
// Check if a config is initialized in the command runner so the check
// doesn't erroneously fail other commands used in initialized projects.
_, err := internalconfig.Read()
_, err := internalconfig.Read(c.fs)
if err == nil || os.IsExist(err) {
log.Fatal("config already initialized")
}
if err := subcommand.Run(); err != nil {
if err := subcommand.Run(c.fs); err != nil {
return fmt.Errorf("failed to initialize project with %q: %v", plugin.KeyFor(initPlugin), err)
}
return cfg.Save()
Expand Down
33 changes: 15 additions & 18 deletions pkg/cli/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ import (
"os"

"github.com/spf13/afero"
"sigs.k8s.io/yaml"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/yaml"
)

const (
Expand Down Expand Up @@ -81,13 +82,13 @@ func readFrom(fs afero.Fs, path string) (config.Config, error) {
}

// Read obtains the configuration from the default path but doesn't allow to persist changes
func Read() (config.Config, error) {
return ReadFrom(DefaultPath)
func Read(fs machinery.Filesystem) (config.Config, error) {
return ReadFrom(fs, DefaultPath)
}

// ReadFrom obtains the configuration from the provided path but doesn't allow to persist changes
func ReadFrom(path string) (config.Config, error) {
return readFrom(afero.NewOsFs(), path)
func ReadFrom(fs machinery.Filesystem, path string) (config.Config, error) {
return readFrom(fs.FS, path)
}

// Config extends model/config.Config allowing to persist changes
Expand All @@ -105,7 +106,7 @@ type Config struct {
}

// New creates a new configuration that will be stored at the provided path
func New(version config.Version, path string) (*Config, error) {
func New(fs machinery.Filesystem, version config.Version, path string) (*Config, error) {
cfg, err := config.New(version)
if err != nil {
return nil, err
Expand All @@ -115,37 +116,33 @@ func New(version config.Version, path string) (*Config, error) {
Config: cfg,
path: path,
mustNotExist: true,
fs: afero.NewOsFs(),
fs: fs.FS,
}, nil
}

// Load obtains the configuration from the default path allowing to persist changes (Save method)
func Load() (*Config, error) {
return LoadFrom(DefaultPath)
func Load(fs machinery.Filesystem) (*Config, error) {
return LoadFrom(fs, DefaultPath)
}

// LoadInitialized calls Load() but returns helpful error messages if the config
// does not exist.
func LoadInitialized() (*Config, error) {
c, err := Load()
func LoadInitialized(fs machinery.Filesystem) (*Config, error) {
c, err := Load(fs)
if os.IsNotExist(err) {
return nil, errors.New("unable to find configuration file, project must be initialized")
}
return c, err
}

// LoadFrom obtains the configuration from the provided path allowing to persist changes (Save method)
func LoadFrom(path string) (*Config, error) {
fs := afero.NewOsFs()
c, err := readFrom(fs, path)
return &Config{Config: c, path: path, fs: fs}, err
func LoadFrom(fs machinery.Filesystem, path string) (*Config, error) {
c, err := readFrom(fs.FS, path)
return &Config{Config: c, path: path, fs: fs.FS}, err
}

// Save saves the configuration information
func (c Config) Save() error {
if c.fs == nil {
c.fs = afero.NewOsFs()
}
// If path is unset, it was created directly with `Config{}`
if c.path == "" {
return saveError{errors.New("no information where it should be stored, " +
Expand Down
4 changes: 2 additions & 2 deletions pkg/cli/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (c CLI) bindCreateWebhook(ctx plugin.Context, cmd *cobra.Command) {
return
}

cfg, err := config.LoadInitialized()
cfg, err := config.LoadInitialized(c.fs)
if err != nil {
cmdErr(cmd, err)
return
Expand All @@ -88,6 +88,6 @@ func (c CLI) bindCreateWebhook(ctx plugin.Context, cmd *cobra.Command) {
subcommand.UpdateContext(&ctx)
cmd.Long = ctx.Description
cmd.Example = ctx.Examples
cmd.RunE = runECmdFunc(cfg, subcommand,
cmd.RunE = runECmdFunc(c.fs, cfg, subcommand,
fmt.Sprintf("failed to create webhook with %q", plugin.KeyFor(createWebhookPlugin)))
}
26 changes: 26 additions & 0 deletions pkg/machinery/filesystem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package machinery

import (
"github.com/spf13/afero"
)

// Filesystem abstracts the underlying disk for scaffolding
type Filesystem struct {
FS afero.Fs
}
3 changes: 2 additions & 1 deletion pkg/plugin/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/spf13/pflag"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
)

// Plugin is an interface that defines the common base for all plugins
Expand Down Expand Up @@ -53,7 +54,7 @@ type Subcommand interface {
// command line flags.
BindFlags(*pflag.FlagSet)
// Run runs the subcommand.
Run() error
Run(fs machinery.Filesystem) error
// InjectConfig passes a config to a plugin. The plugin may modify the config.
// Initializing, loading, and saving the config is managed by the cli package.
InjectConfig(config.Config)
Expand Down
15 changes: 4 additions & 11 deletions pkg/plugins/golang/v2/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"

"github.com/spf13/pflag"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/model"
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
Expand Down Expand Up @@ -126,7 +125,7 @@ func (p *createAPISubcommand) InjectConfig(c config.Config) {
p.config = c
}

func (p *createAPISubcommand) Run() error {
func (p *createAPISubcommand) Run(fs machinery.Filesystem) error {
// Ask for API and Controller if not specified
reader := bufio.NewReader(os.Stdin)
if !p.resourceFlag.Changed {
Expand All @@ -141,7 +140,7 @@ func (p *createAPISubcommand) Run() error {
// Create the resource from the options
p.resource = p.options.NewResource(p.config)

return cmdutil.Run(p)
return cmdutil.Run(p, fs)
}

func (p *createAPISubcommand) Validate() error {
Expand Down Expand Up @@ -171,12 +170,6 @@ func (p *createAPISubcommand) Validate() error {
}

func (p *createAPISubcommand) GetScaffolder() (cmdutil.Scaffolder, error) {
// Load the boilerplate
bp, err := ioutil.ReadFile(filepath.Join("hack", "boilerplate.go.txt")) // nolint:gosec
if err != nil {
return nil, fmt.Errorf("unable to load boilerplate: %v", err)
}

// Load the requested plugins
plugins := make([]model.Plugin, 0)
switch strings.ToLower(p.pattern) {
Expand All @@ -188,7 +181,7 @@ func (p *createAPISubcommand) GetScaffolder() (cmdutil.Scaffolder, error) {
return nil, fmt.Errorf("unknown pattern %q", p.pattern)
}

return scaffolds.NewAPIScaffolder(p.config, string(bp), p.resource, p.force, plugins), nil
return scaffolds.NewAPIScaffolder(p.config, p.resource, p.force, plugins), nil
}

func (p *createAPISubcommand) PostScaffold() error {
Expand Down
5 changes: 3 additions & 2 deletions pkg/plugins/golang/v2/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/spf13/pflag"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/internal/cmdutil"
Expand Down Expand Up @@ -57,8 +58,8 @@ func (p *editSubcommand) InjectConfig(c config.Config) {
p.config = c
}

func (p *editSubcommand) Run() error {
return cmdutil.Run(p)
func (p *editSubcommand) Run(fs machinery.Filesystem) error {
return cmdutil.Run(p, fs)
}

func (p *editSubcommand) Validate() error {
Expand Down
5 changes: 3 additions & 2 deletions pkg/plugins/golang/v2/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"sigs.k8s.io/kubebuilder/v3/pkg/config"
cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2"
"sigs.k8s.io/kubebuilder/v3/pkg/internal/validation"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang"
Expand Down Expand Up @@ -110,8 +111,8 @@ func (p *initSubcommand) InjectConfig(c config.Config) {
p.config = c
}

func (p *initSubcommand) Run() error {
return cmdutil.Run(p)
func (p *initSubcommand) Run(fs machinery.Filesystem) error {
return cmdutil.Run(p, fs)
}

func (p *initSubcommand) Validate() error {
Expand Down
Loading