Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions pkg/chartutil/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"time"

"github.com/ghodss/yaml"

Expand Down Expand Up @@ -205,9 +206,10 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
func writeToTar(out *tar.Writer, name string, body []byte) error {
// TODO: Do we need to create dummy parent directory names if none exist?
h := &tar.Header{
Name: filepath.ToSlash(name),
Mode: 0755,
Size: int64(len(body)),
Name: filepath.ToSlash(name),
Mode: 0755,
Size: int64(len(body)),
ModTime: time.Now(),
}
if err := out.WriteHeader(h); err != nil {
return err
Expand Down
80 changes: 80 additions & 0 deletions pkg/chartutil/save_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ limitations under the License.
package chartutil

import (
"archive/tar"
"compress/gzip"
"io"
"io/ioutil"
"os"
"strings"
"testing"
"time"

"github.com/golang/protobuf/ptypes/any"
"k8s.io/helm/pkg/proto/hapi/chart"
Expand Down Expand Up @@ -73,6 +77,82 @@ func TestSave(t *testing.T) {
}
}

func TestSavePreservesTimestamps(t *testing.T) {
// Test executes so quickly that if we don't subtract a second, the
// check will fail because `initialCreateTime` will be identical to the
// written timestamp for the files.
initialCreateTime := time.Now().Add(-1 * time.Second)

tmp, err := ioutil.TempDir("", "helm-")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmp)

c := &chart.Chart{
Metadata: &chart.Metadata{
Name: "ahab",
Version: "1.2.3.4",
},
Values: &chart.Config{
Raw: "ship: Pequod",
},
Files: []*any.Any{
{TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")},
},
}

where, err := Save(c, tmp)
if err != nil {
t.Fatalf("Failed to save: %s", err)
}

allHeaders, err := retrieveAllHeadersFromTar(where)
if err != nil {
t.Fatalf("Failed to parse tar: %v", err)
}

for _, header := range allHeaders {
if header.ModTime.Before(initialCreateTime) {
t.Fatalf("File timestamp not preserved: %v", header.ModTime)
}
}
}

// We could refactor `load.go` to use this `retrieveAllHeadersFromTar` function
// as well, so we are not duplicating components of the code which iterate
// through the tar.
func retrieveAllHeadersFromTar(path string) ([]*tar.Header, error) {
raw, err := os.Open(path)
if err != nil {
return nil, err
}
defer raw.Close()

unzipped, err := gzip.NewReader(raw)
if err != nil {
return nil, err
}
defer unzipped.Close()

tr := tar.NewReader(unzipped)
headers := []*tar.Header{}
for {
hd, err := tr.Next()
if err == io.EOF {
break
}

if err != nil {
return nil, err
}

headers = append(headers, hd)
}

return headers, nil
}

func TestSaveDir(t *testing.T) {
tmp, err := ioutil.TempDir("", "helm-")
if err != nil {
Expand Down