From b39a0848348c7bfbfb2cda3c27b1da308120959b Mon Sep 17 00:00:00 2001 From: vaikas-google Date: Wed, 4 May 2016 13:46:56 -0700 Subject: [PATCH 1/5] first cut of fetch --- cmd/helm/fetch.go | 60 +++++++++++++++++++++++++++++++++++++----- cmd/helm/fetch_test.go | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 7 deletions(-) create mode 100644 cmd/helm/fetch_test.go diff --git a/cmd/helm/fetch.go b/cmd/helm/fetch.go index c14c4f103..5483f656e 100644 --- a/cmd/helm/fetch.go +++ b/cmd/helm/fetch.go @@ -4,8 +4,11 @@ import ( "fmt" "io" "net/http" + "net/url" "os" + "strings" + "github.com/kubernetes/helm/pkg/repo" "github.com/spf13/cobra" ) @@ -14,23 +17,37 @@ func init() { } var fetchCmd = &cobra.Command{ - Use: "fetch", - Short: "Download a chart from a repository and unpack it in local directory.", + Use: "fetch [chart URL | repo/chartname]", + Short: "Download a chart from a repository and (optionally) unpack it in local directory.", Long: "", RunE: fetch, } func fetch(cmd *cobra.Command, args []string) error { - // parse args + if len(args) == 0 { + return fmt.Errorf("This command needs at least one argument, url or repo/name of the chart.") + } + + f, err := repo.LoadRepositoriesFile(repositoriesFile()) + if err != nil { + return err + } + // get download url - // call download url - out, err := os.Create("nginx-2.0.0.tgz") + u, err := mapRepoArg(args[0], f.Repositories) + if err != nil { + return err + } + + // Grab the package name that we'll use for the name of the file to download to. + p := strings.Split(u.String(), "/") + chartName := p[len(p)-1] + out, err := os.Create(chartName) if err != nil { return err } defer out.Close() - resp, err := http.Get("http://localhost:8879/charts/nginx-2.0.0.tgz") - fmt.Println("after req") + resp, err := http.Get(u) // unpack file if err != nil { return err @@ -44,3 +61,32 @@ func fetch(cmd *cobra.Command, args []string) error { } return nil } + +// mapRepoArg figures out which format the argument is given, and creates a fetchable +// url from it. +func mapRepoArg(arg string, r map[string]string) (*url.URL, error) { + // See if it's already a full URL. + u, err := url.ParseRequestURI(arg) + if err == nil { + // If it has a scheme and host and path, it's a full URL + if u.IsAbs() && len(u.Host) > 0 && len(u.Path) > 0 { + return u, nil + } else { + return nil, fmt.Errorf("Invalid chart url format: %s", arg) + } + } + // See if it's of the form: repo/path_to_chart + p := strings.Split(arg, "/") + if len(p) > 1 { + if baseUrl, ok := r[p[0]]; ok { + if !strings.HasSuffix(baseUrl, "/") { + baseUrl = baseUrl + "/" + } + return url.ParseRequestURI(baseUrl + strings.Join(p[1:], "/")) + } else { + return nil, fmt.Errorf("No such repo: %s", p[0]) + } + } else { + return nil, fmt.Errorf("Invalid chart url format: %s", arg) + } +} diff --git a/cmd/helm/fetch_test.go b/cmd/helm/fetch_test.go new file mode 100644 index 000000000..8c17ef71c --- /dev/null +++ b/cmd/helm/fetch_test.go @@ -0,0 +1,53 @@ +package main + +import ( + "fmt" + // "io" + // "net/http" + //"net/url" + // "os" + + "testing" +) + +type testCase struct { + in string + expectedErr error + expectedOut string +} + +var repos = map[string]string{ + "local": "http://localhost:8879/charts", + "someother": "http://storage.googleapis.com/mycharts", +} + +var testCases = []testCase{ + {"bad", fmt.Errorf("Invalid chart url format: bad"), ""}, + {"http://", fmt.Errorf("Invalid chart url format: http://"), ""}, + {"http://example.com", fmt.Errorf("Invalid chart url format: http://example.com"), ""}, + {"http://example.com/foo/bar", nil, "http://example.com/foo/bar"}, + {"local/nginx-2.0.0.tgz", nil, "http://localhost:8879/charts/nginx-2.0.0.tgz"}, + {"nonexistentrepo/nginx-2.0.0.tgz", fmt.Errorf("No such repo: nonexistentrepo"), ""}, +} + +func testRunner(t *testing.T, tc testCase) { + u, err := mapRepoArg(tc.in, repos) + if (tc.expectedErr == nil && err != nil) || + (tc.expectedErr != nil && err == nil) || + (tc.expectedErr != nil && err != nil && tc.expectedErr.Error() != err.Error()) { + t.Errorf("Expected mapRepoArg to fail with input %s %v but got %v", tc.in, tc.expectedErr, err) + } + + if (u == nil && len(tc.expectedOut) != 0) || + (u != nil && len(tc.expectedOut) == 0) || + (u != nil && tc.expectedOut != u.String()) { + t.Errorf("Expected %s to map to fetch url %v but got %v", tc.in, tc.expectedOut, u) + } + +} + +func TestMappings(t *testing.T) { + for _, tc := range testCases { + testRunner(t, tc) + } +} From 84bf7b41cf17c4d320d53d86a1c5e825fe50c46c Mon Sep 17 00:00:00 2001 From: vaikas-google Date: Wed, 4 May 2016 15:30:38 -0700 Subject: [PATCH 2/5] cleanups, add todos --- cmd/helm/fetch.go | 68 ++++++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/cmd/helm/fetch.go b/cmd/helm/fetch.go index 5483f656e..d27d1f219 100644 --- a/cmd/helm/fetch.go +++ b/cmd/helm/fetch.go @@ -8,6 +8,7 @@ import ( "os" "strings" + "github.com/kubernetes/helm/pkg/chart" "github.com/kubernetes/helm/pkg/repo" "github.com/spf13/cobra" ) @@ -39,27 +40,22 @@ func fetch(cmd *cobra.Command, args []string) error { return err } - // Grab the package name that we'll use for the name of the file to download to. - p := strings.Split(u.String(), "/") - chartName := p[len(p)-1] - out, err := os.Create(chartName) + resp, err := http.Get(u.String()) if err != nil { return err } - defer out.Close() - resp, err := http.Get(u) - // unpack file - if err != nil { - return err + if resp.StatusCode != 200 { + return fmt.Errorf("Failed to fetch %s : %s", u.String(), resp.Status) } defer resp.Body.Close() - - _, err = io.Copy(out, resp.Body) - if err != nil { - return err + // TODO(vaikas): Implement untar / flag + untar := false + if untar { + return untarChart(resp.Body) } - return nil + p := strings.Split(u.String(), "/") + return saveChartFile(p[len(p)-1], resp.Body) } // mapRepoArg figures out which format the argument is given, and creates a fetchable @@ -71,22 +67,46 @@ func mapRepoArg(arg string, r map[string]string) (*url.URL, error) { // If it has a scheme and host and path, it's a full URL if u.IsAbs() && len(u.Host) > 0 && len(u.Path) > 0 { return u, nil - } else { - return nil, fmt.Errorf("Invalid chart url format: %s", arg) } + return nil, fmt.Errorf("Invalid chart url format: %s", arg) } // See if it's of the form: repo/path_to_chart p := strings.Split(arg, "/") if len(p) > 1 { - if baseUrl, ok := r[p[0]]; ok { - if !strings.HasSuffix(baseUrl, "/") { - baseUrl = baseUrl + "/" + if baseURL, ok := r[p[0]]; ok { + if !strings.HasSuffix(baseURL, "/") { + baseURL = baseURL + "/" } - return url.ParseRequestURI(baseUrl + strings.Join(p[1:], "/")) - } else { - return nil, fmt.Errorf("No such repo: %s", p[0]) + return url.ParseRequestURI(baseURL + strings.Join(p[1:], "/")) } - } else { - return nil, fmt.Errorf("Invalid chart url format: %s", arg) + return nil, fmt.Errorf("No such repo: %s", p[0]) } + return nil, fmt.Errorf("Invalid chart url format: %s", arg) +} + +func untarChart(r io.Reader) error { + c, err := chart.LoadDataFromReader(r) + if err != nil { + return err + } + if c == nil { + fmt.Errorf("Failed to untar the chart") + } + return fmt.Errorf("Not implemented yeet") + +} + +func saveChartFile(c string, r io.Reader) error { + // Grab the chart name that we'll use for the name of the file to download to. + out, err := os.Create(c) + if err != nil { + return err + } + defer out.Close() + + _, err = io.Copy(out, r) + if err != nil { + return err + } + return nil } From 95d953b8c395ef32c022b934d638af2bc9d2586f Mon Sep 17 00:00:00 2001 From: vaikas-google Date: Wed, 4 May 2016 15:33:35 -0700 Subject: [PATCH 3/5] add scheme to default local repo --- cmd/helm/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/helm/init.go b/cmd/helm/init.go index 5ea4e4de2..5ae526871 100644 --- a/cmd/helm/init.go +++ b/cmd/helm/init.go @@ -84,7 +84,7 @@ func ensureHome() error { if _, err := os.Create(repoFile); err != nil { return err } - if err := insertRepoLine("local", "localhost:8879/charts"); err != nil { + if err := insertRepoLine("local", "http://localhost:8879/charts"); err != nil { return err } } else if fi.IsDir() { From a1acee52cc9b810ed06dcf8985a982f4280348b5 Mon Sep 17 00:00:00 2001 From: vaikas-google Date: Wed, 4 May 2016 15:35:33 -0700 Subject: [PATCH 4/5] cleanup --- cmd/helm/fetch.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/helm/fetch.go b/cmd/helm/fetch.go index d27d1f219..aa47871b2 100644 --- a/cmd/helm/fetch.go +++ b/cmd/helm/fetch.go @@ -105,8 +105,5 @@ func saveChartFile(c string, r io.Reader) error { defer out.Close() _, err = io.Copy(out, r) - if err != nil { - return err - } - return nil + return err } From d5bf6efebcddac00edbce5d66fbdf793c78bb3fd Mon Sep 17 00:00:00 2001 From: vaikas-google Date: Wed, 4 May 2016 16:35:47 -0700 Subject: [PATCH 5/5] fix typo and return error --- cmd/helm/fetch.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/helm/fetch.go b/cmd/helm/fetch.go index aa47871b2..ca962ffb8 100644 --- a/cmd/helm/fetch.go +++ b/cmd/helm/fetch.go @@ -90,9 +90,9 @@ func untarChart(r io.Reader) error { return err } if c == nil { - fmt.Errorf("Failed to untar the chart") + return fmt.Errorf("Failed to untar the chart") } - return fmt.Errorf("Not implemented yeet") + return fmt.Errorf("Not implemented yee") }