diff --git a/cmd/dagger/cmd/down.go b/cmd/dagger/cmd/down.go index 097a194f..c88df0e3 100644 --- a/cmd/dagger/cmd/down.go +++ b/cmd/dagger/cmd/down.go @@ -22,11 +22,11 @@ var downCmd = &cobra.Command{ }, Run: func(cmd *cobra.Command, args []string) { lg := logger.New() - // nolint:staticcheck ctx := lg.WithContext(cmd.Context()) + store := dagger.DefaultStore() routeName := getRouteName(lg, cmd) - route, err := dagger.LookupRoute(ctx, routeName, nil) + route, err := store.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/list.go b/cmd/dagger/cmd/list.go index 4df40908..bb3b02bb 100644 --- a/cmd/dagger/cmd/list.go +++ b/cmd/dagger/cmd/list.go @@ -23,8 +23,9 @@ var listCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { lg := logger.New() ctx := lg.WithContext(cmd.Context()) + store := dagger.DefaultStore() - routes, err := dagger.ListRoutes(ctx) + routes, err := store.ListRoutes(ctx) if err != nil { lg.Fatal().Err(err).Msg("cannot list routes") } diff --git a/cmd/dagger/cmd/new.go b/cmd/dagger/cmd/new.go index 6368f1d6..21409d68 100644 --- a/cmd/dagger/cmd/new.go +++ b/cmd/dagger/cmd/new.go @@ -22,18 +22,17 @@ var newCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { lg := logger.New() ctx := lg.WithContext(cmd.Context()) + store := dagger.DefaultStore() - // nolint:staticcheck upRouteFlag, err := cmd.Flags().GetBool("up") if err != nil { lg.Fatal().Err(err).Str("flag", "up").Msg("unable to resolve flag") } - // nolint:staticcheck routeName := getRouteName(lg, cmd) // TODO: Implement options: --layout-*, --setup - route, err := dagger.CreateRoute(ctx, routeName, nil) + route, err := store.CreateRoute(ctx, routeName, nil) if err != nil { lg.Fatal().Err(err).Msg("failed to create route") } diff --git a/cmd/dagger/cmd/query.go b/cmd/dagger/cmd/query.go index ffe52f70..58f485ce 100644 --- a/cmd/dagger/cmd/query.go +++ b/cmd/dagger/cmd/query.go @@ -23,11 +23,11 @@ var queryCmd = &cobra.Command{ }, Run: func(cmd *cobra.Command, args []string) { lg := logger.New() - // nolint:staticcheck ctx := lg.WithContext(cmd.Context()) + store := dagger.DefaultStore() routeName := getRouteName(lg, cmd) - route, err := dagger.LookupRoute(ctx, routeName, nil) + route, err := store.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 9464eb86..2d4c972a 100644 --- a/cmd/dagger/cmd/up.go +++ b/cmd/dagger/cmd/up.go @@ -22,11 +22,11 @@ var upCmd = &cobra.Command{ }, Run: func(cmd *cobra.Command, args []string) { lg := logger.New() - // nolint:staticcheck ctx := lg.WithContext(cmd.Context()) + store := dagger.DefaultStore() routeName := getRouteName(lg, cmd) - route, err := dagger.LookupRoute(ctx, routeName, nil) + route, err := store.LookupRoute(ctx, routeName, nil) if err != nil { lg.Fatal().Err(err).Str("route-name", routeName).Msg("failed to lookup route") } diff --git a/dagger/store.go b/dagger/store.go index b52467de..2eab5963 100644 --- a/dagger/store.go +++ b/dagger/store.go @@ -4,22 +4,35 @@ import ( "context" "encoding/json" "errors" - "io/ioutil" "os" "path" - "strings" + "path/filepath" "github.com/google/uuid" ) const ( - storeLocation = "$HOME/.config/dagger/routes" + defaultStoreRoot = "$HOME/.config/dagger/routes" ) +type Store struct { + root string +} + +func NewStore(root string) *Store { + return &Store{ + root: root, + } +} + +func DefaultStore() *Store { + return NewStore(os.ExpandEnv(defaultStoreRoot)) +} + type CreateOpts struct{} -func CreateRoute(ctx context.Context, name string, o *CreateOpts) (*Route, error) { - r, err := LookupRoute(ctx, name, &LookupOpts{}) +func (s *Store) CreateRoute(ctx context.Context, name string, o *CreateOpts) (*Route, error) { + r, err := s.LookupRoute(ctx, name, &LookupOpts{}) if err != nil && !errors.Is(err, os.ErrNotExist) { return nil, err } @@ -36,50 +49,53 @@ func CreateRoute(ctx context.Context, name string, o *CreateOpts) (*Route, error return nil, err } - return r, syncRoute(r) + return r, s.syncRoute(r) } type UpdateOpts struct{} -func UpdateRoute(ctx context.Context, r *Route, o *UpdateOpts) error { - return syncRoute(r) +func (s *Store) UpdateRoute(ctx context.Context, r *Route, o *UpdateOpts) error { + return s.syncRoute(r) } type DeleteOpts struct{} -func DeleteRoute(ctx context.Context, r *Route, o *DeleteOpts) error { - return deleteRoute(r) +func (s *Store) DeleteRoute(ctx context.Context, r *Route, o *DeleteOpts) error { + return os.Remove(s.routePath(r.st.Name)) } type LookupOpts struct{} -func LookupRoute(ctx context.Context, name string, o *LookupOpts) (*Route, error) { - st, err := loadRoute(name) +func (s *Store) LookupRoute(ctx context.Context, name string, o *LookupOpts) (*Route, error) { + data, err := os.ReadFile(s.routePath(name)) if err != nil { return nil, err } + var st RouteState + if err := json.Unmarshal(data, &st); err != nil { + return nil, err + } return &Route{ - st: st, + st: &st, }, nil } type LoadOpts struct{} -func LoadRoute(ctx context.Context, id string, o *LoadOpts) (*Route, error) { +func (s *Store) LoadRoute(ctx context.Context, id string, o *LoadOpts) (*Route, error) { panic("NOT IMPLEMENTED") } -func ListRoutes(ctx context.Context) ([]string, error) { +func (s *Store) ListRoutes(ctx context.Context) ([]string, error) { routes := []string{} - rootDir := os.ExpandEnv(storeLocation) - files, err := ioutil.ReadDir(rootDir) + files, err := os.ReadDir(s.root) if err != nil { return nil, err } for _, f := range files { - if f.IsDir() || !strings.HasSuffix(f.Name(), ".json") { + if f.IsDir() || filepath.Ext(f.Name()) != ".json" { // There is extra data in the directory, ignore continue } @@ -89,12 +105,12 @@ func ListRoutes(ctx context.Context) ([]string, error) { return routes, nil } -func routePath(name string) string { - return path.Join(os.ExpandEnv(storeLocation), name+".json") +func (s *Store) routePath(name string) string { + return path.Join(s.root, name+".json") } -func syncRoute(r *Route) error { - p := routePath(r.st.Name) +func (s *Store) syncRoute(r *Route) error { + p := s.routePath(r.st.Name) if err := os.MkdirAll(path.Dir(p), 0755); err != nil { return err @@ -107,19 +123,3 @@ func syncRoute(r *Route) error { 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 -} diff --git a/dagger/store_test.go b/dagger/store_test.go new file mode 100644 index 00000000..c6d3d3b6 --- /dev/null +++ b/dagger/store_test.go @@ -0,0 +1,37 @@ +package dagger + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestStore(t *testing.T) { + ctx := context.TODO() + + root, err := os.MkdirTemp(os.TempDir(), "dagger-*") + require.NoError(t, err) + store := NewStore(root) + + _, err = store.LookupRoute(ctx, "notexist", nil) + require.Error(t, err) + require.True(t, errors.Is(err, os.ErrNotExist)) + + r, err := store.CreateRoute(ctx, "test", nil) + require.NoError(t, err) + require.NotNil(t, r) + require.Equal(t, "test", r.Name()) + + r, err = store.LookupRoute(ctx, "test", nil) + require.NoError(t, err) + require.NotNil(t, r) + require.Equal(t, "test", r.Name()) + + routes, err := store.ListRoutes(ctx) + require.NoError(t, err) + require.Len(t, routes, 1) + require.Equal(t, "test", routes[0]) +} diff --git a/examples/react-netlify/main.cue b/examples/react-netlify/main.cue index 9ccb8d05..f925acd6 100644 --- a/examples/react-netlify/main.cue +++ b/examples/react-netlify/main.cue @@ -25,6 +25,5 @@ todoApp: netlify.#Site & { contents: yarn.#Script & { source: repository run: "build" - env: "xx" :"bar" } }