Skip to content

Commit

Permalink
Use a memory filesystem to scaffold and persist the changes to disk a…
Browse files Browse the repository at this point in the history
…s part of the post-run

Signed-off-by: Adrian Orive <[email protected]>
  • Loading branch information
Adirio committed Jan 28, 2021
1 parent c3e3bd8 commit 57e3c44
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 4 deletions.
15 changes: 12 additions & 3 deletions pkg/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ type cli struct { //nolint:maligned
// Root command.
cmd *cobra.Command

// Underlying fs
fs afero.Fs
// Underlying filesystems
disk, memory, fs afero.Fs
}

// New creates a new cli instance.
Expand Down Expand Up @@ -133,13 +133,22 @@ func New(opts ...Option) (CLI, error) {
// newCLI creates a default cli instance and applies the provided options.
// It is as a separate function for test purposes.
func newCLI(opts ...Option) (*cli, error) {
path, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("unable to get working directory: %w", err)
}
disk := afero.NewBasePathFs(afero.NewOsFs(), path)
memory := afero.NewBasePathFs(afero.NewMemMapFs(), path)

// Default cli options.
c := &cli{
commandName: "kubebuilder",
defaultProjectVersion: cfgv3alpha.Version,
defaultPlugins: make(map[config.Version][]string),
plugins: make(map[string]plugin.Plugin),
fs: afero.NewOsFs(),
disk: disk,
memory: memory,
fs: afero.NewCopyOnWriteFs(disk, memory),
}

// Apply provided options.
Expand Down
69 changes: 68 additions & 1 deletion pkg/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ package cli

import (
"fmt"
"io"
"os"
"strings"

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

Expand All @@ -34,9 +37,10 @@ func (c cli) newRootCmd() *cobra.Command {
Long: `CLI tool for building Kubernetes extensions and tools.
`,
Example: c.rootExamples(),
RunE: func(cmd *cobra.Command, args []string) error {
RunE: func(cmd *cobra.Command, _ []string) error {
return cmd.Help()
},
PersistentPostRunE: c.persistChanges,
}

// Global flags for all subcommands
Expand Down Expand Up @@ -121,3 +125,66 @@ func (c cli) getPluginTable() string {

return strings.Join(lines, "\n")
}

func closeFile(f io.Closer) {
_ = f.Close()
}

// persistChanges walks the scaffolded files in memory and persist them to disk
func (c cli) persistChanges(*cobra.Command, []string) error {
err := afero.Walk(c.memory, ".", func(path string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("error walking memory filesystem at %q: %w", path, err)
}

if info.IsDir() {
// Skip directories, creating files will create the needed directories
return nil
}

var exists bool
exists, err = afero.Exists(c.disk, path)
if err != nil {
return fmt.Errorf("unable to check if %q existed previously: %w", path, err)
}

if exists {
var diskInfo os.FileInfo
diskInfo, err = c.disk.Stat(path)
if err != nil {
return fmt.Errorf("unable to obtain info of %q: %w", path, err)
}

if os.SameFile(info, diskInfo) {
// The file was unchanged, skip it
return nil
}
}

var source io.ReadCloser
source, err = c.memory.Open(path)
if err != nil {
return fmt.Errorf("unable to read %q from memory: %w", path, err)
}
defer closeFile(source)

var sink io.WriteCloser
sink, err = c.disk.Create(path)
if err != nil {
return fmt.Errorf("unable to create/trucate %q file: %w", path, err)
}
defer closeFile(sink)

_, err = io.Copy(sink, source)
if err != nil {
return fmt.Errorf("unable to update %q file: %w", path, err)
}

return nil
})
if err != nil {
return fmt.Errorf("unable to persist scaffolded changes to disk: %w", err)
}

return nil
}

0 comments on commit 57e3c44

Please sign in to comment.