From 43956e38cc6e701bb2a384f514a14d1fe75c6695 Mon Sep 17 00:00:00 2001 From: Andrea Luzzardi Date: Wed, 24 Mar 2021 18:07:52 -0700 Subject: [PATCH] separate Store from State Signed-off-by: Andrea Luzzardi --- cmd/dagger/cmd/compute.go | 10 +-- cmd/dagger/cmd/down.go | 2 +- cmd/dagger/cmd/query.go | 2 +- cmd/dagger/cmd/up.go | 2 +- dagger/route.go | 34 ++++++++++ dagger/state.go | 132 -------------------------------------- dagger/store.go | 103 +++++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 140 deletions(-) delete mode 100644 dagger/state.go create mode 100644 dagger/store.go diff --git a/cmd/dagger/cmd/compute.go b/cmd/dagger/cmd/compute.go index 1559cd92..d5149ce3 100644 --- a/cmd/dagger/cmd/compute.go +++ b/cmd/dagger/cmd/compute.go @@ -42,7 +42,7 @@ var computeCmd = &cobra.Command{ for _, input := range viper.GetStringSlice("input-string") { parts := strings.SplitN(input, "=", 2) k, v := parts[0], parts[1] - err := st.AddInput(ctx, k, dagger.TextInput(v)) + err := st.AddInput(k, dagger.TextInput(v)) if err != nil { lg.Fatal().Err(err).Str("input", k).Msg("failed to add input") } @@ -51,7 +51,7 @@ var computeCmd = &cobra.Command{ for _, input := range viper.GetStringSlice("input-dir") { parts := strings.SplitN(input, "=", 2) k, v := parts[0], parts[1] - err := st.AddInput(ctx, k, dagger.DirInput(v, []string{})) + err := st.AddInput(k, dagger.DirInput(v, []string{})) if err != nil { lg.Fatal().Err(err).Str("input", k).Msg("failed to add input") } @@ -60,7 +60,7 @@ var computeCmd = &cobra.Command{ for _, input := range viper.GetStringSlice("input-git") { parts := strings.SplitN(input, "=", 2) k, v := parts[0], parts[1] - err := st.AddInput(ctx, k, dagger.GitInput(v, "", "")) + err := st.AddInput(k, dagger.GitInput(v, "", "")) if err != nil { lg.Fatal().Err(err).Str("input", k).Msg("failed to add input") } @@ -87,7 +87,7 @@ var computeCmd = &cobra.Command{ lg.Fatal().Msg("invalid json") } - err = st.AddInput(ctx, "", dagger.JSONInput(string(content))) + err = st.AddInput("", dagger.JSONInput(string(content))) if err != nil { lg.Fatal().Err(err).Msg("failed to add input") } @@ -110,7 +110,7 @@ var computeCmd = &cobra.Command{ content = plaintext } - err = st.AddInput(ctx, "", dagger.YAMLInput(string(content))) + err = st.AddInput("", dagger.YAMLInput(string(content))) if err != nil { lg.Fatal().Err(err).Msg("failed to add input") } diff --git a/cmd/dagger/cmd/down.go b/cmd/dagger/cmd/down.go index 64e7f692..097a194f 100644 --- a/cmd/dagger/cmd/down.go +++ b/cmd/dagger/cmd/down.go @@ -26,7 +26,7 @@ var downCmd = &cobra.Command{ ctx := lg.WithContext(cmd.Context()) routeName := getRouteName(lg, cmd) - route, err := dagger.LookupRoute(routeName, nil) + route, err := dagger.LookupRoute(ctx, routeName, nil) if err != nil { lg.Fatal().Err(err).Str("route-name", routeName).Msg("failed to lookup route") } diff --git a/cmd/dagger/cmd/query.go b/cmd/dagger/cmd/query.go index 91b0775a..ffe52f70 100644 --- a/cmd/dagger/cmd/query.go +++ b/cmd/dagger/cmd/query.go @@ -27,7 +27,7 @@ var queryCmd = &cobra.Command{ ctx := lg.WithContext(cmd.Context()) routeName := getRouteName(lg, cmd) - route, err := dagger.LookupRoute(routeName, nil) + route, err := dagger.LookupRoute(ctx, routeName, nil) if err != nil { lg.Fatal().Err(err).Str("route-name", routeName).Msg("failed to lookup route") } diff --git a/cmd/dagger/cmd/up.go b/cmd/dagger/cmd/up.go index ded638a0..f41ec94d 100644 --- a/cmd/dagger/cmd/up.go +++ b/cmd/dagger/cmd/up.go @@ -26,7 +26,7 @@ var upCmd = &cobra.Command{ ctx := lg.WithContext(cmd.Context()) routeName := getRouteName(lg, cmd) - route, err := dagger.LookupRoute(routeName, nil) + route, err := dagger.LookupRoute(ctx, routeName, nil) if err != nil { lg.Fatal().Err(err).Str("route-name", routeName).Msg("failed to lookup route") } diff --git a/dagger/route.go b/dagger/route.go index a97e55b4..666d0daf 100644 --- a/dagger/route.go +++ b/dagger/route.go @@ -19,6 +19,40 @@ import ( "github.com/rs/zerolog/log" ) +// Contents of a route serialized to a file +type RouteState struct { + // Globally unique route ID + ID string `json:"id,omitempty"` + + // Human-friendly route name. + // A route may have more than one name. + // FIXME: store multiple names? + Name string `json:"name,omitempty"` + + // Cue module containing the route layout + // The input's top-level artifact is used as a module directory. + LayoutSource Input `json:"layout,omitempty"` + + Inputs []inputKV `json:"inputs,omitempty"` +} + +type inputKV struct { + Key string `json:"key,omitempty"` + Value Input `json:"value,omitempty"` +} + +func (r *RouteState) AddInput(key string, value Input) error { + r.Inputs = append(r.Inputs, inputKV{Key: key, Value: value}) + return nil +} + +// Remove all inputs at the given key, including sub-keys. +// For example RemoveInputs("foo.bar") will remove all inputs +// at foo.bar, foo.bar.baz, etc. +func (r *RouteState) RemoveInputs(key string) error { + panic("NOT IMPLEMENTED") +} + type Route struct { st *RouteState diff --git a/dagger/state.go b/dagger/state.go deleted file mode 100644 index 74dfa87c..00000000 --- a/dagger/state.go +++ /dev/null @@ -1,132 +0,0 @@ -package dagger - -import ( - "context" - "encoding/json" - "errors" - "os" - "path" - - "github.com/google/uuid" -) - -const ( - routeLocation = "$HOME/.config/dagger/routes" -) - -// Contents of a route serialized to a file -type RouteState struct { - // Globally unique route ID - ID string `json:"id,omitempty"` - - // Human-friendly route name. - // A route may have more than one name. - // FIXME: store multiple names? - Name string `json:"name,omitempty"` - - // Cue module containing the route layout - // The input's top-level artifact is used as a module directory. - LayoutSource Input `json:"layout,omitempty"` - - Inputs []inputKV `json:"inputs,omitempty"` -} - -type inputKV struct { - Key string `json:"key,omitempty"` - Value Input `json:"value,omitempty"` -} - -func (r *RouteState) SetLayoutSource(ctx context.Context, src Input) error { - r.LayoutSource = src - return nil -} - -func (r *RouteState) AddInput(ctx context.Context, key string, value Input) error { - r.Inputs = append(r.Inputs, inputKV{Key: key, Value: value}) - return nil -} - -// Remove all inputs at the given key, including sub-keys. -// For example RemoveInputs("foo.bar") will remove all inputs -// at foo.bar, foo.bar.baz, etc. -func (r *RouteState) RemoveInputs(ctx context.Context, key string) error { - panic("NOT IMPLEMENTED") -} - -func routePath(name string) string { - return path.Join(os.ExpandEnv(routeLocation), name+".json") -} - -func syncRoute(r *Route) error { - p := routePath(r.st.Name) - - if err := os.MkdirAll(path.Dir(p), 0755); err != nil { - return err - } - - data, err := json.MarshalIndent(r.st, "", " ") - if err != nil { - return err - } - - return os.WriteFile(p, data, 0644) -} - -func loadRoute(name string) (*RouteState, error) { - data, err := os.ReadFile(routePath(name)) - if err != nil { - return nil, err - } - var st *RouteState - if err := json.Unmarshal(data, st); err != nil { - return nil, err - } - return st, nil -} - -func CreateRoute(ctx context.Context, name string, o *CreateOpts) (*Route, error) { - r, err := LookupRoute(name, &LookupOpts{}) - if err != nil && !errors.Is(err, os.ErrNotExist) { - return nil, err - } - if r != nil { - return nil, os.ErrExist - } - r, err = NewRoute( - &RouteState{ - ID: uuid.New().String(), - Name: name, - }, - ) - if err != nil { - return nil, err - } - - return r, syncRoute(r) -} - -type CreateOpts struct{} - -func DeleteRoute(ctx context.Context, o *DeleteOpts) (*Route, error) { - panic("NOT IMPLEMENTED") -} - -type DeleteOpts struct{} - -func LookupRoute(name string, o *LookupOpts) (*Route, error) { - st, err := loadRoute(name) - if err != nil { - return nil, err - } - return &Route{ - st: st, - }, nil -} - -type LookupOpts struct{} - -func LoadRoute(ctx context.Context, id string, o *LoadOpts) (*Route, error) { - panic("NOT IMPLEMENTED") -} - -type LoadOpts struct{} diff --git a/dagger/store.go b/dagger/store.go new file mode 100644 index 00000000..9bcfffbf --- /dev/null +++ b/dagger/store.go @@ -0,0 +1,103 @@ +package dagger + +import ( + "context" + "encoding/json" + "errors" + "os" + "path" + + "github.com/google/uuid" +) + +const ( + storeLocation = "$HOME/.config/dagger/routes" +) + +type CreateOpts struct{} + +func CreateRoute(ctx context.Context, name string, o *CreateOpts) (*Route, error) { + r, err := LookupRoute(ctx, name, &LookupOpts{}) + if err != nil && !errors.Is(err, os.ErrNotExist) { + return nil, err + } + if r != nil { + return nil, os.ErrExist + } + r, err = NewRoute( + &RouteState{ + ID: uuid.New().String(), + Name: name, + }, + ) + if err != nil { + return nil, err + } + + return r, syncRoute(r) +} + +type UpdateOpts struct{} + +func UpdateRoute(ctx context.Context, r *Route, o *UpdateOpts) error { + return syncRoute(r) +} + +type DeleteOpts struct{} + +func DeleteRoute(ctx context.Context, r *Route, o *DeleteOpts) error { + return deleteRoute(r) +} + +type LookupOpts struct{} + +func LookupRoute(ctx context.Context, name string, o *LookupOpts) (*Route, error) { + st, err := loadRoute(name) + if err != nil { + return nil, err + } + return &Route{ + st: st, + }, nil +} + +type LoadOpts struct{} + +func LoadRoute(ctx context.Context, id string, o *LoadOpts) (*Route, error) { + panic("NOT IMPLEMENTED") +} + +func routePath(name string) string { + return path.Join(os.ExpandEnv(storeLocation), name+".json") +} + +func syncRoute(r *Route) error { + p := routePath(r.st.Name) + + if err := os.MkdirAll(path.Dir(p), 0755); err != nil { + return err + } + + data, err := json.MarshalIndent(r.st, "", " ") + if err != nil { + return err + } + + return os.WriteFile(p, data, 0644) +} + +func deleteRoute(r *Route) error { + return os.Remove(routePath(r.st.Name)) +} + +func loadRoute(name string) (*RouteState, error) { + data, err := os.ReadFile(routePath(name)) + if err != nil { + return nil, err + } + var st *RouteState + if err := json.Unmarshal(data, st); err != nil { + return nil, err + } + return st, nil +}