From 999b8b2ed0b478cc203c5400fc27a4334b87c807 Mon Sep 17 00:00:00 2001 From: Joel Scoble Date: Wed, 6 Jul 2016 15:42:26 -0500 Subject: [PATCH] file provisioner: download should create all dirs in the destination path --- provisioner/file/provisioner.go | 15 +++++-- provisioner/file/provisioner_test.go | 59 +++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/provisioner/file/provisioner.go b/provisioner/file/provisioner.go index 63c1c0a8d..2b9a6b5fe 100644 --- a/provisioner/file/provisioner.go +++ b/provisioner/file/provisioner.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "os" + "path/filepath" "strings" "github.com/mitchellh/packer/common" @@ -95,12 +96,20 @@ func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { func (p *Provisioner) ProvisionDownload(ui packer.Ui, comm packer.Communicator) error { for _, src := range p.config.Sources { ui.Say(fmt.Sprintf("Downloading %s => %s", src, p.config.Destination)) - - if strings.HasSuffix(p.config.Destination, "/") { - err := os.MkdirAll(p.config.Destination, os.FileMode(0755)) + // ensure destination dir exists. p.config.Destination may either be a file or a dir. + dir := p.config.Destination + // if it doesn't end with a /, set dir as the parent dir + if !strings.HasSuffix(p.config.Destination, "/") { + dir = filepath.Dir(dir) + } + if dir != "" { + err := os.MkdirAll(dir, os.FileMode(0755)) if err != nil { return err } + } + // if the config.Destination was a dir, download the dir + if !strings.HasSuffix(p.config.Destination, "/") { return comm.DownloadDir(src, p.config.Destination, nil) } diff --git a/provisioner/file/provisioner_test.go b/provisioner/file/provisioner_test.go index 6f7cd5ea3..0086ed5ab 100644 --- a/provisioner/file/provisioner_test.go +++ b/provisioner/file/provisioner_test.go @@ -1,11 +1,14 @@ package file import ( - "github.com/mitchellh/packer/packer" + "fmt" "io/ioutil" "os" + "path/filepath" "strings" "testing" + + "github.com/mitchellh/packer/packer" ) func testConfig() map[string]interface{} { @@ -139,3 +142,57 @@ func TestProvisionerProvision_SendsFile(t *testing.T) { t.Fatalf("should upload with source file's data") } } + +func TestProvisionDownloadMkdirAll(t *testing.T) { + tests := []struct { + path string + }{ + {"dir"}, + {"dir/"}, + {"dir/subdir"}, + {"dir/subdir/"}, + {"path/to/dir"}, + {"path/to/dir/"}, + } + tmpDir, err := ioutil.TempDir("", "packer-file") + if err != nil { + t.Fatalf("error tempdir: %s", err) + } + defer os.RemoveAll(tmpDir) + tf, err := ioutil.TempFile(tmpDir, "packer") + if err != nil { + t.Fatalf("error tempfile: %s", err) + } + fmt.Println(tf.Name()) + defer os.Remove(tf.Name()) + + config := map[string]interface{}{ + "source": tf.Name(), + } + var p Provisioner + for _, test := range tests { + path := filepath.Join(tmpDir, test.path) + config["destination"] = filepath.Join(path, "something") + if err := p.Prepare(config); err != nil { + t.Fatalf("err: %s", err) + } + ui := &stubUi{} + comm := &packer.MockCommunicator{} + err = p.ProvisionDownload(ui, comm) + if err != nil { + t.Fatalf("should successfully provision: %s", err) + } + + if !strings.Contains(ui.sayMessages, tf.Name()) { + t.Fatalf("should print source filename") + } + + if !strings.Contains(ui.sayMessages, "something") { + t.Fatalf("should print destination filename") + } + + if _, err := os.Stat(path); err != nil { + t.Fatalf("stat of download dir should not error: %s", err) + } + } +}