Skip to content

Commit

Permalink
Inject filesystem from cli instead of creating several per command
Browse files Browse the repository at this point in the history
Signed-off-by: Adrian Orive <[email protected]>
  • Loading branch information
Adirio committed Feb 4, 2021
1 parent 3c8e370 commit 9eb1b07
Show file tree
Hide file tree
Showing 31 changed files with 245 additions and 170 deletions.
2 changes: 1 addition & 1 deletion pkg/cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
5 changes: 5 additions & 0 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"os"
"strings"

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

Expand Down Expand Up @@ -96,6 +97,9 @@ type cli struct { //nolint:maligned

// Root command.
cmd *cobra.Command

// Underlying fs
fs afero.Fs
}

// New creates a new cli instance.
Expand Down Expand Up @@ -134,6 +138,7 @@ func newCLI(opts ...Option) (*cli, error) {
defaultProjectVersion: cfgv3.Version,
defaultPlugins: make(map[config.Version][]string),
plugins: make(map[string]plugin.Plugin),
fs: afero.NewOsFs(),
}

// Apply provided options.
Expand Down
6 changes: 4 additions & 2 deletions pkg/cli/cmd_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package cli
import (
"fmt"

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

"sigs.k8s.io/kubebuilder/v3/pkg/cli/internal/config"
Expand Down Expand Up @@ -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 afero.Fs,
c *config.Config,
subcommand plugin.Subcommand, // nolint:interfacer
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
2 changes: 1 addition & 1 deletion pkg/cli/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
2 changes: 1 addition & 1 deletion pkg/cli/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func (c cli) bindInit(ctx plugin.Context, cmd *cobra.Command) {
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
3 changes: 3 additions & 0 deletions pkg/cli/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ const (
DefaultPath = "PROJECT"
)

// TODO: use cli.fs instead of creating a new afero.Fs for each config. For this purpose, we may want to turn this
// package's functions into methods of cli.

func exists(fs afero.Fs, path string) (bool, error) {
// Look up the file
_, err := fs.Stat(path)
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}
3 changes: 2 additions & 1 deletion pkg/plugin/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package plugin

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

"sigs.k8s.io/kubebuilder/v3/pkg/config"
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 afero.Fs) 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,11 +20,10 @@ import (
"bufio"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"

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

"sigs.k8s.io/kubebuilder/v3/pkg/config"
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 afero.Fs) 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 @@ -19,6 +19,7 @@ package v2
import (
"fmt"

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

"sigs.k8s.io/kubebuilder/v3/pkg/config"
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 afero.Fs) 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 @@ -22,6 +22,7 @@ import (
"path/filepath"
"strings"

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

"sigs.k8s.io/kubebuilder/v3/pkg/config"
Expand Down Expand Up @@ -109,8 +110,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 afero.Fs) error {
return cmdutil.Run(p, fs)
}

func (p *initSubcommand) Validate() error {
Expand Down
43 changes: 28 additions & 15 deletions pkg/plugins/golang/v2/scaffolds/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package scaffolds
import (
"fmt"

"github.com/spf13/afero"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/model"
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
Expand All @@ -29,6 +31,7 @@ import (
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds/internal/templates/config/rbac"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds/internal/templates/config/samples"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds/internal/templates/controllers"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2/scaffolds/internal/templates/hack"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/internal/cmdutil"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/internal/machinery"
)
Expand All @@ -46,6 +49,9 @@ type apiScaffolder struct {
boilerplate string
resource resource.Resource

// fs is the filesystem that will be used by the scaffolder
fs afero.Fs

// plugins is the list of plugins we should allow to transform our generated scaffolding
plugins []model.Plugin

Expand All @@ -56,24 +62,21 @@ type apiScaffolder struct {
// NewAPIScaffolder returns a new Scaffolder for API/controller creation operations
func NewAPIScaffolder(
config config.Config,
boilerplate string,
res resource.Resource,
force bool,
plugins []model.Plugin,
) cmdutil.Scaffolder {
return &apiScaffolder{
config: config,
boilerplate: boilerplate,
resource: res,
plugins: plugins,
force: force,
config: config,
resource: res,
plugins: plugins,
force: force,
}
}

// Scaffold implements Scaffolder
func (s *apiScaffolder) Scaffold() error {
fmt.Println("Writing scaffold for you to edit...")
return s.scaffold()
// InjectFS implements cmdutil.Scaffolder
func (s *apiScaffolder) InjectFS(fs afero.Fs) {
s.fs = fs
}

func (s *apiScaffolder) newUniverse() *model.Universe {
Expand All @@ -84,7 +87,17 @@ func (s *apiScaffolder) newUniverse() *model.Universe {
)
}

func (s *apiScaffolder) scaffold() error {
// Scaffold implements cmdutil.Scaffolder
func (s *apiScaffolder) Scaffold() error {
fmt.Println("Writing scaffold for you to edit...")

// Load the boilerplate
bp, err := afero.ReadFile(s.fs, hack.DefaultBoilerplatePath)
if err != nil {
return fmt.Errorf("error scaffolding API/controller: unable to load boilerplate: %w", err)
}
s.boilerplate = string(bp)

// Keep track of these values before the update
doAPI := s.resource.HasAPI()
doController := s.resource.HasController()
Expand All @@ -95,7 +108,7 @@ func (s *apiScaffolder) scaffold() error {
return fmt.Errorf("error updating resource: %w", err)
}

if err := machinery.NewScaffold(s.plugins...).Execute(
if err := machinery.NewScaffold(s.fs, s.plugins...).Execute(
s.newUniverse(),
&api.Types{Force: s.force},
&api.Group{},
Expand All @@ -108,7 +121,7 @@ func (s *apiScaffolder) scaffold() error {
return fmt.Errorf("error scaffolding APIs: %w", err)
}

if err := machinery.NewScaffold().Execute(
if err := machinery.NewScaffold(s.fs).Execute(
s.newUniverse(),
&crd.Kustomization{},
&crd.KustomizeConfig{},
Expand All @@ -119,7 +132,7 @@ func (s *apiScaffolder) scaffold() error {
}

if doController {
if err := machinery.NewScaffold(s.plugins...).Execute(
if err := machinery.NewScaffold(s.fs, s.plugins...).Execute(
s.newUniverse(),
&controllers.SuiteTest{Force: s.force},
&controllers.Controller{ControllerRuntimeVersion: ControllerRuntimeVersion, Force: s.force},
Expand All @@ -128,7 +141,7 @@ func (s *apiScaffolder) scaffold() error {
}
}

if err := machinery.NewScaffold(s.plugins...).Execute(
if err := machinery.NewScaffold(s.fs, s.plugins...).Execute(
s.newUniverse(),
&templates.MainUpdater{WireResource: doAPI, WireController: doController},
); err != nil {
Expand Down
20 changes: 14 additions & 6 deletions pkg/plugins/golang/v2/scaffolds/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ package scaffolds

import (
"fmt"
"io/ioutil"
"strings"

"github.com/spf13/afero"

"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/internal/cmdutil"
)
Expand All @@ -30,6 +31,9 @@ var _ cmdutil.Scaffolder = &editScaffolder{}
type editScaffolder struct {
config config.Config
multigroup bool

// fs is the filesystem that will be used by the scaffolder
fs afero.Fs
}

// NewEditScaffolder returns a new Scaffolder for configuration edit operations
Expand All @@ -40,10 +44,15 @@ func NewEditScaffolder(config config.Config, multigroup bool) cmdutil.Scaffolder
}
}

// Scaffold implements Scaffolder
// InjectFS implements cmdutil.Scaffolder
func (s *editScaffolder) InjectFS(fs afero.Fs) {
s.fs = fs
}

// Scaffold implements cmdutil.Scaffolder
func (s *editScaffolder) Scaffold() error {
filename := "Dockerfile"
bs, err := ioutil.ReadFile(filename)
bs, err := afero.ReadFile(s.fs, filename)
if err != nil {
return err
}
Expand Down Expand Up @@ -76,9 +85,8 @@ func (s *editScaffolder) Scaffold() error {
// Check if the str is not empty, because when the file is already in desired format it will return empty string
// because there is nothing to replace.
if str != "" {
// false positive
// nolint:gosec
return ioutil.WriteFile(filename, []byte(str), 0644)
// TODO: instead of writing it directly, we should use the scaffolding machinery for consistency
return afero.WriteFile(s.fs, filename, []byte(str), 0644)
}

return nil
Expand Down
Loading

0 comments on commit 9eb1b07

Please sign in to comment.