func addRepository(name, url string, home helmpath.Home) error { cif := home.CacheIndex(name) if err := repo.DownloadIndexFile(name, url, cif); err != nil { return fmt.Errorf("Looks like %q is not a valid chart repository or cannot be reached: %s", url, err.Error()) } return insertRepoLine(name, url, home) }
func updateRepository(name, url string, home helmpath.Home) error { cif := home.CacheIndex(name) if err := repo.DownloadIndexFile(name, url, cif); err != nil { return err } return updateRepoLine(name, url, home) }
func removeRepoCache(name string, home helmpath.Home) error { if _, err := os.Stat(home.CacheIndex(name)); err == nil { err = os.Remove(home.CacheIndex(name)) if err != nil { return err } } return nil }
func updateCharts(repos []*repo.Entry, verbose bool, out io.Writer, home helmpath.Home) { fmt.Fprintln(out, "Hang tight while we grab the latest from your chart repositories...") var wg sync.WaitGroup for _, re := range repos { wg.Add(1) go func(n, u string) { defer wg.Done() if n == localRepository { // We skip local because the indices are symlinked. return } err := repo.DownloadIndexFile(n, u, home.CacheIndex(n)) if err != nil { fmt.Fprintf(out, "...Unable to get an update from the %q chart repository (%s):\n\t%s\n", n, u, err) } else { fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", n) } }(re.Name, re.URL) } wg.Wait() fmt.Fprintln(out, "Update Complete. ⎈ Happy Helming!⎈ ") }
func removeRepoLine(out io.Writer, name string, home helmpath.Home) error { repoFile := home.RepositoryFile() r, err := repo.LoadRepositoriesFile(repoFile) if err != nil { return err } if !r.Remove(name) { return fmt.Errorf("no repo named %q found", name) } if err := r.WriteFile(repoFile, 0644); err != nil { return err } if err := removeRepoCache(name, home); err != nil { return err } fmt.Fprintf(out, "%q has been removed from your repositories\n", name) return nil }
func updateRepoLine(name, url string, home helmpath.Home) error { cif := home.CacheIndex(name) f, err := repo.LoadRepositoriesFile(home.RepositoryFile()) if err != nil { return err } f.Update(&repo.Entry{ Name: name, URL: url, Cache: filepath.Base(cif), }) return f.WriteFile(home.RepositoryFile(), 0666) }
func insertRepoLine(name, url string, home helmpath.Home) error { cif := home.CacheIndex(name) f, err := repo.LoadRepositoriesFile(home.RepositoryFile()) if err != nil { return err } if f.Has(name) { return fmt.Errorf("The repository name you provided (%s) already exists. Please specify a different name.", name) } f.Add(&repo.Entry{ Name: name, URL: url, Cache: filepath.Base(cif), }) return f.WriteFile(home.RepositoryFile(), 0644) }
// ensureHome checks to see if $HELM_HOME exists // // If $HELM_HOME does not exist, this function will create it. func ensureHome(home helmpath.Home, out io.Writer) error { configDirectories := []string{home.String(), home.Repository(), home.Cache(), home.LocalRepository()} for _, p := range configDirectories { if fi, err := os.Stat(p); err != nil { fmt.Fprintf(out, "Creating %s \n", p) if err := os.MkdirAll(p, 0755); err != nil { return fmt.Errorf("Could not create %s: %s", p, err) } } else if !fi.IsDir() { return fmt.Errorf("%s must be a directory", p) } } repoFile := home.RepositoryFile() if fi, err := os.Stat(repoFile); err != nil { fmt.Fprintf(out, "Creating %s \n", repoFile) r := repo.NewRepoFile() r.Add(&repo.Entry{ Name: stableRepository, URL: stableRepositoryURL, Cache: "stable-index.yaml", }, &repo.Entry{ Name: localRepository, URL: localRepositoryURL, Cache: "local-index.yaml", }) if err := r.WriteFile(repoFile, 0644); err != nil { return err } cif := home.CacheIndex(stableRepository) if err := repo.DownloadIndexFile(stableRepository, stableRepositoryURL, cif); err != nil { fmt.Fprintf(out, "WARNING: Failed to download %s: %s (run 'helm repo update')\n", stableRepository, err) } } else if fi.IsDir() { return fmt.Errorf("%s must be a file, not a directory", repoFile) } if r, err := repo.LoadRepositoriesFile(repoFile); err == repo.ErrRepoOutOfDate { fmt.Fprintln(out, "Updating repository file format...") if err := r.WriteFile(repoFile, 0644); err != nil { return err } } localRepoIndexFile := home.LocalRepository(localRepoIndexFilePath) if fi, err := os.Stat(localRepoIndexFile); err != nil { fmt.Fprintf(out, "Creating %s \n", localRepoIndexFile) i := repo.NewIndexFile() if err := i.WriteFile(localRepoIndexFile, 0644); err != nil { return err } //TODO: take this out and replace with helm update functionality os.Symlink(localRepoIndexFile, home.CacheIndex("local")) } else if fi.IsDir() { return fmt.Errorf("%s must be a file, not a directory", localRepoIndexFile) } fmt.Fprintf(out, "$HELM_HOME has been configured at %s.\n", helmHome) return nil }
// loadPlugins loads plugins into the command list. // // This follows a different pattern than the other commands because it has // to inspect its environment and then add commands to the base command // as it finds them. func loadPlugins(baseCmd *cobra.Command, home helmpath.Home, out io.Writer) { plugdirs := os.Getenv(pluginEnvVar) if plugdirs == "" { plugdirs = home.Plugins() } found, err := findPlugins(plugdirs) if err != nil { fmt.Fprintf(os.Stderr, "failed to load plugins: %s", err) return } // Now we create commands for all of these. for _, plug := range found { plug := plug md := plug.Metadata if md.Usage == "" { md.Usage = fmt.Sprintf("the %q plugin", md.Name) } c := &cobra.Command{ Use: md.Name, Short: md.Usage, Long: md.Description, RunE: func(cmd *cobra.Command, args []string) error { k, u := manuallyProcessArgs(args) if err := cmd.Parent().ParseFlags(k); err != nil { return err } // Call setupEnv before PrepareCommand because // PrepareCommand uses os.ExpandEnv and expects the // setupEnv vars. setupEnv(md.Name, plug.Dir, plugdirs, home) main, argv := plug.PrepareCommand(u) prog := exec.Command(main, argv...) prog.Env = os.Environ() prog.Stdout = out prog.Stderr = os.Stderr if err := prog.Run(); err != nil { if eerr, ok := err.(*exec.ExitError); ok { os.Stderr.Write(eerr.Stderr) return fmt.Errorf("plugin %q exited with error", md.Name) } return err } return nil }, // This passes all the flags to the subcommand. DisableFlagParsing: true, } if md.UseTunnel { c.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { // Parse the parent flag, but not the local flags. k, _ := manuallyProcessArgs(args) if err := c.Parent().ParseFlags(k); err != nil { return err } return setupConnection(cmd, args) } } // TODO: Make sure a command with this name does not already exist. baseCmd.AddCommand(c) } }
// setupEnv prepares os.Env for plugins. It operates on os.Env because // the plugin subsystem itself needs access to the environment variables // created here. func setupEnv(shortname, base, plugdirs string, home helmpath.Home) { // Set extra env vars: for key, val := range map[string]string{ "HELM_PLUGIN_NAME": shortname, "HELM_PLUGIN_DIR": base, "HELM_BIN": os.Args[0], // Set vars that may not have been set, and save client the // trouble of re-parsing. pluginEnvVar: plugdirs, homeEnvVar: home.String(), // Set vars that convey common information. "HELM_PATH_REPOSITORY": home.Repository(), "HELM_PATH_REPOSITORY_FILE": home.RepositoryFile(), "HELM_PATH_CACHE": home.Cache(), "HELM_PATH_LOCAL_REPOSITORY": home.LocalRepository(), "HELM_PATH_STARTER": home.Starters(), "TILLER_HOST": tillerHost, tillerNamespaceEnvVar: tillerNamespace, } { os.Setenv(key, val) } if flagDebug { os.Setenv("HELM_DEBUG", "1") } }
// ensureTestHome creates a home directory like ensureHome, but without remote references. // // t is used only for logging. func ensureTestHome(home helmpath.Home, t *testing.T) error { configDirectories := []string{home.String(), home.Repository(), home.Cache(), home.LocalRepository(), home.Plugins(), home.Starters()} for _, p := range configDirectories { if fi, err := os.Stat(p); err != nil { if err := os.MkdirAll(p, 0755); err != nil { return fmt.Errorf("Could not create %s: %s", p, err) } } else if !fi.IsDir() { return fmt.Errorf("%s must be a directory", p) } } repoFile := home.RepositoryFile() if fi, err := os.Stat(repoFile); err != nil { rf := repo.NewRepoFile() rf.Add(&repo.Entry{ Name: "charts", URL: "http://example.com/foo", Cache: "charts-index.yaml", }, &repo.Entry{ Name: "local", URL: "http://localhost.com:7743/foo", Cache: "local-index.yaml", }) if err := rf.WriteFile(repoFile, 0644); err != nil { return err } } else if fi.IsDir() { return fmt.Errorf("%s must be a file, not a directory", repoFile) } if r, err := repo.LoadRepositoriesFile(repoFile); err == repo.ErrRepoOutOfDate { t.Log("Updating repository file format...") if err := r.WriteFile(repoFile, 0644); err != nil { return err } } localRepoIndexFile := home.LocalRepository(localRepoIndexFilePath) if fi, err := os.Stat(localRepoIndexFile); err != nil { i := repo.NewIndexFile() if err := i.WriteFile(localRepoIndexFile, 0644); err != nil { return err } //TODO: take this out and replace with helm update functionality os.Symlink(localRepoIndexFile, home.CacheIndex("local")) } else if fi.IsDir() { return fmt.Errorf("%s must be a file, not a directory", localRepoIndexFile) } t.Logf("$HELM_HOME has been configured at %s.\n", helmHome) return nil }