diff --git a/README.md b/README.md index 2610cb8..2ce09ce 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Start the server. The `--init` flag with create the default files and directory makeshift serve --root $HOME/apps/makeshift/server --init ``` -From here, you might want to see what files are available by default. +From here, you might want to see what files, plugins, and profiles that are available by default. ```bash # list the files in the root directory @@ -60,7 +60,7 @@ makeshift list profiles makeshift list profiles default ``` -Then, we can start downloading some files or directories (as archives). +Then, we can start downloading some files or directories (as archives) both with and without running plugins. ```bash # download all data (notice --host and --port are not set here) @@ -158,7 +158,7 @@ type Example struct{} func (p *Example) Name() string { return "example" } func (p *Example) Version() string { return "v0.0.1-alpha" } func (p *Example) Description() string { return "An example plugin" } -func (p *Example) Metadata() map[string]string { +func (p *Example) Metadata() map[string]any { return makeshift.Metadata{ "author": map[string]any{ "name": "John Smith", diff --git a/cmd/download.go b/cmd/download.go index 03bf061..0111b53 100644 --- a/cmd/download.go +++ b/cmd/download.go @@ -9,11 +9,16 @@ import ( "strings" "git.towk2.me/towk/makeshift/internal/archive" + "git.towk2.me/towk/makeshift/internal/kwargs" "git.towk2.me/towk/makeshift/pkg/client" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) +var ( + pluginArgs []string + pluginKWArgs kwargs.KWArgs = kwargs.KWArgs{} +) var downloadCmd = cobra.Command{ Use: "download", Example: ` @@ -64,6 +69,12 @@ var downloadCmd = cobra.Command{ if len(profileIDs) > 0 { query += "&profiles=" + url.QueryEscape(strings.Join(profileIDs, ",")) } + if len(pluginArgs) > 0 { + query += "&args=" + url.QueryEscape(strings.Join(pluginArgs, ",")) + } + if len(pluginKWArgs) > 0 { + query += "&kwargs=" + url.QueryEscape(pluginKWArgs.String()) + } log.Debug(). Str("host", host). @@ -287,6 +298,8 @@ func init() { downloadCmd.Flags().StringP("path", "p", ".", "Set the path to list files (can be set with MAKESHIFT_PATH)") downloadCmd.Flags().StringSlice("profiles", []string{}, "Set the profile(s) to use to populate data store") downloadCmd.Flags().StringSlice("plugins", []string{}, "Set the plugin(s) to run before downloading files") + downloadCmd.Flags().StringSlice("plugin-args", []string{}, "Set the argument list to pass to plugin(s)") + downloadCmd.Flags().Var(&pluginKWArgs, "plugin-kwargs", "Set the argument map to pass to plugin(s)") downloadCmd.Flags().BoolP("extract", "x", false, "Set whether to extract archive locally after downloading") downloadCmd.Flags().BoolP("remove-archive", "r", false, "Set whether to remove the archive after extracting (used with '--extract' flag)") diff --git a/internal/format/format.go b/internal/format/format.go index b753268..bdbfea0 100644 --- a/internal/format/format.go +++ b/internal/format/format.go @@ -36,11 +36,11 @@ func (df DataFormat) Type() string { return "DataFormat" } -// MarshalData marshals arbitrary data into a byte slice formatted as outFormat. +// Marshal marshals arbitrary data into a byte slice formatted as outFormat. // If a marshalling error occurs or outFormat is unknown, an error is returned. // // Supported values are: json, list, yaml -func Marshal(data interface{}, outFormat DataFormat) ([]byte, error) { +func Marshal(data any, outFormat DataFormat) ([]byte, error) { switch outFormat { case JSON: if bytes, err := json.MarshalIndent(data, "", " "); err != nil { @@ -61,12 +61,12 @@ func Marshal(data interface{}, outFormat DataFormat) ([]byte, error) { } } -// UnmarshalData unmarshals a byte slice formatted as inFormat into an interface +// Unmarshal unmarshals a byte slice formatted as inFormat into an interface // v. If an unmarshalling error occurs or inFormat is unknown, an error is // returned. // // Supported values are: json, list, yaml -func Unmarshal(data []byte, v interface{}, inFormat DataFormat) error { +func Unmarshal(data []byte, v any, inFormat DataFormat) error { switch inFormat { case JSON: if err := json.Unmarshal(data, v); err != nil { diff --git a/internal/kwargs/kwargs.go b/internal/kwargs/kwargs.go new file mode 100644 index 0000000..1da80bd --- /dev/null +++ b/internal/kwargs/kwargs.go @@ -0,0 +1,34 @@ +package kwargs + +import ( + "encoding/json" + "fmt" + + "git.towk2.me/towk/makeshift/internal/format" +) + +const RESERVED_KEY = "kwargs" + +type KWArgs map[string]any + +func (kw KWArgs) String() string { + b, _ := json.Marshal(kw) + return string(b) +} + +func (kw *KWArgs) Set(v string /* should be JSON object*/) error { + var ( + newArgs KWArgs + err error + ) + err = format.Unmarshal([]byte(v), &newArgs, format.JSON) + if err != nil { + return fmt.Errorf("failed to unmarshal value for %s: %w", kw.Type(), err) + } + *kw = newArgs + return nil +} + +func (kw *KWArgs) Type() string { + return "KWArgs" +} diff --git a/pkg/plugins/mapper/mapper.go b/pkg/plugins/mapper/mapper.go index 1fded1f..66b4a5d 100644 --- a/pkg/plugins/mapper/mapper.go +++ b/pkg/plugins/mapper/mapper.go @@ -1,16 +1,25 @@ package main -import "git.towk2.me/towk/makeshift/pkg/storage" +import ( + makeshift "git.towk2.me/towk/makeshift/pkg" + "git.towk2.me/towk/makeshift/pkg/storage" +) type Mapper struct{} -func (p *Mapper) Name() string { return "jinja2" } -func (p *Mapper) Version() string { return "test" } -func (p *Mapper) Description() string { return "Renders Jinja 2 templates" } -func (p *Mapper) Metadata() map[string]string { - return map[string]string{ - "author.name": "David J. Allen", - "author.email": "davidallendj@gmail.com", +func (p *Mapper) Name() string { return "mapper" } +func (p *Mapper) Version() string { return "v0.0.1-alpha" } +func (p *Mapper) Description() string { return "Directly maps data to store" } +func (p *Mapper) Metadata() makeshift.Metadata { + return makeshift.Metadata{ + "author": map[string]any{ + "name": "David J. Allen", + "email": "davidallendj@gmail.com", + "links": []string{ + "https://github.com/davidallendj", + "https://git.towk2.me/towk", + }, + }, } } diff --git a/pkg/plugins/user/user.go b/pkg/plugins/user/user.go new file mode 100644 index 0000000..ff59640 --- /dev/null +++ b/pkg/plugins/user/user.go @@ -0,0 +1,36 @@ +package main + +import ( + makeshift "git.towk2.me/towk/makeshift/pkg" + "git.towk2.me/towk/makeshift/pkg/storage" +) + +type User struct{} + +func (p *User) Name() string { return "user" } +func (p *User) Version() string { return "v0.0.1-alpha" } +func (p *User) Description() string { return "Get user information" } +func (p *User) Metadata() makeshift.Metadata { + return makeshift.Metadata{ + "author": map[string]any{ + "name": "David J. Allen", + "email": "davidallendj@gmail.com", + "links": []string{ + "https://github.com/davidallendj", + "https://git.towk2.me/towk", + }, + }, + } +} + +func (p *User) Init() error { + return nil +} + +func (p *User) Run(store storage.KVStore, args []string) error { + return nil +} + +func (p *User) Cleanup() error { + return nil +} diff --git a/pkg/service/routes.go b/pkg/service/routes.go index 7d371c9..555c115 100644 --- a/pkg/service/routes.go +++ b/pkg/service/routes.go @@ -11,18 +11,23 @@ import ( "strings" "git.towk2.me/towk/makeshift/internal/archive" + "git.towk2.me/towk/makeshift/internal/kwargs" makeshift "git.towk2.me/towk/makeshift/pkg" "git.towk2.me/towk/makeshift/pkg/storage" + "github.com/go-chi/chi/v5" "github.com/rs/zerolog/log" ) func (s *Service) Download() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var ( - path = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/download") - pluginNames = strings.Split(r.URL.Query().Get("plugins"), ",") - profileIDs = strings.Split(r.URL.Query().Get("profiles"), ",") + path = s.PathForData() + strings.TrimPrefix(r.URL.Path, "/download") + pluginKWArgs = chi.URLParam(r, "kwargs") + pluginArgs = strings.Split(r.URL.Query().Get("args"), ",") + pluginNames = strings.Split(r.URL.Query().Get("plugins"), ",") + profileIDs = strings.Split(r.URL.Query().Get("profiles"), ",") + kw *kwargs.KWArgs fileInfo os.FileInfo out *os.File store *storage.MemoryStorage = new(storage.MemoryStorage) @@ -32,8 +37,12 @@ func (s *Service) Download() http.HandlerFunc { err error ) + // parse the KWArgs from request + kw.Set(pluginKWArgs) + // initialize storage store.Init() + store.SetKWArgs(kw) log.Debug(). Str("path", path). @@ -78,7 +87,7 @@ func (s *Service) Download() http.HandlerFunc { log.Debug().Strs("files", filenamesToArchive).Send() // prepare plugins - hooks, errs = s.loadPlugins(pluginNames, store, nil, errs) + hooks, errs = s.loadPlugins(pluginNames, store, pluginArgs, errs) if len(errs) > 0 { log.Error().Errs("errs", errs).Msg("errors occurred loading plugins") errs = []error{} diff --git a/pkg/storage/disk.go b/pkg/storage/disk.go index 46d3f1b..f464056 100644 --- a/pkg/storage/disk.go +++ b/pkg/storage/disk.go @@ -1,5 +1,7 @@ package storage +import "git.towk2.me/towk/makeshift/internal/kwargs" + type DiskStorage struct{} func (ds DiskStorage) Init() error { @@ -10,8 +12,17 @@ func (ds DiskStorage) Cleanup() error { return nil } -func (ds DiskStorage) Get(k string) error { - return nil +func (ds *DiskStorage) SetKWArgs(kw *kwargs.KWArgs) error { + return ds.Set(kwargs.RESERVED_KEY, kw) +} + +func (ds *DiskStorage) GetKWArgs() (*kwargs.KWArgs, error) { + kw, err := ds.Get(kwargs.RESERVED_KEY) + return kw.(*kwargs.KWArgs), err +} + +func (ds DiskStorage) Get(k string) (any, error) { + return nil, nil } func (ds DiskStorage) Set(k string, v any) error { diff --git a/pkg/storage/memory.go b/pkg/storage/memory.go index e554fbd..a3b1abb 100644 --- a/pkg/storage/memory.go +++ b/pkg/storage/memory.go @@ -1,6 +1,10 @@ package storage -import "fmt" +import ( + "fmt" + + "git.towk2.me/towk/makeshift/internal/kwargs" +) type MemoryStorage struct { Data map[string]any `json:"data"` @@ -15,6 +19,15 @@ func (ms *MemoryStorage) Cleanup() error { return nil } +func (ms *MemoryStorage) SetKWArgs(kw *kwargs.KWArgs) error { + return ms.Set(kwargs.RESERVED_KEY, kw) +} + +func (ms *MemoryStorage) GetKWArgs() (*kwargs.KWArgs, error) { + kw, err := ms.Get(kwargs.RESERVED_KEY) + return kw.(*kwargs.KWArgs), err +} + func (ms *MemoryStorage) Get(k string) (any, error) { v, ok := ms.Data[k] if ok { @@ -24,6 +37,9 @@ func (ms *MemoryStorage) Get(k string) (any, error) { } func (ms *MemoryStorage) Set(k string, v any) error { + if k == "kwargs" { + return fmt.Errorf("cannot set reserved key '%s' (use SetKWArgs() instead)", k) + } ms.Data[k] = v return nil } diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index 3bc9877..82908f6 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -1,9 +1,14 @@ package storage +import "git.towk2.me/towk/makeshift/internal/kwargs" + type KVStore interface { Init() error Cleanup() error + SetKWArgs(kwargs *kwargs.KWArgs) error + GetKWArgs() (*kwargs.KWArgs, error) + Get(k string) (any, error) Set(k string, v any) error GetData() any