Skip to content

Commit

Permalink
Merge pull request #2080 from Adirio/inject-filesystem
Browse files Browse the repository at this point in the history
⚠️ Inject filesystem from CLI instead of creating several per command
  • Loading branch information
k8s-ci-robot committed Mar 13, 2021
2 parents 9742a11 + a2cc78c commit 73cda2b
Show file tree
Hide file tree
Showing 33 changed files with 310 additions and 201 deletions.
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

0 comments on commit 73cda2b

Please sign in to comment.