From 03b6dfd7e3280062cb34a0e5be3536a157d2a346 Mon Sep 17 00:00:00 2001 From: Nevins Date: Mon, 23 Jan 2017 17:17:45 -0500 Subject: [PATCH] adding (backwards compatible) support for providing multiple source filename and content (#11271) --- builtin/providers/archive/archiver.go | 1 + .../archive/data_source_archive_file.go | 39 +++++++++++++++++++ .../archive/data_source_archive_file_test.go | 18 +++++++++ builtin/providers/archive/zip_archiver.go | 29 ++++++++++++++ .../providers/archive/zip_archiver_test.go | 17 ++++++++ 5 files changed, 104 insertions(+) diff --git a/builtin/providers/archive/archiver.go b/builtin/providers/archive/archiver.go index cdf2c3a68..c216f4620 100644 --- a/builtin/providers/archive/archiver.go +++ b/builtin/providers/archive/archiver.go @@ -9,6 +9,7 @@ type Archiver interface { ArchiveContent(content []byte, infilename string) error ArchiveFile(infilename string) error ArchiveDir(indirname string) error + ArchiveMultiple(content map[string][]byte) error } type ArchiverBuilder func(filepath string) Archiver diff --git a/builtin/providers/archive/data_source_archive_file.go b/builtin/providers/archive/data_source_archive_file.go index d99b52f56..218629cba 100644 --- a/builtin/providers/archive/data_source_archive_file.go +++ b/builtin/providers/archive/data_source_archive_file.go @@ -1,6 +1,7 @@ package archive import ( + "bytes" "crypto/md5" "crypto/sha1" "crypto/sha256" @@ -11,6 +12,7 @@ import ( "os" "path" + "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" ) @@ -24,6 +26,33 @@ func dataSourceFile() *schema.Resource { Required: true, ForceNew: true, }, + "source": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "content": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "filename": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + ConflictsWith: []string{"source_file", "source_dir", "source_content", "source_content_filename"}, + Set: func(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", m["filename"].(string))) + buf.WriteString(fmt.Sprintf("%s-", m["content"].(string))) + return hashcode.String(buf.String()) + }, + }, "source_content": &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -138,6 +167,16 @@ func archive(d *schema.ResourceData) error { if err := archiver.ArchiveContent([]byte(content), filename.(string)); err != nil { return fmt.Errorf("error archiving content: %s", err) } + } else if v, ok := d.GetOk("source"); ok { + vL := v.(*schema.Set).List() + content := make(map[string][]byte) + for _, v := range vL { + src := v.(map[string]interface{}) + content[src["filename"].(string)] = []byte(src["content"].(string)) + } + if err := archiver.ArchiveMultiple(content); err != nil { + return fmt.Errorf("error archiving content: %s", err) + } } else { return fmt.Errorf("one of 'source_dir', 'source_file', 'source_content_filename' must be specified") } diff --git a/builtin/providers/archive/data_source_archive_file_test.go b/builtin/providers/archive/data_source_archive_file_test.go index 7701b57a7..e1ccc4705 100644 --- a/builtin/providers/archive/data_source_archive_file_test.go +++ b/builtin/providers/archive/data_source_archive_file_test.go @@ -51,6 +51,13 @@ func TestAccArchiveFile_Basic(t *testing.T) { r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), ), }, + r.TestStep{ + Config: testAccArchiveFileMultiConfig, + Check: r.ComposeTestCheckFunc( + testAccArchiveFileExists("zip_file_acc_test.zip", &fileSize), + r.TestCheckResourceAttrPtr("data.archive_file.foo", "output_size", &fileSize), + ), + }, r.TestStep{ Config: testAccArchiveFileOutputPath, Check: r.ComposeTestCheckFunc( @@ -107,3 +114,14 @@ data "archive_file" "foo" { output_path = "zip_file_acc_test.zip" } ` + +var testAccArchiveFileMultiConfig = ` +data "archive_file" "foo" { + type = "zip" + source { + filename = "content.txt" + content = "This is some content" + } + output_path = "zip_file_acc_test.zip" +} +` diff --git a/builtin/providers/archive/zip_archiver.go b/builtin/providers/archive/zip_archiver.go index 499c17e56..0bbdd8825 100644 --- a/builtin/providers/archive/zip_archiver.go +++ b/builtin/providers/archive/zip_archiver.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sort" ) type ZipArchiver struct { @@ -85,6 +86,34 @@ func (a *ZipArchiver) ArchiveDir(indirname string) error { } +func (a *ZipArchiver) ArchiveMultiple(content map[string][]byte) error { + if err := a.open(); err != nil { + return err + } + defer a.close() + + // Ensure files are processed in the same order so hashes don't change + keys := make([]string, len(content)) + i := 0 + for k := range content { + keys[i] = k + i++ + } + sort.Strings(keys) + + for _, filename := range keys { + f, err := a.writer.Create(filename) + if err != nil { + return err + } + _, err = f.Write(content[filename]) + if err != nil { + return err + } + } + return nil +} + func (a *ZipArchiver) open() error { f, err := os.Create(a.filepath) if err != nil { diff --git a/builtin/providers/archive/zip_archiver_test.go b/builtin/providers/archive/zip_archiver_test.go index 5eb7a8a15..34a272724 100644 --- a/builtin/providers/archive/zip_archiver_test.go +++ b/builtin/providers/archive/zip_archiver_test.go @@ -44,6 +44,23 @@ func TestZipArchiver_Dir(t *testing.T) { }) } +func TestZipArchiver_Multiple(t *testing.T) { + zipfilepath := "archive-content.zip" + content := map[string][]byte{ + "file1.txt": []byte("This is file 1"), + "file2.txt": []byte("This is file 2"), + "file3.txt": []byte("This is file 3"), + } + + archiver := NewZipArchiver(zipfilepath) + if err := archiver.ArchiveMultiple(content); err != nil { + t.Fatalf("unexpected error: %s", err) + } + + ensureContents(t, zipfilepath, content) + +} + func ensureContents(t *testing.T, zipfilepath string, wants map[string][]byte) { r, err := zip.OpenReader(zipfilepath) if err != nil {