diff --git a/cmd/hauler/cli/cli.go b/cmd/hauler/cli/cli.go index 96deb06..4d36528 100644 --- a/cmd/hauler/cli/cli.go +++ b/cmd/hauler/cli/cli.go @@ -1,32 +1,17 @@ package cli import ( - "context" - "errors" - "os" - "path/filepath" - - "github.com/rancherfederal/ocil/pkg/layer" "github.com/spf13/cobra" - "github.com/rancherfederal/ocil/pkg/store" - "github.com/rancherfederal/hauler/pkg/log" ) type rootOpts struct { logLevel string - cacheDir string - storeDir string } var ro = &rootOpts{} -const ( - DefaultStoreName = "store" - DefaultCacheDir = "hauler" -) - func New() *cobra.Command { cmd := &cobra.Command{ Use: "hauler", @@ -44,8 +29,6 @@ func New() *cobra.Command { pf := cmd.PersistentFlags() pf.StringVarP(&ro.logLevel, "log-level", "l", "info", "") - pf.StringVar(&ro.cacheDir, "cache", "", "Location of where to store cache data (defaults to $XDG_CACHE_DIR/hauler)") - pf.StringVarP(&ro.storeDir, "store", "s", DefaultStoreName, "Location to create store at") // Add subcommands addDownload(cmd) @@ -55,57 +38,3 @@ func New() *cobra.Command { return cmd } - -func (o *rootOpts) getStore(ctx context.Context) (*store.Layout, error) { - l := log.FromContext(ctx) - dir := o.storeDir - - abs, err := filepath.Abs(dir) - if err != nil { - return nil, err - } - - l.Debugf("using store at %s", abs) - if _, err := os.Stat(abs); errors.Is(err, os.ErrNotExist) { - err := os.Mkdir(abs, os.ModePerm) - if err != nil { - return nil, err - } - } else if err != nil { - return nil, err - } - - // TODO: Do we want this to be configurable? - c, err := o.getCache(ctx) - if err != nil { - return nil, err - } - - s, err := store.NewLayout(abs, store.WithCache(c)) - if err != nil { - return nil, err - } - return s, nil -} - -func (o *rootOpts) getCache(ctx context.Context) (layer.Cache, error) { - dir := o.cacheDir - - if dir == "" { - // Default to $XDG_CACHE_HOME - cachedir, err := os.UserCacheDir() - if err != nil { - return nil, err - } - - abs, _ := filepath.Abs(filepath.Join(cachedir, DefaultCacheDir)) - if err := os.MkdirAll(abs, os.ModePerm); err != nil { - return nil, err - } - - dir = abs - } - - c := layer.NewFilesystemCache(dir) - return c, nil -} diff --git a/cmd/hauler/cli/store.go b/cmd/hauler/cli/store.go index 49b86df..41e383a 100644 --- a/cmd/hauler/cli/store.go +++ b/cmd/hauler/cli/store.go @@ -6,6 +6,8 @@ import ( "github.com/rancherfederal/hauler/cmd/hauler/cli/store" ) +var rootStoreOpts = &store.RootOpts{} + func addStore(parent *cobra.Command) { cmd := &cobra.Command{ Use: "store", @@ -15,6 +17,7 @@ func addStore(parent *cobra.Command) { return cmd.Help() }, } + rootStoreOpts.AddArgs(cmd) cmd.AddCommand( addStoreSync(), @@ -33,7 +36,7 @@ func addStore(parent *cobra.Command) { } func addStoreExtract() *cobra.Command { - o := &store.ExtractOpts{} + o := &store.ExtractOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "extract", @@ -43,7 +46,7 @@ func addStoreExtract() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } @@ -57,7 +60,7 @@ func addStoreExtract() *cobra.Command { } func addStoreSync() *cobra.Command { - o := &store.SyncOpts{} + o := &store.SyncOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "sync", @@ -65,7 +68,7 @@ func addStoreSync() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } @@ -79,7 +82,7 @@ func addStoreSync() *cobra.Command { } func addStoreLoad() *cobra.Command { - o := &store.LoadOpts{} + o := &store.LoadOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "load", @@ -88,13 +91,13 @@ func addStoreLoad() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } _ = s - return store.LoadCmd(ctx, o, "", args...) + return store.LoadCmd(ctx, o, args...) }, } o.AddFlags(cmd) @@ -103,7 +106,7 @@ func addStoreLoad() *cobra.Command { } func addStoreServe() *cobra.Command { - o := &store.ServeOpts{} + o := &store.ServeOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "serve", @@ -111,7 +114,7 @@ func addStoreServe() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } @@ -125,7 +128,7 @@ func addStoreServe() *cobra.Command { } func addStoreSave() *cobra.Command { - o := &store.SaveOpts{} + o := &store.SaveOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "save", @@ -134,13 +137,13 @@ func addStoreSave() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } _ = s - return store.SaveCmd(ctx, o, o.FileName, "") + return store.SaveCmd(ctx, o, o.FileName) }, } o.AddArgs(cmd) @@ -149,7 +152,7 @@ func addStoreSave() *cobra.Command { } func addStoreInfo() *cobra.Command { - o := &store.InfoOpts{} + o := &store.InfoOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "info", @@ -159,7 +162,7 @@ func addStoreInfo() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } @@ -173,7 +176,7 @@ func addStoreInfo() *cobra.Command { } func addStoreCopy() *cobra.Command { - o := &store.CopyOpts{} + o := &store.CopyOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "copy", @@ -182,7 +185,7 @@ func addStoreCopy() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } @@ -214,7 +217,7 @@ func addStoreAdd() *cobra.Command { } func addStoreAddFile() *cobra.Command { - o := &store.AddFileOpts{} + o := &store.AddFileOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "file", @@ -223,7 +226,7 @@ func addStoreAddFile() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } @@ -237,7 +240,7 @@ func addStoreAddFile() *cobra.Command { } func addStoreAddImage() *cobra.Command { - o := &store.AddImageOpts{} + o := &store.AddImageOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "image", @@ -246,7 +249,7 @@ func addStoreAddImage() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } @@ -260,7 +263,7 @@ func addStoreAddImage() *cobra.Command { } func addStoreAddChart() *cobra.Command { - o := &store.AddChartOpts{} + o := &store.AddChartOpts{RootOpts: rootStoreOpts} cmd := &cobra.Command{ Use: "chart", @@ -282,7 +285,7 @@ hauler store add chart rancher --repo "https://releases.rancher.com/server-chart RunE: func(cmd *cobra.Command, args []string) error { ctx := cmd.Context() - s, err := ro.getStore(ctx) + s, err := o.Store(ctx) if err != nil { return err } diff --git a/cmd/hauler/cli/store/add.go b/cmd/hauler/cli/store/add.go index 1b3ef83..c997b9b 100644 --- a/cmd/hauler/cli/store/add.go +++ b/cmd/hauler/cli/store/add.go @@ -19,6 +19,7 @@ import ( ) type AddFileOpts struct { + *RootOpts Name string } @@ -54,6 +55,7 @@ func storeFile(ctx context.Context, s *store.Layout, fi v1alpha1.File) error { } type AddImageOpts struct { + *RootOpts Name string } @@ -93,6 +95,7 @@ func storeImage(ctx context.Context, s *store.Layout, i v1alpha1.Image) error { } type AddChartOpts struct { + *RootOpts Version string RepoURL string diff --git a/cmd/hauler/cli/store/copy.go b/cmd/hauler/cli/store/copy.go index 51e844b..df47d5d 100644 --- a/cmd/hauler/cli/store/copy.go +++ b/cmd/hauler/cli/store/copy.go @@ -16,8 +16,9 @@ import ( ) type CopyOpts struct { - Target string + *RootOpts + Target string Username string Password string Insecure bool diff --git a/cmd/hauler/cli/store/extract.go b/cmd/hauler/cli/store/extract.go index 9d24469..de29b92 100644 --- a/cmd/hauler/cli/store/extract.go +++ b/cmd/hauler/cli/store/extract.go @@ -16,6 +16,7 @@ import ( ) type ExtractOpts struct { + *RootOpts DestinationDir string } diff --git a/cmd/hauler/cli/store/flags.go b/cmd/hauler/cli/store/flags.go new file mode 100644 index 0000000..dbb1b7f --- /dev/null +++ b/cmd/hauler/cli/store/flags.go @@ -0,0 +1,84 @@ +package store + +import ( + "context" + "errors" + "os" + "path/filepath" + + "github.com/rancherfederal/ocil/pkg/layer" + "github.com/rancherfederal/ocil/pkg/store" + "github.com/spf13/cobra" + + "github.com/rancherfederal/hauler/pkg/log" +) + +const ( + DefaultStoreName = "store" + DefaultCacheDir = "hauler" +) + +type RootOpts struct { + StoreDir string + CacheDir string +} + +func (o *RootOpts) AddArgs(cmd *cobra.Command) { + pf := cmd.PersistentFlags() + pf.StringVar(&o.CacheDir, "cache", "", "Location of where to store cache data (defaults to $XDG_CACHE_DIR/hauler)") + pf.StringVarP(&o.StoreDir, "store", "s", DefaultStoreName, "Location to create store at") +} + +func (o *RootOpts) Store(ctx context.Context) (*store.Layout, error) { + l := log.FromContext(ctx) + dir := o.StoreDir + + abs, err := filepath.Abs(dir) + if err != nil { + return nil, err + } + + l.Debugf("using store at %s", abs) + if _, err := os.Stat(abs); errors.Is(err, os.ErrNotExist) { + err := os.Mkdir(abs, os.ModePerm) + if err != nil { + return nil, err + } + } else if err != nil { + return nil, err + } + + // TODO: Do we want this to be configurable? + c, err := o.Cache(ctx) + if err != nil { + return nil, err + } + + s, err := store.NewLayout(abs, store.WithCache(c)) + if err != nil { + return nil, err + } + return s, nil +} + +func (o *RootOpts) Cache(ctx context.Context) (layer.Cache, error) { + dir := o.CacheDir + + if dir == "" { + // Default to $XDG_CACHE_HOME + cachedir, err := os.UserCacheDir() + if err != nil { + return nil, err + } + + abs, _ := filepath.Abs(filepath.Join(cachedir, DefaultCacheDir)) + if err := os.MkdirAll(abs, os.ModePerm); err != nil { + return nil, err + } + + dir = abs + } + + c := layer.NewFilesystemCache(dir) + return c, nil +} diff --git a/cmd/hauler/cli/store/info.go b/cmd/hauler/cli/store/info.go index 439a0ef..74cdce7 100644 --- a/cmd/hauler/cli/store/info.go +++ b/cmd/hauler/cli/store/info.go @@ -18,6 +18,8 @@ import ( ) type InfoOpts struct { + *RootOpts + OutputFormat string SizeUnit string } diff --git a/cmd/hauler/cli/store/load.go b/cmd/hauler/cli/store/load.go index 69488de..4027948 100644 --- a/cmd/hauler/cli/store/load.go +++ b/cmd/hauler/cli/store/load.go @@ -10,32 +10,26 @@ import ( ) type LoadOpts struct { - OutputDir string + *RootOpts } func (o *LoadOpts) AddFlags(cmd *cobra.Command) { f := cmd.Flags() - - f.StringVarP(&o.OutputDir, "output", "o", "", "Directory to unload archived contents to (defaults to $PWD/haul)") + _ = f } // LoadCmd // TODO: Just use mholt/archiver for now, even though we don't need most of it -func LoadCmd(ctx context.Context, o *LoadOpts, dir string, archiveRefs ...string) error { +func LoadCmd(ctx context.Context, o *LoadOpts, archiveRefs ...string) error { l := log.FromContext(ctx) // TODO: Support more formats? a := archiver.NewTarZstd() a.OverwriteExisting = true - odir := dir - if o.OutputDir != "" { - odir = o.OutputDir - } - for _, archiveRef := range archiveRefs { - l.Infof("loading content from [%s] to [%s]", archiveRef, odir) - err := a.Unarchive(archiveRef, odir) + l.Infof("loading content from [%s] to [%s]", archiveRef, o.StoreDir) + err := a.Unarchive(archiveRef, o.StoreDir) if err != nil { return err } diff --git a/cmd/hauler/cli/store/save.go b/cmd/hauler/cli/store/save.go index 4f59166..3d27382 100644 --- a/cmd/hauler/cli/store/save.go +++ b/cmd/hauler/cli/store/save.go @@ -12,6 +12,7 @@ import ( ) type SaveOpts struct { + *RootOpts FileName string } @@ -23,7 +24,7 @@ func (o *SaveOpts) AddArgs(cmd *cobra.Command) { // SaveCmd // TODO: Just use mholt/archiver for now, even though we don't need most of it -func SaveCmd(ctx context.Context, o *SaveOpts, outputFile string, dir string) error { +func SaveCmd(ctx context.Context, o *SaveOpts, outputFile string) error { l := log.FromContext(ctx) // TODO: Support more formats? @@ -40,7 +41,7 @@ func SaveCmd(ctx context.Context, o *SaveOpts, outputFile string, dir string) er return err } defer os.Chdir(cwd) - if err := os.Chdir(dir); err != nil { + if err := os.Chdir(o.StoreDir); err != nil { return err } @@ -49,6 +50,6 @@ func SaveCmd(ctx context.Context, o *SaveOpts, outputFile string, dir string) er return err } - l.Infof("saved store [%s] -> [%s]", dir, absOutputfile) + l.Infof("saved store [%s] -> [%s]", o.StoreDir, absOutputfile) return nil } diff --git a/cmd/hauler/cli/store/serve.go b/cmd/hauler/cli/store/serve.go index 37b378f..6f39441 100644 --- a/cmd/hauler/cli/store/serve.go +++ b/cmd/hauler/cli/store/serve.go @@ -20,6 +20,8 @@ import ( ) type ServeOpts struct { + *RootOpts + Port int RootDir string ConfigFile string diff --git a/cmd/hauler/cli/store/sync.go b/cmd/hauler/cli/store/sync.go index 4d254f9..046ef0e 100644 --- a/cmd/hauler/cli/store/sync.go +++ b/cmd/hauler/cli/store/sync.go @@ -20,6 +20,7 @@ import ( ) type SyncOpts struct { + *RootOpts ContentFiles []string }