Commit e2f9d894 authored by Matt Butcher's avatar Matt Butcher Committed by GitHub

Merge pull request #1107 from technosophos/fix/696-update

fix(helm): refactor 'helm update' to match new style
parents 25c77feb 1fb16ab3
......@@ -97,6 +97,7 @@ func newRootCmd(out io.Writer) *cobra.Command {
newPackageCmd(nil, out),
newFetchCmd(out),
newVerifyCmd(out),
newUpdateCmd(out),
)
return cmd
}
......
charts: http://storage.googleapis.com/kubernetes-charts
local: http://localhost:8879/charts
......@@ -19,6 +19,7 @@ package main
import (
"errors"
"fmt"
"io"
"sync"
"github.com/spf13/cobra"
......@@ -26,23 +27,37 @@ import (
"k8s.io/helm/pkg/repo"
)
var verboseUpdate bool
const updateDesc = `
Update gets the latest information about charts from the respective chart repositories.
Information is cached locally, where it is used by commands like 'helm search'.
`
var updateCommand = &cobra.Command{
Use: "update",
Aliases: []string{"up"},
Short: "update information on available charts in the chart repositories",
RunE: runUpdate,
type updateCmd struct {
repoFile string
update func(map[string]string, bool, io.Writer)
out io.Writer
}
func init() {
updateCommand.Flags().BoolVar(&verboseUpdate, "verbose", false, "verbose error messages")
RootCommand.AddCommand(updateCommand)
func newUpdateCmd(out io.Writer) *cobra.Command {
u := &updateCmd{
out: out,
update: updateCharts,
repoFile: repositoriesFile(),
}
cmd := &cobra.Command{
Use: "update",
Aliases: []string{"up"},
Short: "update information on available charts in the chart repositories",
Long: updateDesc,
RunE: func(cmd *cobra.Command, args []string) error {
return u.run()
},
}
return cmd
}
func runUpdate(cmd *cobra.Command, args []string) error {
f, err := repo.LoadRepositoriesFile(repositoriesFile())
func (u *updateCmd) run() error {
f, err := repo.LoadRepositoriesFile(u.repoFile)
if err != nil {
return err
}
......@@ -51,12 +66,12 @@ func runUpdate(cmd *cobra.Command, args []string) error {
return errors.New("no repositories found. You must add one before updating")
}
updateCharts(f.Repositories, verboseUpdate)
u.update(f.Repositories, flagDebug, u.out)
return nil
}
func updateCharts(repos map[string]string, verbose bool) {
fmt.Println("Hang tight while we grab the latest from your chart repositories...")
func updateCharts(repos map[string]string, verbose bool, out io.Writer) {
fmt.Fprintln(out, "Hang tight while we grab the latest from your chart repositories...")
var wg sync.WaitGroup
for name, url := range repos {
wg.Add(1)
......@@ -65,16 +80,16 @@ func updateCharts(repos map[string]string, verbose bool) {
indexFileName := cacheDirectory(n + "-index.yaml")
err := repo.DownloadIndexFile(n, u, indexFileName)
if err != nil {
updateErr := "...Unable to get an update from the " + n + " chart repository"
updateErr := fmt.Sprintf("...Unable to get an update from the %q chart repository", n)
if verbose {
updateErr = updateErr + ": " + err.Error()
}
fmt.Println(updateErr)
fmt.Fprintln(out, updateErr)
} else {
fmt.Println("...Successfully got an update from the " + n + " chart repository")
fmt.Fprintf(out, "...Successfully got an update from the %q chart repository\n", n)
}
}(name, url)
}
wg.Wait()
fmt.Println("Update Complete. Happy Helming!")
fmt.Fprintln(out, "Update Complete. Happy Helming!")
}
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestUpdateCmd(t *testing.T) {
out := bytes.NewBuffer(nil)
// Instead of using the HTTP updater, we provide our own for this test.
// The TestUpdateCharts test verifies the HTTP behavior independently.
updater := func(repos map[string]string, verbose bool, out io.Writer) {
for name := range repos {
fmt.Fprintln(out, name)
}
}
uc := &updateCmd{
out: out,
update: updater,
repoFile: "testdata/repositories.yaml",
}
uc.run()
if got := out.String(); !strings.Contains(got, "charts") || !strings.Contains(got, "local") {
t.Errorf("Expected 'charts' and 'local' (in any order) got %s", got)
}
}
const mockRepoIndex = `
mychart-0.1.0:
name: mychart-0.1.0
url: localhost:8879/charts/mychart-0.1.0.tgz
chartfile:
name: ""
home: ""
sources: []
version: ""
description: ""
keywords: []
maintainers: []
engine: ""
icon: ""
`
func TestUpdateCharts(t *testing.T) {
// This tests the repo in isolation. It creates a mock HTTP server that simply
// returns a static YAML file in the anticipate format.
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(mockRepoIndex))
})
srv := httptest.NewServer(handler)
defer srv.Close()
buf := bytes.NewBuffer(nil)
repos := map[string]string{
"charts": srv.URL,
}
updateCharts(repos, false, buf)
got := buf.String()
if strings.Contains(got, "Unable to get an update") {
t.Errorf("Failed to get a repo: %q", got)
}
if !strings.Contains(got, "Update Complete.") {
t.Errorf("Update was not successful")
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment