From 5251344318a6e78b4d1159c425b66fb0aae3597f Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Wed, 27 Apr 2016 13:46:26 -0600 Subject: [PATCH 1/2] feat(helm): add structure.go to hold paths --- cmd/helm/home.go | 6 ------ cmd/helm/init.go | 46 ++++++++++++++++++------------------------- cmd/helm/init_test.go | 9 +++++---- cmd/helm/package.go | 2 +- cmd/helm/search.go | 2 +- cmd/helm/serve.go | 2 +- cmd/helm/structure.go | 31 +++++++++++++++++++++++++++++ 7 files changed, 58 insertions(+), 40 deletions(-) create mode 100644 cmd/helm/structure.go diff --git a/cmd/helm/home.go b/cmd/helm/home.go index 1e9e63b64..0f3d4480a 100644 --- a/cmd/helm/home.go +++ b/cmd/helm/home.go @@ -1,8 +1,6 @@ package main import ( - "os" - "github.com/spf13/cobra" ) @@ -25,7 +23,3 @@ func init() { func home(cmd *cobra.Command, args []string) { cmd.Printf(homePath() + "\n") } - -func homePath() string { - return os.ExpandEnv(helmHome) -} diff --git a/cmd/helm/init.go b/cmd/helm/init.go index 26688f6de..24dbde8c2 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -5,7 +5,6 @@ import ( "fmt" "io/ioutil" "os" - "path/filepath" "github.com/deis/tiller/pkg/client" "github.com/deis/tiller/pkg/kubectl" @@ -17,13 +16,10 @@ This command installs Tiller (the helm server side component) onto your Kubernetes Cluster and sets up local configuration in $HELM_HOME (default: ~/.helm/) ` -var repositoriesFilePath string -var cachePath string -var localRepoPath string -var localCacheFilePath string -var tillerImg string - -var defaultRepo = map[string]string{"default-name": "default-url"} +var ( + tillerImg string + defaultRepo = map[string]string{"default-name": "default-url"} +) func init() { initCmd.Flags().StringVarP(&tillerImg, "tiller-image", "i", "", "override tiller image") @@ -43,7 +39,7 @@ func runInit(cmd *cobra.Command, args []string) error { return errors.New("This command does not accept arguments. \n") } - if err := ensureHome(homePath()); err != nil { + if err := ensureHome(); err != nil { return err } @@ -81,14 +77,8 @@ func buildKubectlRunner(kubectlPath string) kubectl.Runner { // ensureHome checks to see if $HELM_HOME exists // // If $HELM_HOME does not exist, this function will create it. -func ensureHome(home string) error { - repositoriesFilePath = filepath.Join(home, "repositories.yaml") - cachePath = filepath.Join(home, "cache") - localRepoPath = filepath.Join(home, "local") - localCacheFilePath = filepath.Join(home, "cache.yaml") - - fmt.Println("home path: " + home) - configDirectories := []string{home, cachePath, localRepoPath} +func ensureHome() error { + configDirectories := []string{homePath(), cacheDirectory(), localRepoDirectory()} for _, p := range configDirectories { if fi, err := os.Stat(p); err != nil { @@ -101,28 +91,30 @@ func ensureHome(home string) error { } } - if fi, err := os.Stat(repositoriesFilePath); err != nil { - fmt.Printf("Creating %s \n", repositoriesFilePath) - if err := ioutil.WriteFile(repositoriesFilePath, []byte("local: localhost:8879/charts\n"), 0644); err != nil { + repoFile := repositoriesFile() + if fi, err := os.Stat(repoFile); err != nil { + fmt.Printf("Creating %s \n", repoFile) + if err := ioutil.WriteFile(repoFile, []byte("local: localhost:8879/charts\n"), 0644); err != nil { return err } } else if fi.IsDir() { - return fmt.Errorf("%s must be a file, not a directory", repositoriesFilePath) + return fmt.Errorf("%s must be a file, not a directory", repoFile) } - if fi, err := os.Stat(localCacheFilePath); err != nil { - fmt.Printf("Creating %s \n", localCacheFilePath) - _, err := os.Create(localCacheFilePath) + localRepoCacheFile := localRepoDirectory(localRepoCacheFilePath) + if fi, err := os.Stat(localRepoCacheFile); err != nil { + fmt.Printf("Creating %s \n", localRepoCacheFile) + _, err := os.Create(localRepoCacheFile) if err != nil { return err } //TODO: take this out and replace with helm update functionality - os.Symlink(localCacheFilePath, filepath.Join(cachePath, "local-cache.yaml")) + os.Symlink(localRepoCacheFile, cacheDirectory("local-cache.yaml")) } else if fi.IsDir() { - return fmt.Errorf("%s must be a file, not a directory", localCacheFilePath) + return fmt.Errorf("%s must be a file, not a directory", localRepoCacheFile) } - fmt.Printf("$HELM_HOME has also been configured at %s.\n", helmHome) + fmt.Printf("$HELM_HOME has been configured at %s.\n", helmHome) return nil } diff --git a/cmd/helm/init_test.go b/cmd/helm/init_test.go index 2b3728e6a..6c5bebbe9 100644 --- a/cmd/helm/init_test.go +++ b/cmd/helm/init_test.go @@ -8,11 +8,12 @@ import ( func TestEnsureHome(t *testing.T) { home := createTmpHome() - if err := ensureHome(home); err != nil { + helmHome = home + if err := ensureHome(); err != nil { t.Errorf("%s", err) } - expectedDirs := []string{home, cachePath, localRepoPath} + expectedDirs := []string{homePath(), cacheDirectory(), localRepoDirectory()} for _, dir := range expectedDirs { if fi, err := os.Stat(dir); err != nil { t.Errorf("%s", err) @@ -21,13 +22,13 @@ func TestEnsureHome(t *testing.T) { } } - if fi, err := os.Stat(repositoriesFilePath); err != nil { + if fi, err := os.Stat(repositoriesFile()); err != nil { t.Errorf("%s", err) } else if fi.IsDir() { t.Errorf("%s should not be a directory", fi) } - if fi, err := os.Stat(localCacheFilePath); err != nil { + if fi, err := os.Stat(localRepoDirectory(localRepoCacheFilePath)); err != nil { t.Errorf("%s", err) } else if fi.IsDir() { t.Errorf("%s should not be a directory", fi) diff --git a/cmd/helm/package.go b/cmd/helm/package.go index 66678a184..98c12ce05 100644 --- a/cmd/helm/package.go +++ b/cmd/helm/package.go @@ -56,7 +56,7 @@ func runPackage(cmd *cobra.Command, args []string) error { // Save to $HELM_HOME/local directory. if save { - if err := repo.AddChartToLocalRepo(ch, localRepoPath); err != nil { + if err := repo.AddChartToLocalRepo(ch, localRepoDirectory()); err != nil { return err } } diff --git a/cmd/helm/search.go b/cmd/helm/search.go index d3b451a2d..b4175b99c 100644 --- a/cmd/helm/search.go +++ b/cmd/helm/search.go @@ -40,7 +40,7 @@ func search(cmd *cobra.Command, args []string) error { func searchCacheForPattern(name string) ([]string, error) { fileList := []string{} - filepath.Walk(cachePath, func(path string, f os.FileInfo, err error) error { + filepath.Walk(cacheDirectory(), func(path string, f os.FileInfo, err error) error { if !f.IsDir() { fileList = append(fileList, path) } diff --git a/cmd/helm/serve.go b/cmd/helm/serve.go index 7c046e139..fd713dafd 100644 --- a/cmd/helm/serve.go +++ b/cmd/helm/serve.go @@ -22,5 +22,5 @@ var serveCmd = &cobra.Command{ } func serve(cmd *cobra.Command, args []string) { - repo.StartLocalRepo(localRepoPath) + repo.StartLocalRepo(localRepoDirectory()) } diff --git a/cmd/helm/structure.go b/cmd/helm/structure.go new file mode 100644 index 000000000..056be291d --- /dev/null +++ b/cmd/helm/structure.go @@ -0,0 +1,31 @@ +package main + +import ( + "os" + "path/filepath" +) + +const ( + repositoriesFilePath string = "repositories.yaml" + cachePath string = "cache" + localRepoPath string = "local" + localRepoCacheFilePath string = "cache.yaml" +) + +func homePath() string { + return os.ExpandEnv(helmHome) +} + +func cacheDirectory(paths ...string) string { + fragments := append([]string{homePath(), cachePath}, paths...) + return filepath.Join(fragments...) +} + +func localRepoDirectory(paths ...string) string { + fragments := append([]string{homePath(), localRepoPath}, paths...) + return filepath.Join(fragments...) +} + +func repositoriesFile() string { + return filepath.Join(homePath(), repositoriesFilePath) +} From e250328e224f0ea2afbc92c6ce5c4961614bbecd Mon Sep 17 00:00:00 2001 From: Michelle Noorali Date: Mon, 25 Apr 2016 13:10:33 -0600 Subject: [PATCH 2/2] feat(helm): add helm repo add command --- cmd/helm/repo.go | 72 +++++++++++++++++++++++++++++++++++++++++++ cmd/helm/repo_test.go | 35 +++++++++++++++++++++ pkg/repo/repo.go | 40 ++++++++++++++++++++++++ 3 files changed, 147 insertions(+) create mode 100644 cmd/helm/repo.go create mode 100644 cmd/helm/repo_test.go create mode 100644 pkg/repo/repo.go diff --git a/cmd/helm/repo.go b/cmd/helm/repo.go new file mode 100644 index 000000000..e60bd5f41 --- /dev/null +++ b/cmd/helm/repo.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "os" + + "github.com/deis/tiller/pkg/repo" + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" +) + +func init() { + repoCmd.AddCommand(repoAddCmd) + RootCommand.AddCommand(repoCmd) +} + +var repoCmd = &cobra.Command{ + Use: "repo add|remove|list [ARG]", + Short: "add, list, or remove chart repositories", +} + +var repoAddCmd = &cobra.Command{ + Use: "add [flags] [NAME] [URL]", + Short: "add a chart repository", + RunE: runRepoAdd, +} + +func runRepoAdd(cmd *cobra.Command, args []string) error { + if len(args) != 2 { + return fmt.Errorf("This command needs two argument, a name for the chart repository and the url of the chart repository") + } + + err := insertRepoLine(args[0], args[1]) + if err != nil { + return err + } + fmt.Println(args[0] + " has been added to your repositories") + return nil +} + +func insertRepoLine(name, url string) error { + err := checkUniqueName(name) + if err != nil { + return err + } + + b, _ := yaml.Marshal(map[string]string{name: url}) + f, err := os.OpenFile(repositoriesFile(), os.O_APPEND|os.O_WRONLY, 0666) + if err != nil { + return err + } + defer f.Close() + _, err = f.Write(b) + if err != nil { + return err + } + + return nil +} + +func checkUniqueName(name string) error { + file, err := repo.LoadRepositoriesFile(repositoriesFile()) + if err != nil { + return err + } + + _, ok := file.Repositories[name] + if ok { + return fmt.Errorf("The repository name you provided (%s) already exists. Please specifiy a different name.", name) + } + return nil +} diff --git a/cmd/helm/repo_test.go b/cmd/helm/repo_test.go new file mode 100644 index 000000000..f4c234ebf --- /dev/null +++ b/cmd/helm/repo_test.go @@ -0,0 +1,35 @@ +package main + +import ( + "testing" + + "github.com/deis/tiller/pkg/repo" +) + +func TestRepoAdd(t *testing.T) { + home := createTmpHome() + helmHome = home + if err := ensureHome(); err != nil { + t.Errorf("%s", err) + } + + testName := "test-name" + testURL := "test-url" + if err := insertRepoLine(testName, testURL); err != nil { + t.Errorf("%s", err) + } + + f, err := repo.LoadRepositoriesFile(repositoriesFile()) + if err != nil { + t.Errorf("%s", err) + } + _, ok := f.Repositories[testName] + if !ok { + t.Errorf("%s was not successfully inserted into %s", testName, repositoriesFile()) + } + + if err := insertRepoLine(testName, testURL); err == nil { + t.Errorf("Duplicate repository name was added") + } + +} diff --git a/pkg/repo/repo.go b/pkg/repo/repo.go new file mode 100644 index 000000000..13138c10d --- /dev/null +++ b/pkg/repo/repo.go @@ -0,0 +1,40 @@ +package repo + +import ( + "io/ioutil" + + "gopkg.in/yaml.v2" +) + +// RepoFile represents the .repositories file in $HELM_HOME +type RepoFile struct { + Repositories map[string]string +} + +// LoadRepositoriesFile takes a file at the given path and returns a RepoFile object +func LoadRepositoriesFile(path string) (*RepoFile, error) { + b, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + var r RepoFile + err = yaml.Unmarshal(b, &r) + if err != nil { + return nil, err + } + + return &r, nil +} + +// UnmarshalYAML unmarshals the repo file +func (rf *RepoFile) UnmarshalYAML(unmarshal func(interface{}) error) error { + var repos map[string]string + if err := unmarshal(&repos); err != nil { + if _, ok := err.(*yaml.TypeError); !ok { + return err + } + } + rf.Repositories = repos + return nil +}