Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmd/nsc/cmd/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"namespacelabs.dev/foundation/internal/cli/cmd/admin"
"namespacelabs.dev/foundation/internal/cli/cmd/auth"
"namespacelabs.dev/foundation/internal/cli/cmd/aws"
"namespacelabs.dev/foundation/internal/cli/cmd/cache"
"namespacelabs.dev/foundation/internal/cli/cmd/cluster"
"namespacelabs.dev/foundation/internal/cli/cmd/cluster/baseimage"
"namespacelabs.dev/foundation/internal/cli/cmd/cluster/github"
Expand All @@ -30,6 +31,8 @@ func RegisterCommands(root *cobra.Command) {

root.AddCommand(version.NewVersionCmd())

root.AddCommand(cache.NewCacheCmd()) // nsc cache

root.AddCommand(cluster.NewBareClusterCmd("instance", false))
root.AddCommand(cluster.NewBareClusterCmd("cluster", true)) // backwards compatibility
root.AddCommand(cluster.NewExtendDurationCmd("extend")) // nsc extend
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ require (
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.7
github.com/spf13/viper v1.14.0
github.com/stretchr/testify v1.11.0
github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a
github.com/tonistiigi/fsutil v0.0.0-20250605211040-586307ad452f
go.lsp.dev/jsonrpc2 v0.10.0
Expand Down
23 changes: 23 additions & 0 deletions internal/cache/mode/apt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package mode

import "context"

type AptProvider struct{}

func (g AptProvider) List() []string {
return []string{
"apt",
}
}

func (g AptProvider) Mode(ctx context.Context, mode string) (Result, error) {
return Result{
// TODO
}, nil
}

func (g AptProvider) Detect(ctx context.Context, dir, mode string) (Result, error) {
return Result{
// TODO
}, nil
}
28 changes: 28 additions & 0 deletions internal/cache/mode/golang.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package mode

import "context"

type GoProvider struct{}

func (g GoProvider) List() []string {
return []string{
"go",
"golangci-lint",
}
}

func (g GoProvider) Mode(ctx context.Context, mode string) (Result, error) {
return Result{
Paths: []string{
"/some/dir",
},
}, nil
}

func (g GoProvider) Detect(ctx context.Context, dir, mode string) (Result, error) {
return Result{
Paths: []string{
"/some/dir",
},
}, nil
}
131 changes: 131 additions & 0 deletions internal/cache/mode/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package mode

import (
"context"
"fmt"
"slices"
"sync"

"golang.org/x/sync/errgroup"
)

func DefaultProviders() Providers {
return Providers{
AptProvider{},
GoProvider{},
}
}

type UnknownModeError struct {
Mode string
}

func (e UnknownModeError) Error() string {
return "unknown cache mode: " + e.Mode
}

// Provider knows how to provide cache paths for specific modes.
type Provider interface {
List() []string
Mode(ctx context.Context, mode string) (Result, error)
Detect(ctx context.Context, dir, mode string) (Result, error)
}

type Result struct {
Paths []string `json:"paths"`
}

type Providers []Provider

func (ps Providers) List() []string {
modes := make([]string, 0, len(ps)*2)
for _, p := range ps {
modes = append(modes, p.List()...)
}
slices.Sort(modes)
return modes
}

func (ps Providers) Mode(ctx context.Context, filter ...string) (map[string]Result, error) {
var m sync.Mutex
results := make(map[string]Result, len(ps)*2)

eg, ctx := errgroup.WithContext(ctx)
for _, provider := range ps {
for _, mode := range provider.List() {
switch {
case len(filter) == 0:
case slices.Contains(filter, mode):
default:
continue
}

eg.Go(func() error {
result, err := provider.Mode(ctx, mode)
if err != nil {
return fmt.Errorf("looking up `%s` mode: %w", mode, err)
}
if len(result.Paths) > 0 {
m.Lock()
results[mode] = result
m.Unlock()
}
return nil
})
}
}

if err := eg.Wait(); err != nil {
return nil, err
}

for _, mode := range filter {
if _, ok := results[mode]; !ok {
return nil, UnknownModeError{Mode: mode}
}
}

return results, nil
}

func (ps Providers) Detect(ctx context.Context, dir string, filter ...string) (map[string]Result, error) {
var m sync.Mutex
results := make(map[string]Result, len(ps)*2)

eg, ctx := errgroup.WithContext(ctx)
for _, provider := range ps {
for _, mode := range provider.List() {
switch {
case len(filter) == 0:
case slices.Contains(filter, mode):
default:
continue
}

eg.Go(func() error {
result, err := provider.Detect(ctx, dir, mode)
if err != nil {
return fmt.Errorf("looking up `%s` mode: %w", mode, err)
}
if len(result.Paths) > 0 {
m.Lock()
results[mode] = result
m.Unlock()
}
return nil
})
}
}

if err := eg.Wait(); err != nil {
return nil, err
}

for _, mode := range filter {
if _, ok := results[mode]; !ok {
return nil, UnknownModeError{Mode: mode}
}
}

return results, nil
}
Loading
Loading