mirror of https://github.com/helm/helm
parent
cfaca7ffb5
commit
4fe37ea634
@ -0,0 +1,124 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
"github.com/kubernetes/deployment-manager/log"
|
||||
)
|
||||
|
||||
// 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()
|
||||
basename := filepath.Base(dir)
|
||||
pdir := filepath.Dir(dir)
|
||||
if basename == "." {
|
||||
basename = fname(cfile.Name)
|
||||
}
|
||||
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 {
|
||||
log.Warn("Removing incomplete archive %s", filename)
|
||||
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()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
rollback = true
|
||||
return filename, err
|
||||
}
|
||||
return filename, nil
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
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"
|
||||
"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/LICENSE",
|
||||
"sprocket/README.md",
|
||||
"sprocket/docs",
|
||||
"sprocket/docs/README.md",
|
||||
"sprocket/hooks",
|
||||
"sprocket/hooks/pre-install.py",
|
||||
"sprocket/icon.svg",
|
||||
"sprocket/templates",
|
||||
"sprocket/templates/placeholder.txt",
|
||||
}
|
||||
if len(expect) != len(files) {
|
||||
t.Errorf("Expected %d files, found %d", len(expect), len(files))
|
||||
return
|
||||
}
|
||||
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
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
name: sprocket
|
||||
description: This is a sprocket.
|
||||
version: 1.2.3-alpha.1+12345
|
||||
home: ""
|
@ -0,0 +1 @@
|
||||
Placeholder for license.
|
@ -0,0 +1,3 @@
|
||||
# Sprocket
|
||||
|
||||
This is an example chart.
|
@ -0,0 +1 @@
|
||||
This is a placeholder for documentation.
|
@ -0,0 +1 @@
|
||||
# Placeholder.
|
After Width: | Height: | Size: 374 B |
@ -0,0 +1 @@
|
||||
This is a placeholder.
|
Loading…
Reference in new issue