diff --git a/glide.lock b/glide.lock index 8d962eb56..a766840c6 100644 --- a/glide.lock +++ b/glide.lock @@ -1,8 +1,8 @@ -hash: 2ac3dc0e19d5a688173924d35a07b4bad2454c7e6f5ff4d5a6911f33d1037586 -updated: 2016-05-24T09:51:36.455233258-07:00 +hash: c936008b9f7c5628e6c1bc442f64c7f858387eb2ce56337a33d6b5ef98a6b822 +updated: 2016-06-16T12:47:24.36415913-06:00 imports: - name: bitbucket.org/ww/goautoneg - version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675 + version: 75cd24fc2f2c - name: github.com/aokoli/goutils version: 9c37978a95bd5c709a15883b6242714ea6709e64 - name: github.com/beorn7/perks @@ -11,8 +11,6 @@ imports: - quantile - name: github.com/blang/semver version: 31b736133b98f26d5e078ec9eb591666edfd091f -- name: github.com/BurntSushi/toml - version: bbd5bb678321a0d6e58f1099321dfa73391c1b6f - name: github.com/davecgh/go-spew version: 5215b55f46b2b919f50a1df0eaa5886afe4e3b3d subpackages: @@ -22,17 +20,6 @@ imports: subpackages: - digest - reference -- name: github.com/docker/docker - version: 0f5c9d301b9b1cca66b3ea0f9dec3b5317d3686d - subpackages: - - pkg/jsonmessage - - pkg/mount - - pkg/stdcopy - - pkg/symlink - - pkg/term - - pkg/term/winconsole - - pkg/timeutils - - pkg/units - name: github.com/docker/engine-api version: 3d72d392d07bece8d7d7b2a3b6b2e57c2df376a2 subpackages: @@ -155,8 +142,6 @@ imports: - util/wordwrap - name: github.com/imdario/mergo version: 6633656539c1639d9d78127b7d47c622b5d7b6dc -- name: github.com/inconshreveable/mousetrap - version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 - name: github.com/juju/ratelimit version: 77ed1c8a01217656d2080ad51981f6e99adaa177 - name: github.com/Masterminds/semver @@ -169,24 +154,6 @@ imports: version: fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a subpackages: - pbutil -- name: github.com/opencontainers/runc - version: 7ca2aa4873aea7cb4265b1726acb24b90d8726c6 - subpackages: - - libcontainer - - libcontainer/apparmor - - libcontainer/cgroups - - libcontainer/cgroups/fs - - libcontainer/cgroups/systemd - - libcontainer/configs - - libcontainer/configs/validate - - libcontainer/criurpc - - libcontainer/label - - libcontainer/seccomp - - libcontainer/selinux - - libcontainer/stacktrace - - libcontainer/system - - libcontainer/user - - libcontainer/utils - name: github.com/pborman/uuid version: ca53cad383cad2479bbba7f7a1a05797ec1386e4 - name: github.com/prometheus/client_golang @@ -234,18 +201,6 @@ imports: - internal - jws - jwt -- name: google.golang.org/appengine - version: 12d5545dc1cfa6047a286d5e853841b6471f4c19 - subpackages: - - internal - - internal/app_identity - - internal/base - - internal/datastore - - internal/log - - internal/modules - - internal/remote_api - - urlfetch - - internal/urlfetch - name: google.golang.org/cloud version: eb47ba841d53d93506cfbfbc03927daf9cc48f88 subpackages: @@ -280,14 +235,24 @@ imports: - pkg/kubectl/cmd/util - pkg/kubectl/resource - pkg/labels + - pkg/api/resource - pkg/api/unversioned + - pkg/auth/user + - pkg/conversion + - pkg/fields + - pkg/runtime + - pkg/runtime/serializer + - pkg/types + - pkg/util + - pkg/util/intstr + - pkg/util/rand + - pkg/util/sets + - pkg/util/validation - pkg/client/unversioned/auth - pkg/client/unversioned/clientcmd/api - pkg/client/unversioned/clientcmd/api/latest - - pkg/runtime - pkg/util/errors - pkg/util/homedir - - pkg/util/validation - pkg/kubelet/server/portforward - pkg/util/httpstream - pkg/util/runtime @@ -313,17 +278,14 @@ imports: - pkg/util/flag - pkg/util/strategicpatch - pkg/watch - - pkg/util/sets - pkg/util/yaml - - pkg/api/resource - - pkg/auth/user - - pkg/conversion - - pkg/fields - - pkg/runtime/serializer - - pkg/types - - pkg/util - - pkg/util/intstr - - pkg/util/rand + - third_party/forked/reflect + - pkg/conversion/queryparams + - pkg/util/json + - pkg/runtime/serializer/protobuf + - pkg/runtime/serializer/recognizer + - pkg/runtime/serializer/versioning + - pkg/util/wait - pkg/api/v1 - pkg/client/metrics - pkg/runtime/serializer/streaming @@ -333,9 +295,6 @@ imports: - pkg/version - pkg/watch/versioned - pkg/client/unversioned/clientcmd/api/v1 - - pkg/runtime/serializer/versioning - - pkg/conversion/queryparams - - pkg/util/json - pkg/httplog - pkg/util/wsstream - third_party/golang/netutil @@ -357,7 +316,6 @@ imports: - pkg/apis/extensions/install - pkg/apis/metrics/install - pkg/apis/policy/install - - pkg/util/wait - plugin/pkg/client/auth - pkg/client/clientset_generated/internalclientset - pkg/client/clientset_generated/internalclientset/typed/core/unversioned @@ -380,9 +338,6 @@ imports: - pkg/registry/generic - pkg/util/framer - third_party/forked/json - - third_party/forked/reflect - - pkg/runtime/serializer/protobuf - - pkg/runtime/serializer/recognizer - pkg/util/parsers - pkg/util/net/sets - pkg/apis/apps/v1alpha1 diff --git a/glide.yaml b/glide.yaml index 042afb189..bd2f07a6b 100644 --- a/glide.yaml +++ b/glide.yaml @@ -12,8 +12,6 @@ import: - package: gopkg.in/yaml.v2 - package: github.com/Masterminds/semver version: 1.1.0 -- package: github.com/BurntSushi/toml - version: bbd5bb678321a0d6e58f1099321dfa73391c1b6f - package: github.com/technosophos/moniker - package: github.com/golang/protobuf version: f0a097ddac24fb00e07d2ac17f8671423f3ea47c @@ -38,5 +36,5 @@ import: - pkg/labels - package: github.com/gosuri/uitable - package: speter.net/go/exp/math/dec/inf - vcs: git repo: https://github.com/go-inf/inf.git + vcs: git diff --git a/pkg/chart/chart.go b/pkg/chart/chart.go deleted file mode 100644 index f4a2782e5..000000000 --- a/pkg/chart/chart.go +++ /dev/null @@ -1,525 +0,0 @@ -/* -Copyright 2015 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 chart - -import ( - "archive/tar" - "bytes" - "compress/gzip" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "k8s.io/helm/pkg/chartutil" -) - -// ChartfileName is the default Chart file name. -const ChartfileName string = "Chart.yaml" - -const ( - preTemplates string = "templates/" - preValues string = "values.yaml" - preCharts string = "charts/" -) - -const defaultValues = `# Default values for %s. -# This is a YAML-formatted file. -# Declare name/value pairs to be passed into your templates. -# name: value -` - -var headerBytes = []byte("+aHR0cHM6Ly95b3V0dS5iZS96OVV6MWljandyTQo=") - -// Chart represents a complete chart. -// -// A chart consists of the following parts: -// -// - Chart.yaml: In code, we refer to this as the Chartfile -// - templates/*: The template directory -// - README.md: Optional README file -// - LICENSE: Optional license file -// - hooks/: Optional hooks registry -// - docs/: Optional docs directory -// -// Packed charts are stored in gzipped tar archives (.tgz). Unpackaged charts -// are directories where the directory name is the Chartfile.Name. -// -// Optionally, a chart might also locate a provenance (.prov) file that it -// can use for cryptographic signing. -type Chart struct { - loader chartLoader -} - -// Close the chart. -// -// Charts should always be closed when no longer needed. -func (c *Chart) Close() error { - return c.loader.close() -} - -// Chartfile gets the Chartfile (Chart.yaml) for this chart. -func (c *Chart) Chartfile() *Chartfile { - return c.loader.chartfile() -} - -// Dir returns the directory where the charts are located. -func (c *Chart) Dir() string { - return c.loader.dir() -} - -// TemplatesDir returns the directory where the templates are stored. -func (c *Chart) TemplatesDir() string { - return filepath.Join(c.loader.dir(), preTemplates) -} - -// ChartsDir returns the directory where dependency charts are stored. -func (c *Chart) ChartsDir() string { - return filepath.Join(c.loader.dir(), preCharts) -} - -// LoadValues loads the contents of values.yaml into a map -func (c *Chart) LoadValues() (Values, error) { - m, err := chartutil.ReadValuesFile(filepath.Join(c.loader.dir(), preValues)) - if err != nil { - return map[string]interface{}{}, err - } - return m.AsMap(), nil -} - -// ChartDepNames returns the list of chart names found in ChartsDir. -func (c *Chart) ChartDepNames() ([]string, error) { - files, err := ioutil.ReadDir(c.ChartsDir()) - if err != nil { - return nil, err - } - - var deps []string - for _, file := range files { - if file.IsDir() { - deps = append(deps, filepath.Join(c.ChartsDir(), file.Name())) - } - } - - return deps, nil -} - -// chartLoader provides load, close, and save implementations for a chart. -type chartLoader interface { - // Chartfile resturns a *Chartfile for this chart. - chartfile() *Chartfile - // Dir returns a directory where the chart can be accessed. - dir() string - - // Close cleans up a chart. - close() error -} - -type dirChart struct { - chartyaml *Chartfile - chartdir string -} - -func (d *dirChart) chartfile() *Chartfile { - return d.chartyaml -} - -func (d *dirChart) dir() string { - return d.chartdir -} - -func (d *dirChart) close() error { - return nil -} - -type tarChart struct { - chartyaml *Chartfile - tmpDir string -} - -func (t *tarChart) chartfile() *Chartfile { - return t.chartyaml -} - -func (t *tarChart) dir() string { - return t.tmpDir -} - -func (t *tarChart) close() error { - // Remove the temp directory. - return os.RemoveAll(t.tmpDir) -} - -// Create creates a new chart in a directory. -// -// Inside of dir, this will create a directory based on the name of -// chartfile.Name. It will then write the Chart.yaml into this directory and -// create the (empty) appropriate directories. -// -// The returned *Chart will point to the newly created directory. -// -// If dir does not exist, this will return an error. -// If Chart.yaml or any directories cannot be created, this will return an -// error. In such a case, this will attempt to clean up by removing the -// new chart directory. -func Create(chartfile *Chartfile, dir string) (*Chart, error) { - path, err := filepath.Abs(dir) - if err != nil { - return nil, err - } - - if fi, err := os.Stat(path); err != nil { - return nil, err - } else if !fi.IsDir() { - return nil, fmt.Errorf("no such directory %s", path) - } - - n := fname(chartfile.Name) - cdir := filepath.Join(path, n) - if fi, err := os.Stat(cdir); err == nil && !fi.IsDir() { - return nil, fmt.Errorf("file %s already exists and is not a directory", cdir) - } - if err := os.MkdirAll(cdir, 0755); err != nil { - return nil, err - } - - if err := chartfile.Save(filepath.Join(cdir, ChartfileName)); err != nil { - return nil, err - } - - val := []byte(fmt.Sprintf(defaultValues, chartfile.Name)) - if err := ioutil.WriteFile(filepath.Join(cdir, preValues), val, 0644); err != nil { - return nil, err - } - - for _, d := range []string{preTemplates, preCharts} { - if err := os.MkdirAll(filepath.Join(cdir, d), 0755); err != nil { - return nil, err - } - } - - return &Chart{ - loader: &dirChart{chartyaml: chartfile, chartdir: cdir}, - }, nil -} - -// Expand uncompresses and extracts a chart into the specified directory. -func Expand(dir string, r io.Reader) error { - gr, err := gzip.NewReader(r) - if err != nil { - return err - } - defer gr.Close() - tr := tar.NewReader(gr) - for { - header, err := tr.Next() - if err == io.EOF { - break - } else if err != nil { - return err - } - - path := filepath.Clean(filepath.Join(dir, header.Name)) - info := header.FileInfo() - if info.IsDir() { - if err = os.MkdirAll(path, info.Mode()); err != nil { - return err - } - continue - } - - file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode()) - if err != nil { - return err - } - defer file.Close() - _, err = io.Copy(file, tr) - if err != nil { - return err - } - } - return nil -} - -// fname prepares names for the filesystem -func fname(name string) string { - // Right now, we don't do anything. Do we need to encode any particular - // characters? What characters are legal in a chart name, but not in file - // names on Windows, Linux, or OSX. - return name -} - -// LoadDir loads an entire chart from a directory. -// -// This includes the Chart.yaml (*Chartfile) and all of the manifests. -// -// If you are just reading the Chart.yaml file, it is substantially more -// performant to use LoadChartfile. -func LoadDir(chart string) (*Chart, error) { - dir, err := filepath.Abs(chart) - if err != nil { - return nil, fmt.Errorf("%s is not a valid path", chart) - } - - if fi, err := os.Stat(dir); err != nil { - return nil, err - } else if !fi.IsDir() { - return nil, fmt.Errorf("%s is not a directory", chart) - } - - cf, err := LoadChartfile(filepath.Join(dir, "Chart.yaml")) - if err != nil { - return nil, err - } - - cl := &dirChart{ - chartyaml: cf, - chartdir: dir, - } - - return &Chart{ - loader: cl, - }, nil -} - -// LoadChart loads an entire chart archive. -// -// The following are valid values for 'chfi': -// -// - relative path to the chart archive -// - absolute path to the chart archive -// - name of the chart directory -// -func LoadChart(chfi string) (*Chart, error) { - path, err := filepath.Abs(chfi) - if err != nil { - return nil, err - } - - fi, err := os.Stat(path) - if err != nil { - return nil, err - } - - if fi.IsDir() { - return LoadDir(path) - } - - return Load(path) -} - -// LoadData loads a chart from data, where data is a []byte containing a gzipped tar file. -func LoadData(data []byte) (*Chart, error) { - return LoadDataFromReader(bytes.NewBuffer(data)) -} - -// Load loads a chart from a chart archive. -// -// A chart archive is a gzipped tar archive that follows the Chart format -// specification. -func Load(archive string) (*Chart, error) { - if fi, err := os.Stat(archive); err != nil { - return nil, err - } else if fi.IsDir() { - return nil, errors.New("cannot load a directory with chart.Load()") - } - - raw, err := os.Open(archive) - if err != nil { - return nil, err - } - defer raw.Close() - - return LoadDataFromReader(raw) -} - -// LoadDataFromReader loads a chart from a reader -func LoadDataFromReader(r io.Reader) (*Chart, error) { - unzipped, err := gzip.NewReader(r) - if err != nil { - return nil, err - } - defer unzipped.Close() - - untarred := tar.NewReader(unzipped) - c, err := loadTar(untarred) - if err != nil { - return nil, err - } - - cf, err := LoadChartfile(filepath.Join(c.tmpDir, ChartfileName)) - if err != nil { - return nil, err - } - c.chartyaml = cf - return &Chart{loader: c}, nil -} - -func loadTar(r *tar.Reader) (*tarChart, error) { - td, err := ioutil.TempDir("", "chart-") - if err != nil { - return nil, err - } - - // ioutil.TempDir uses Getenv("TMPDIR"), so there are no guarantees - dir, err := filepath.Abs(td) - if err != nil { - return nil, fmt.Errorf("%s is not a valid path", td) - } - - c := &tarChart{ - chartyaml: &Chartfile{}, - tmpDir: dir, - } - - firstDir := "" - - hdr, err := r.Next() - for err == nil { - // This is to prevent malformed tar attacks. - hdr.Name = filepath.Clean(hdr.Name) - - if firstDir == "" { - fi := hdr.FileInfo() - if fi.IsDir() { - firstDir = hdr.Name - } - } else if strings.HasPrefix(hdr.Name, firstDir) { - // We know this has the prefix, so we know there won't be an error. - rel, _ := filepath.Rel(firstDir, hdr.Name) - - // If tar record is a directory, create one in the tmpdir and return. - if hdr.FileInfo().IsDir() { - os.MkdirAll(filepath.Join(c.tmpDir, rel), 0755) - hdr, err = r.Next() - continue - } - - //dest := filepath.Join(c.tmpDir, rel) - f, err := os.Create(filepath.Join(c.tmpDir, rel)) - if err != nil { - hdr, err = r.Next() - continue - } - if _, err := io.Copy(f, r); err != nil { - } - f.Close() - } - hdr, err = r.Next() - } - - if err != nil && err != io.EOF { - c.close() - return c, err - } - return c, nil -} - -// Member is a file in a chart. -type Member struct { - Path string `json:"path"` // Path from the root of the chart. - Content []byte `json:"content"` // Base64 encoded content. -} - -// LoadTemplates loads the members of TemplatesDir(). -func (c *Chart) LoadTemplates() ([]*Member, error) { - dir := c.TemplatesDir() - return c.loadDirectory(dir) -} - -// loadDirectory loads the members of a directory. -func (c *Chart) loadDirectory(dir string) ([]*Member, error) { - files, err := ioutil.ReadDir(dir) - if err != nil { - return nil, err - } - - members := []*Member{} - for _, file := range files { - filename := filepath.Join(dir, file.Name()) - if !file.IsDir() { - addition, err := c.loadMember(filename) - if err != nil { - return nil, err - } - - members = append(members, addition) - } else { - additions, err := c.loadDirectory(filename) - if err != nil { - return nil, err - } - - members = append(members, additions...) - } - } - - return members, nil -} - -// LoadMember loads a chart member from a given path where path is the root of the chart. -func (c *Chart) LoadMember(path string) (*Member, error) { - filename := filepath.Join(c.loader.dir(), path) - return c.loadMember(filename) -} - -// loadMember loads and base 64 encodes a file. -func (c *Chart) loadMember(filename string) (*Member, error) { - dir := c.Dir() - if !strings.HasPrefix(filename, dir) { - err := fmt.Errorf("File %s is outside chart directory %s", filename, dir) - return nil, err - } - - content, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - - path := strings.TrimPrefix(filename, dir) - path = strings.TrimLeft(path, "/") - result := &Member{ - Path: path, - Content: content, - } - - return result, nil -} - -// Content is abstraction for the contents of a chart. -type Content struct { - Chartfile *Chartfile `json:"chartfile"` - Members []*Member `json:"members"` -} - -// LoadContent loads contents of a chart directory into Content -func (c *Chart) LoadContent() (*Content, error) { - ms, err := c.loadDirectory(c.Dir()) - if err != nil { - return nil, err - } - - cc := &Content{ - Chartfile: c.Chartfile(), - Members: ms, - } - - return cc, nil -} diff --git a/pkg/chart/chart_test.go b/pkg/chart/chart_test.go deleted file mode 100644 index 6ed4e4f84..000000000 --- a/pkg/chart/chart_test.go +++ /dev/null @@ -1,308 +0,0 @@ -/* -Copyright 2015 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 chart - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "reflect" - "testing" -) - -const ( - testfile = "testdata/frobnitz/Chart.yaml" - testdir = "testdata/frobnitz/" - testarchive = "testdata/frobnitz-0.0.1.tgz" - testmember = "templates/template.tpl" - expectedTemplate = "Hello {{.Name | default \"world\"}}\n" -) - -// Type canaries. If these fail, they will fail at compile time. -var _ chartLoader = &dirChart{} -var _ chartLoader = &tarChart{} - -func TestLoadDir(t *testing.T) { - - c, err := LoadDir(testdir) - if err != nil { - t.Errorf("Failed to load chart: %s", err) - } - - if c.Chartfile().Name != "frobnitz" { - t.Errorf("Expected chart name to be 'frobnitz'. Got '%s'.", c.Chartfile().Name) - } -} - -func TestCreate(t *testing.T) { - tdir, err := ioutil.TempDir("", "helm-") - if err != nil { - t.Fatal(err) - } - defer os.RemoveAll(tdir) - - cf := &Chartfile{Name: "foo"} - - c, err := Create(cf, tdir) - if err != nil { - t.Fatal(err) - } - - dir := filepath.Join(tdir, "foo") - - if c.Chartfile().Name != "foo" { - t.Errorf("Expected name to be 'foo', got %q", c.Chartfile().Name) - } - - for _, d := range []string{preTemplates, preCharts} { - if fi, err := os.Stat(filepath.Join(dir, d)); err != nil { - t.Errorf("Expected %s dir: %s", d, err) - } else if !fi.IsDir() { - t.Errorf("Expected %s to be a directory.", d) - } - } - - for _, f := range []string{ChartfileName, preValues} { - if fi, err := os.Stat(filepath.Join(dir, f)); err != nil { - t.Errorf("Expected %s file: %s", f, err) - } else if fi.IsDir() { - t.Errorf("Expected %s to be a fle.", f) - } - } - -} - -func TestLoad(t *testing.T) { - c, err := Load(testarchive) - if err != nil { - t.Errorf("Failed to load chart: %s", err) - return - } - defer c.Close() - - if c.Chartfile() == nil { - t.Error("No chartfile was loaded.") - return - } - - if c.Chartfile().Name != "frobnitz" { - t.Errorf("Expected name to be frobnitz, got %q", c.Chartfile().Name) - } -} - -func TestLoadData(t *testing.T) { - data, err := ioutil.ReadFile(testarchive) - if err != nil { - t.Errorf("Failed to read testarchive file: %s", err) - return - } - c, err := LoadData(data) - if err != nil { - t.Errorf("Failed to load chart: %s", err) - return - } - if c.Chartfile() == nil { - t.Error("No chartfile was loaded.") - return - } - - if c.Chartfile().Name != "frobnitz" { - t.Errorf("Expected name to be frobnitz, got %q", c.Chartfile().Name) - } -} - -func TestChart(t *testing.T) { - c, err := LoadDir(testdir) - if err != nil { - t.Errorf("Failed to load chart: %s", err) - } - defer c.Close() - - if c.Dir() != c.loader.dir() { - t.Errorf("Unexpected location for directory: %s", c.Dir()) - } - - if c.Chartfile().Name != c.loader.chartfile().Name { - t.Errorf("Unexpected chart file name: %s", c.Chartfile().Name) - } - - dir := c.Dir() - d := c.ChartsDir() - if d != filepath.Join(dir, preCharts) { - t.Errorf("Unexpectedly, charts are in %s", d) - } - - d = c.TemplatesDir() - if d != filepath.Join(dir, preTemplates) { - t.Errorf("Unexpectedly, templates are in %s", d) - } -} - -func TestLoadTemplates(t *testing.T) { - c, err := LoadDir(testdir) - if err != nil { - t.Errorf("Failed to load chart: %s", err) - } - - members, err := c.LoadTemplates() - if members == nil { - t.Fatalf("Cannot load templates: unknown error") - } - - if err != nil { - t.Fatalf("Cannot load templates: %s", err) - } - - dir := c.TemplatesDir() - files, err := ioutil.ReadDir(dir) - if err != nil { - t.Fatalf("Cannot read template directory: %s", err) - } - - if len(members) != len(files) { - t.Fatalf("Expected %d templates, got %d", len(files), len(members)) - } - - root := c.loader.dir() - for _, file := range files { - path := filepath.Join(preTemplates, file.Name()) - if err := findMember(root, path, members); err != nil { - t.Fatal(err) - } - } -} - -func findMember(root, path string, members []*Member) error { - for _, member := range members { - if member.Path == path { - filename := filepath.Join(root, path) - return compareContent(filename, member.Content) - } - } - - return fmt.Errorf("Template not found: %s", path) -} - -func TestLoadMember(t *testing.T) { - c, err := LoadDir(testdir) - if err != nil { - t.Errorf("Failed to load chart: %s", err) - } - - member, err := c.LoadMember(testmember) - if member == nil { - t.Fatalf("Cannot load member %s: unknown error", testmember) - } - - if err != nil { - t.Fatalf("Cannot load member %s: %s", testmember, err) - } - - if member.Path != testmember { - t.Errorf("Expected member path %s, got %s", testmember, member.Path) - } - - filename := filepath.Join(c.loader.dir(), testmember) - if err := compareContent(filename, member.Content); err != nil { - t.Fatal(err) - } -} - -func TestLoadContent(t *testing.T) { - c, err := LoadDir(testdir) - if err != nil { - t.Errorf("Failed to load chart: %s", err) - } - - content, err := c.LoadContent() - if err != nil { - t.Errorf("Failed to load chart content: %s", err) - } - - want := c.Chartfile() - have := content.Chartfile - if !reflect.DeepEqual(want, have) { - t.Errorf("Unexpected chart file\nwant:\n%v\nhave:\n%v\n", want, have) - } - - for _, member := range content.Members { - have := member.Content - wantMember, err := c.LoadMember(member.Path) - if err != nil { - t.Errorf("Failed to load chart member: %s", err) - } - - t.Logf("%s:\n%s\n\n", member.Path, member.Content) - want := wantMember.Content - if !reflect.DeepEqual(want, have) { - t.Errorf("Unexpected chart member %s\nwant:\n%v\nhave:\n%v\n", member.Path, want, have) - } - } -} - -func compareContent(filename string, content []byte) error { - compare, err := ioutil.ReadFile(filename) - if err != nil { - return fmt.Errorf("Cannot read test file %s: %s", filename, err) - } - - if !reflect.DeepEqual(compare, content) { - return fmt.Errorf("Expected member content\n%v\ngot\n%v", compare, content) - } - - return nil -} - -func TestExpand(t *testing.T) { - r, err := os.Open(testarchive) - if err != nil { - t.Errorf("Failed to read testarchive file: %s", err) - return - } - - td, err := ioutil.TempDir("", "helm-unittest-chart-") - if err != nil { - t.Errorf("Failed to create tempdir: %s", err) - return - } - - err = Expand(td, r) - if err != nil { - t.Errorf("Failed to expand testarchive file: %s", err) - } - - fi, err := os.Lstat(td + "/frobnitz/Chart.yaml") - if err != nil { - t.Errorf("Failed to stat Chart.yaml from expanded archive: %s", err) - } - if fi.Name() != "Chart.yaml" { - t.Errorf("Didn't get the right file name from stat, expected Chart.yaml, got: %s", fi.Name()) - } - - tr, err := os.Open(td + "/frobnitz/templates/template.tpl") - if err != nil { - t.Errorf("Failed to open template.tpl from expanded archive: %s", err) - } - c, err := ioutil.ReadAll(tr) - if err != nil { - t.Errorf("Failed to read contents of template.tpl from expanded archive: %s", err) - } - if string(c) != expectedTemplate { - t.Errorf("Contents of the expanded template differ, wanted '%s' got '%s'", expectedTemplate, c) - } -} diff --git a/pkg/chart/chartfile.go b/pkg/chart/chartfile.go deleted file mode 100644 index effde9cc1..000000000 --- a/pkg/chart/chartfile.go +++ /dev/null @@ -1,75 +0,0 @@ -/* -Copyright 2015 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 chart - -import ( - "io/ioutil" - - "github.com/Masterminds/semver" - "gopkg.in/yaml.v2" -) - -// Chartfile describes a Helm Chart (e.g. Chart.yaml) -type Chartfile struct { - Name string `yaml:"name"` - Description string `yaml:"description"` - Version string `yaml:"version"` - Keywords []string `yaml:"keywords,omitempty"` - Maintainers []*Maintainer `yaml:"maintainers,omitempty"` - Source []string `yaml:"sources,omitempty"` - Home string `yaml:"home"` -} - -// Maintainer describes a chart maintainer. -type Maintainer struct { - Name string `yaml:"name"` - Email string `yaml:"email,omitempty"` -} - -// LoadChartfile loads a Chart.yaml file into a *Chart. -func LoadChartfile(filename string) (*Chartfile, error) { - b, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - var y Chartfile - err = yaml.Unmarshal(b, &y) - if err != nil { - return nil, err - } - // Validate that the Version is actually a valid semver version - _, err = semver.NewVersion(y.Version) - if err != nil { - return nil, err - } - return &y, nil -} - -// Save saves a Chart.yaml file -func (c *Chartfile) Save(filename string) error { - b, err := c.Marshal() - if err != nil { - return err - } - - return ioutil.WriteFile(filename, b, 0644) -} - -// Marshal encodes the chart file into YAML. -func (c *Chartfile) Marshal() ([]byte, error) { - return yaml.Marshal(c) -} diff --git a/pkg/chart/chartfile_test.go b/pkg/chart/chartfile_test.go deleted file mode 100644 index 3c5713499..000000000 --- a/pkg/chart/chartfile_test.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2015 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 chart - -import ( - "testing" -) - -const badChart = "testdata/badchartversion/Chart.yaml" - -func TestLoadChartfile(t *testing.T) { - f, err := LoadChartfile(testfile) - if err != nil { - t.Errorf("Failed to open %s: %s", testfile, err) - return - } - - if f.Name != "frobnitz" { - t.Errorf("Expected frobnitz, got %s", f.Name) - } - - if len(f.Maintainers) != 2 { - t.Errorf("Expected 2 maintainers, got %d", len(f.Maintainers)) - } - - if f.Source[0] != "https://example.com/foo/bar" { - t.Errorf("Expected https://example.com/foo/bar, got %s", f.Source) - } -} - -func TestLoadChartfileFailsWithInvalidVersion(t *testing.T) { - f, err := LoadChartfile(badChart) - if err == nil { - t.Errorf("LoadChartFile didn't fail with invalid version") - return - } - if err.Error() != "Invalid Semantic Version" { - t.Errorf("LoadChartFile didn't return the expected error") - return - } - if f != nil { - t.Errorf("LoadChartFile returned a chart despite error") - return - } -} diff --git a/pkg/chart/doc.go b/pkg/chart/doc.go deleted file mode 100644 index ec0627506..000000000 --- a/pkg/chart/doc.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2015 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 chart implements the Chart format. - -This package provides tools for working with the Chart format, including the -Chartfile (chart.yaml) and compressed chart archives. -*/ -package chart diff --git a/pkg/chart/save.go b/pkg/chart/save.go deleted file mode 100644 index 5b8b302ed..000000000 --- a/pkg/chart/save.go +++ /dev/null @@ -1,113 +0,0 @@ -/* -Copyright 2015 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 chart - -import ( - "archive/tar" - "compress/gzip" - "fmt" - "io" - "os" - "path/filepath" -) - -// Save creates an archived chart to the given directory. -// -// This takes an existing chart and a destination directory. -// -// If the directory is /foo, and the chart is named bar, with version 1.0.0, this -// will generate /foo/bar-1.0.0.tgz. -// -// This returns the absolute path to the chart archive file. -func Save(c *Chart, outDir string) (string, error) { - // Create archive - if fi, err := os.Stat(outDir); err != nil { - return "", err - } else if !fi.IsDir() { - return "", fmt.Errorf("location %s is not a directory", outDir) - } - - cfile := c.Chartfile() - dir := c.Dir() - pdir := filepath.Dir(dir) - filename := fmt.Sprintf("%s-%s.tgz", fname(cfile.Name), cfile.Version) - filename = filepath.Join(outDir, filename) - - // Fail early if the YAML is borked. - if err := cfile.Save(filepath.Join(dir, ChartfileName)); err != nil { - return "", err - } - - // Create file. - f, err := os.Create(filename) - if err != nil { - return "", err - } - - // Wrap in gzip writer - zipper := gzip.NewWriter(f) - zipper.Header.Extra = headerBytes - zipper.Header.Comment = "Helm" - - // Wrap in tar writer - twriter := tar.NewWriter(zipper) - rollback := false - defer func() { - twriter.Close() - zipper.Close() - f.Close() - if rollback { - os.Remove(filename) - } - }() - - err = filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { - if err != nil { - return err - } - hdr, err := tar.FileInfoHeader(fi, ".") - if err != nil { - return err - } - - relpath, err := filepath.Rel(pdir, path) - if err != nil { - return err - } - hdr.Name = relpath - - twriter.WriteHeader(hdr) - - // Skip directories. - if fi.IsDir() { - return nil - } - - in, err := os.Open(path) - if err != nil { - return err - } - _, err = io.Copy(twriter, in) - in.Close() - return err - }) - if err != nil { - rollback = true - return filename, err - } - return filename, nil -} diff --git a/pkg/chart/save_test.go b/pkg/chart/save_test.go deleted file mode 100644 index 5722e987f..000000000 --- a/pkg/chart/save_test.go +++ /dev/null @@ -1,120 +0,0 @@ -/* -Copyright 2015 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 chart - -import ( - "archive/tar" - "compress/gzip" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - "testing" -) - -const sprocketdir = "testdata/sprocket" - -func TestSave(t *testing.T) { - - tmpdir, err := ioutil.TempDir("", "helm-") - if err != nil { - t.Fatal("Could not create temp directory") - } - t.Logf("Temp: %s", tmpdir) - // Because of the defer, don't call t.Fatal in the remainder of this - // function. - defer os.RemoveAll(tmpdir) - - c, err := LoadDir(sprocketdir) - if err != nil { - t.Errorf("Failed to load %s: %s", sprocketdir, err) - return - } - - tfile, err := Save(c, tmpdir) - if err != nil { - t.Errorf("Failed to save %s to %s: %s", c.Chartfile().Name, tmpdir, err) - return - } - - b := filepath.Base(tfile) - expectname := "sprocket-1.2.3-alpha.1+12345.tgz" - if b != expectname { - t.Errorf("Expected %q, got %q", expectname, b) - } - - files, err := getAllFiles(tfile) - if err != nil { - t.Errorf("Could not extract files: %s", err) - } - - // Files should come back in order. - expect := []string{ - "sprocket", - "sprocket/Chart.yaml", - "sprocket/values.toml", - "sprocket/templates", - "sprocket/templates/template.tpl", - } - if len(expect) != len(files) { - t.Errorf("Expected %d files, found %d", len(expect), len(files)) - return - } - sort.Strings(files) - sort.Strings(expect) - for i := 0; i < len(expect); i++ { - if expect[i] != files[i] { - t.Errorf("Expected file %q, got %q", expect[i], files[i]) - } - } -} - -func getAllFiles(tfile string) ([]string, error) { - f1, err := os.Open(tfile) - if err != nil { - return []string{}, err - } - f2, err := gzip.NewReader(f1) - if err != nil { - f1.Close() - return []string{}, err - } - - if f2.Header.Comment != "Helm" { - return []string{}, fmt.Errorf("Expected header Helm. Got %s", f2.Header.Comment) - } - if string(f2.Header.Extra) != string(headerBytes) { - return []string{}, fmt.Errorf("Expected header signature. Got %v", f2.Header.Extra) - } - - f3 := tar.NewReader(f2) - - files := []string{} - var e error - var hdr *tar.Header - for e == nil { - hdr, e = f3.Next() - if e == nil { - files = append(files, hdr.Name) - } - } - - f2.Close() - f1.Close() - return files, nil -} diff --git a/pkg/chart/testdata/README.md b/pkg/chart/testdata/README.md deleted file mode 100644 index a3aa71f14..000000000 --- a/pkg/chart/testdata/README.md +++ /dev/null @@ -1 +0,0 @@ -This directory houses charts used in testing. diff --git a/pkg/chart/testdata/badchartversion/Chart.yaml b/pkg/chart/testdata/badchartversion/Chart.yaml deleted file mode 100644 index 4407b54c3..000000000 --- a/pkg/chart/testdata/badchartversion/Chart.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: frobnitz -description: This is a frobniz. -version: "garbage" -keywords: - - bad bad chart file -maintainers: - - name: The Helm Team - email: helm@example.com - - name: Someone Else - email: nobody@example.com -sources: - - https://example.com/foo/bar -home: http://example.com diff --git a/pkg/chart/testdata/coleridge.toml b/pkg/chart/testdata/coleridge.toml deleted file mode 100644 index bd16a8c84..000000000 --- a/pkg/chart/testdata/coleridge.toml +++ /dev/null @@ -1,11 +0,0 @@ -poet = "Coleridge" -title = "Rime of the Ancient Mariner" -stanza = ["at", "length", "did", "cross", "an", "Albatross"] - -[mariner] -with = "crossbow" -shot = "ALBATROSS" - -[water.water] -where = "everywhere" -nor = "any drop to drink" diff --git a/pkg/chart/testdata/frobnitz-0.0.1.tgz b/pkg/chart/testdata/frobnitz-0.0.1.tgz deleted file mode 100644 index 38bfb862e..000000000 Binary files a/pkg/chart/testdata/frobnitz-0.0.1.tgz and /dev/null differ diff --git a/pkg/chart/testdata/frobnitz/Chart.toml b/pkg/chart/testdata/frobnitz/Chart.toml deleted file mode 100644 index 0f4c51d57..000000000 --- a/pkg/chart/testdata/frobnitz/Chart.toml +++ /dev/null @@ -1,15 +0,0 @@ -name = "frobnitz" -description = "This is a frobniz." -version = "1.2.3-alpha.1+12345" -keywords = ["frobnitz", "sprocket", "dodad"] -home = "http://example.com" -source = [ - "https://example.com/foo/bar", - "https://github.com/example/foo" -] -[[maintainer]] - name = "The Helm Team" - email = "helm@example.com" -[[maintainer]] - name = "Someone Else" - email = "nobody@example.com" diff --git a/pkg/chart/testdata/frobnitz/Chart.yaml b/pkg/chart/testdata/frobnitz/Chart.yaml deleted file mode 100644 index 1920d219b..000000000 --- a/pkg/chart/testdata/frobnitz/Chart.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: frobnitz -description: This is a frobniz. -version: "1.2.3-alpha.1+12345" -keywords: - - frobnitz - - sprocket - - dodad -maintainers: - - name: The Helm Team - email: helm@example.com - - name: Someone Else - email: nobody@example.com -sources: - - https://example.com/foo/bar -home: http://example.com diff --git a/pkg/chart/testdata/frobnitz/INSTALL.txt b/pkg/chart/testdata/frobnitz/INSTALL.txt deleted file mode 100644 index 2010438c2..000000000 --- a/pkg/chart/testdata/frobnitz/INSTALL.txt +++ /dev/null @@ -1 +0,0 @@ -This is an install document. The client may display this. diff --git a/pkg/chart/testdata/frobnitz/LICENSE b/pkg/chart/testdata/frobnitz/LICENSE deleted file mode 100644 index 6121943b1..000000000 --- a/pkg/chart/testdata/frobnitz/LICENSE +++ /dev/null @@ -1 +0,0 @@ -LICENSE placeholder. diff --git a/pkg/chart/testdata/frobnitz/README.md b/pkg/chart/testdata/frobnitz/README.md deleted file mode 100644 index 8cf4cc3d7..000000000 --- a/pkg/chart/testdata/frobnitz/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Frobnitz - -This is an example chart. - -## Usage - -This is an example. It has no usage. - -## Development - -For developer info, see the top-level repository. diff --git a/pkg/chart/testdata/frobnitz/docs/README.md b/pkg/chart/testdata/frobnitz/docs/README.md deleted file mode 100644 index d40747caf..000000000 --- a/pkg/chart/testdata/frobnitz/docs/README.md +++ /dev/null @@ -1 +0,0 @@ -This is a placeholder for documentation. diff --git a/pkg/chart/testdata/frobnitz/icon.svg b/pkg/chart/testdata/frobnitz/icon.svg deleted file mode 100644 index 892130606..000000000 --- a/pkg/chart/testdata/frobnitz/icon.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - Example icon - - - diff --git a/pkg/chart/testdata/frobnitz/templates/template.tpl b/pkg/chart/testdata/frobnitz/templates/template.tpl deleted file mode 100644 index c651ee6a0..000000000 --- a/pkg/chart/testdata/frobnitz/templates/template.tpl +++ /dev/null @@ -1 +0,0 @@ -Hello {{.Name | default "world"}} diff --git a/pkg/chart/testdata/frobnitz/values.toml b/pkg/chart/testdata/frobnitz/values.toml deleted file mode 100644 index 6fc24051f..000000000 --- a/pkg/chart/testdata/frobnitz/values.toml +++ /dev/null @@ -1,6 +0,0 @@ -# A values file contains configuration. - -name = "Some Name" - -[section] -name = "Name in a section" diff --git a/pkg/chart/testdata/sprocket/Chart.yaml b/pkg/chart/testdata/sprocket/Chart.yaml deleted file mode 100644 index b09e10439..000000000 --- a/pkg/chart/testdata/sprocket/Chart.yaml +++ /dev/null @@ -1,13 +0,0 @@ -name: sprocket -description: This is a sprocket" -version: 1.2.3-alpha.1+12345 -keywords: -- frobnitz -- sprocket -- dodad -maintainers: -- name: The Helm Team - email: helm@example.com -- name: Someone Else - email: nobody@example.com -home: http://example.com diff --git a/pkg/chart/testdata/sprocket/templates/template.tpl b/pkg/chart/testdata/sprocket/templates/template.tpl deleted file mode 100644 index c651ee6a0..000000000 --- a/pkg/chart/testdata/sprocket/templates/template.tpl +++ /dev/null @@ -1 +0,0 @@ -Hello {{.Name | default "world"}} diff --git a/pkg/chart/testdata/sprocket/values.toml b/pkg/chart/testdata/sprocket/values.toml deleted file mode 100644 index 6fc24051f..000000000 --- a/pkg/chart/testdata/sprocket/values.toml +++ /dev/null @@ -1,6 +0,0 @@ -# A values file contains configuration. - -name = "Some Name" - -[section] -name = "Name in a section" diff --git a/pkg/chart/values.go b/pkg/chart/values.go deleted file mode 100644 index b00da1b3e..000000000 --- a/pkg/chart/values.go +++ /dev/null @@ -1,75 +0,0 @@ -package chart - -import ( - "errors" - "io" - "io/ioutil" - "strings" - - "github.com/BurntSushi/toml" -) - -// ErrNoTable indicates that a chart does not have a matching table. -var ErrNoTable = errors.New("no table") - -// Values represents a collection of chart values. -type Values map[string]interface{} - -// Table gets a table (TOML subsection) from a Values object. -// -// The table is returned as a Values. -// -// Compound table names may be specified with dots: -// -// foo.bar -// -// The above will be evaluated as "The table bar inside the table -// foo". -// -// An ErrNoTable is returned if the table does not exist. -func (v Values) Table(name string) (Values, error) { - names := strings.Split(name, ".") - table := v - var err error - - for _, n := range names { - table, err = tableLookup(table, n) - if err != nil { - return table, err - } - } - return table, err -} - -// Encode writes serialized Values information to the given io.Writer. -func (v Values) Encode(w io.Writer) error { - return toml.NewEncoder(w).Encode(v) -} - -func tableLookup(v Values, simple string) (Values, error) { - v2, ok := v[simple] - if !ok { - return v, ErrNoTable - } - vv, ok := v2.(map[string]interface{}) - if !ok { - return vv, ErrNoTable - } - return vv, nil -} - -// ReadValues will parse TOML byte data into a Values. -func ReadValues(data []byte) (Values, error) { - out := map[string]interface{}{} - err := toml.Unmarshal(data, out) - return out, err -} - -// ReadValuesFile will parse a TOML file into a Values. -func ReadValuesFile(filename string) (Values, error) { - data, err := ioutil.ReadFile(filename) - if err != nil { - return map[string]interface{}{}, err - } - return ReadValues(data) -} diff --git a/pkg/chart/values_test.go b/pkg/chart/values_test.go deleted file mode 100644 index ecb6b3df9..000000000 --- a/pkg/chart/values_test.go +++ /dev/null @@ -1,134 +0,0 @@ -package chart - -import ( - "bytes" - "fmt" - "testing" - "text/template" -) - -func TestReadValues(t *testing.T) { - doc := `# Test TOML parse -poet = "Coleridge" -title = "Rime of the Ancient Mariner" -stanza = ["at", "length", "did", "cross", "an", "Albatross"] - -[mariner] -with = "crossbow" -shot = "ALBATROSS" - -[water.water] -where = "everywhere" -nor = "any drop to drink" -` - - data, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Error parsing bytes: %s", err) - } - matchValues(t, data) -} - -func TestReadValuesFile(t *testing.T) { - data, err := ReadValuesFile("./testdata/coleridge.toml") - if err != nil { - t.Fatalf("Error reading TOML file: %s", err) - } - matchValues(t, data) -} - -func ExampleValues() { - doc := `title="Moby Dick" -[chapter.one] -title = "Loomings" - -[chapter.two] -title = "The Carpet-Bag" - -[chapter.three] -title = "The Spouter Inn" -` - d, err := ReadValues([]byte(doc)) - if err != nil { - panic(err) - } - ch1, err := d.Table("chapter.one") - if err != nil { - panic("could not find chapter one") - } - fmt.Print(ch1["title"]) - // Output: - // Loomings -} - -func TestTable(t *testing.T) { - doc := `title="Moby Dick" -[chapter.one] -title = "Loomings" - -[chapter.two] -title = "The Carpet-Bag" - -[chapter.three] -title = "The Spouter Inn" -` - d, err := ReadValues([]byte(doc)) - if err != nil { - t.Fatalf("Failed to parse the White Whale: %s", err) - } - - if _, err := d.Table("title"); err == nil { - t.Fatalf("Title is not a table.") - } - - if _, err := d.Table("chapter"); err != nil { - t.Fatalf("Failed to get the chapter table: %s\n%v", err, d) - } - - if v, err := d.Table("chapter.one"); err != nil { - t.Errorf("Failed to get chapter.one: %s", err) - } else if v["title"] != "Loomings" { - t.Errorf("Unexpected title: %s", v["title"]) - } - - if _, err := d.Table("chapter.three"); err != nil { - t.Errorf("Chapter three is missing: %s\n%v", err, d) - } - - if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil { - t.Errorf("I think you mean 'Epilogue'") - } -} - -func matchValues(t *testing.T, data map[string]interface{}) { - if data["poet"] != "Coleridge" { - t.Errorf("Unexpected poet: %s", data["poet"]) - } - - if o, err := ttpl("{{len .stanza}}", data); err != nil { - t.Errorf("len stanza: %s", err) - } else if o != "6" { - t.Errorf("Expected 6, got %s", o) - } - - if o, err := ttpl("{{.mariner.shot}}", data); err != nil { - t.Errorf(".mariner.shot: %s", err) - } else if o != "ALBATROSS" { - t.Errorf("Expected that mariner shot ALBATROSS") - } - - if o, err := ttpl("{{.water.water.where}}", data); err != nil { - t.Errorf(".water.water.where: %s", err) - } else if o != "everywhere" { - t.Errorf("Expected water water everywhere") - } -} - -func ttpl(tpl string, v map[string]interface{}) (string, error) { - var b bytes.Buffer - tt := template.Must(template.New("t").Parse(tpl)) - if err := tt.Execute(&b, v); err != nil { - return "", err - } - return b.String(), nil -}