Skip to content
Open
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
6 changes: 6 additions & 0 deletions cli/cmd/cache_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ import (
"context"

"github.com/pkg/errors"
replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
"github.com/replicatedhq/replicated/pkg/kotsclient"
"github.com/replicatedhq/replicated/pkg/types"
)

func getApp(appSlugOrID string, kotsClient *kotsclient.VendorV3Client) (*types.App, error) {
cache, err := replicatedcache.GetInstance()
if err != nil {
return nil, errors.Wrap(err, "initialize cache")
}

app, err := cache.GetApp(appSlugOrID)
if err == nil && app != nil {
return app, nil
Expand Down
35 changes: 35 additions & 0 deletions cli/cmd/completion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,46 @@ package cmd

import (
"bytes"
"os"
"testing"

replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
"github.com/spf13/cobra"
)

// TestShellCompletionsNoHome verifies that completion commands work even when
// HOME is unset or invalid (e.g., during Nix builds). This is a regression
// test for https://github.com/replicatedhq/replicated/issues/535.
func TestShellCompletionsNoHome(t *testing.T) {
// Save and clear HOME to simulate an environment where cache initialization
// would fail.
origHome := os.Getenv("HOME")
os.Unsetenv("HOME")
os.Unsetenv("XDG_CACHE_HOME")
defer func() {
os.Setenv("HOME", origHome)
}()

// Reset the lazy cache state so this test doesn't interfere with others.
replicatedcache.ResetForTesting()
defer replicatedcache.ResetForTesting()

parentCmd := &cobra.Command{
Use: "replicated",
}
out := bytes.NewBufferString("")
cmd := NewCmdCompletion(out, parentCmd.Name())
parentCmd.AddCommand(cmd)

err := RunCompletion(out, cmd, []string{"bash"})
if err != nil {
t.Fatalf("Unexpected error with no HOME: %v", err)
}
if out.Len() == 0 {
t.Fatalf("Output was not written")
}
}

// This unit-test was adapted from kubectl repo
// Link: https://github.com/kubernetes/kubectl/blob/826006cdb947f80a679ff1eb3cb53f183a6a9bf2/pkg/cmd/completion/completion_test.go
func TestShellCompletions(t *testing.T) {
Expand Down
6 changes: 6 additions & 0 deletions cli/cmd/default_clear.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"github.com/pkg/errors"
replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -29,6 +30,11 @@ replicated default clear app`,
}

func (r *runners) clearDefault(cmd *cobra.Command, defaultType string) error {
cache, err := replicatedcache.GetInstance()
if err != nil {
return errors.Wrap(err, "initialize cache")
}

if err := cache.ClearDefault(defaultType); err != nil {
return errors.Wrap(err, "clear default")
}
Expand Down
11 changes: 10 additions & 1 deletion cli/cmd/default_clearall.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package cmd

import "github.com/spf13/cobra"
import (
"github.com/pkg/errors"
replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
"github.com/spf13/cobra"
)

func (r *runners) InitDefaultClearAllCommand(parent *cobra.Command) *cobra.Command {
cmd := &cobra.Command{
Expand All @@ -22,6 +26,11 @@ replicated default clear-all`,
}

func (r *runners) clearAllDefaults(cmd *cobra.Command) error {
cache, err := replicatedcache.GetInstance()
if err != nil {
return errors.Wrap(err, "initialize cache")
}

if err := cache.ClearDefault("app"); err != nil {
return err
}
Expand Down
6 changes: 6 additions & 0 deletions cli/cmd/default_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"github.com/pkg/errors"
"github.com/replicatedhq/replicated/cli/print"
replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
"github.com/replicatedhq/replicated/pkg/types"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -44,6 +45,11 @@ func (r *runners) setDefault(cmd *cobra.Command, defaultType string, defaultValu
return errors.Wrap(err, "get app")
}

cache, err := replicatedcache.GetInstance()
if err != nil {
return errors.Wrap(err, "initialize cache")
}

if err := cache.SetDefault(defaultType, defaultValue); err != nil {
return errors.Wrap(err, "set default in cache")
}
Expand Down
6 changes: 6 additions & 0 deletions cli/cmd/default_show.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/pkg/errors"
"github.com/replicatedhq/replicated/cli/print"
replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
"github.com/replicatedhq/replicated/pkg/types"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -40,6 +41,11 @@ replicated default show app
}

func (r *runners) showDefault(cmd *cobra.Command, defaultType string, outputFormat string) error {
cache, err := replicatedcache.GetInstance()
if err != nil {
return errors.Wrap(err, "initialize cache")
}

defaultValue, err := cache.GetDefault(defaultType)
if err != nil {
return errors.Wrap(err, "get default value")
Expand Down
8 changes: 6 additions & 2 deletions cli/cmd/enterprise_portal_preview.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"time"

"github.com/pkg/errors"
replicatedcache "github.com/replicatedhq/replicated/pkg/cache"
"github.com/replicatedhq/replicated/pkg/credentials"
"github.com/replicatedhq/replicated/pkg/kotsclient"
"github.com/replicatedhq/replicated/pkg/platformclient"
Expand Down Expand Up @@ -106,8 +107,11 @@ func (r *runners) enterprisePortalPreview(cmd *cobra.Command, args []string) err
// 2. default app set via `replicated default app <slug>` (cache.DefaultApp)
// 3. REPLICATED_APP env var
appSlug := appSlugOrID
if appSlug == "" && cache != nil {
appSlug = cache.DefaultApp
if appSlug == "" {
cache, err := replicatedcache.GetInstance()
if err == nil && cache != nil {
appSlug = cache.DefaultApp
}
}
if appSlug == "" {
appSlug = os.Getenv("REPLICATED_APP")
Expand Down
12 changes: 5 additions & 7 deletions cli/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ var (
profileNameFlag string
platformOrigin = "https://api.replicated.com/vendor"
kurlDotSHOrigin = "https://kurl.sh"
cache *replicatedcache.Cache
debugFlag bool
)

Expand All @@ -45,12 +44,6 @@ func init() {
platformOrigin = originFromEnv
}

c, err := replicatedcache.InitCache()
if err != nil {
panic(err)
}
cache = c

// Set debug mode from environment variable
if os.Getenv("REPLICATED_DEBUG") == "1" || os.Getenv("REPLICATED_DEBUG") == "true" {
debugFlag = true
Expand Down Expand Up @@ -446,6 +439,11 @@ func Execute(rootCmd *cobra.Command, stdin io.Reader, stdout io.Writer, stderr i
return errors.Wrap(err, "set up APIs")
}

cache, err := replicatedcache.GetInstance()
if err != nil {
return errors.Wrap(err, "initialize cache")
}

if appSlugOrID == "" {
if cache.DefaultApp != "" {
appSlugOrID = cache.DefaultApp
Expand Down
27 changes: 27 additions & 0 deletions pkg/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,40 @@ import (
"encoding/json"
"os"
"path/filepath"
"sync"
"time"

"github.com/adrg/xdg"
"github.com/pkg/errors"
"github.com/replicatedhq/replicated/pkg/types"
)

var (
instance *Cache
instanceErr error
once sync.Once
)

// GetInstance returns the singleton cache instance, initializing it on first
// call. Lazy initialization ensures commands that don't need the cache (e.g.
// 'completion') won't fail when HOME is not writable.
func GetInstance() (*Cache, error) {
once.Do(func() {
instance, instanceErr = InitCache()
})
if instanceErr != nil {
return nil, instanceErr
}
return instance, nil
}

// ResetForTesting resets the singleton so tests can control cache state.
func ResetForTesting() {
once = sync.Once{}
instance = nil
instanceErr = nil
}

const cacheFileName = "replicated.cache"

type Cache struct {
Expand Down