diff --git a/go.mod b/go.mod index 4754181..ee48f6d 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,15 @@ require ( github.com/google/uuid v1.1.1 github.com/kardianos/service v0.0.0-20180823001510-8f267d80f2eb github.com/mh-cbon/stringexec v0.0.0-20160727103857-bc348d279f97 + github.com/stretchr/testify v1.7.0 github.com/urfave/cli v1.20.0 golang.org/x/sys v0.0.0-20161108151328-9a2e24c3733e golang.org/x/text v0.3.1-0.20180810153555-6e3c4e7365dd ) -require github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect +require ( + github.com/davecgh/go-spew v1.1.0 // indirect + github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect +) diff --git a/go.sum b/go.sum index 3fac115..83ef80e 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITg github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/bmatcuk/doublestar v1.1.5 h1:2bNwBOmhyFEFcoB3tGvTD5xanq+4kyOZlB8wFYbMjkk= github.com/bmatcuk/doublestar v1.1.5/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1 h1:PJPDf8OUfOK1bb/NeTKd4f1QXZItOX389VN3B6qC8ro= @@ -10,9 +12,18 @@ github.com/kardianos/service v0.0.0-20180823001510-8f267d80f2eb h1:2lmKB0a4p/+Pn github.com/kardianos/service v0.0.0-20180823001510-8f267d80f2eb/go.mod h1:10UU/bEkzh2iEN6aYzbevY7J6p03KO5siTxQWXMEerg= github.com/mh-cbon/stringexec v0.0.0-20160727103857-bc348d279f97 h1:mGgcjK6Gl7q7LrdJPdD9hpzGLzlOhaZHus/sfR2xCbg= github.com/mh-cbon/stringexec v0.0.0-20160727103857-bc348d279f97/go.mod h1:SI078kddNqdZJQDEdmObdv8P9mpOlA7zkH2KWmBnsOs= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= golang.org/x/sys v0.0.0-20161108151328-9a2e24c3733e h1:noFVAnJ3Wx72//8KbQX5NXL+mYoL7MPza20zUFW2nMQ= golang.org/x/sys v0.0.0-20161108151328-9a2e24c3733e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.1-0.20180810153555-6e3c4e7365dd h1:lo2UnwK3h6RzZubcJ+kvjMy3neKtAKQ7TnVRxhiEceU= golang.org/x/text v0.3.1-0.20180810153555-6e3c4e7365dd/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/manifest/index.go b/manifest/index.go index c43fa57..7c917a4 100644 --- a/manifest/index.go +++ b/manifest/index.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "os" + "path" "path/filepath" "strconv" "strings" @@ -251,17 +252,101 @@ func (wixFile *WixManifest) Load(p string) error { if p == "" { p = "wix.json" } + if _, err := os.Stat(p); os.IsNotExist(err) { return err } + dat, err := ioutil.ReadFile(p) if err != nil { return fmt.Errorf("JSON ReadFile failed with %v", err) } + err = json.Unmarshal(dat, &wixFile) if err != nil { return fmt.Errorf("JSON Unmarshal failed with %v", err) } + + // dynamically build wixFile.Directories + return wixFile.buildDirectoriesRecursive() +} + +// buildDirectoriesRecursive detects all files and directories nested under a top level +// directory. The wix.JSON should look similar to: +// "directories": [ +// { +// "name": "config" +// }, +// { +// "name": "launcher" +// } +// ], +func (wixFile *WixManifest) buildDirectoriesRecursive() error { + for key, _ := range wixFile.Directories { + err := buildDirectories(".", &wixFile.Directories[key]) + if err != nil { + return err + } + } + + // Write the dynamic config to disk so we can inspect it manually + // while debugging builds. + b, err := json.MarshalIndent(wixFile, "", " ") + if err != nil { + return fmt.Errorf("DEBUG: failed to marshal fix config: %v", err) + } + f, err := os.Create("wix.dynamic.json") + if err != nil { + return err + } + if _, err := f.Write(b); err != nil { + return fmt.Errorf("failed to write dynamic wix config to disk: %v", err) + } + return f.Close() +} + +// buildDirectories detects all sub files and directories for the given +// *Directory. Useful for performing auto detection when there are too +// many files and directories to specify in the wix.json. +func buildDirectories(parentPath string, dir *Directory) error { + // Get a list of all files and directories + p := path.Join(parentPath, dir.Name) + list, err := ioutil.ReadDir(p) + if err != nil { + return fmt.Errorf("failed to read path: %s", p) + } + + // Iterate over the list: + // Append all files to the directories []Files list + // When a directory is detected, call this function again + // and grap it's sub directories and files before appending + // to the parent directory. + for _, sub := range list { + // purposely shadowing + parentPath := path.Join(parentPath, dir.Name) + + if !sub.IsDir() { + subFile := File{ + Path: path.Join(parentPath, sub.Name()), + } + dir.Files = append(dir.Files, subFile) + continue + } + + subDir := Directory{ + Name: sub.Name(), + } + + err := buildDirectories(parentPath, &subDir) + if err != nil { + return err + } + + // When finished building the directory tree, append the directory + // to the parent directory. + dir.Directories = append(dir.Directories, subDir) + } + return nil } diff --git a/manifest/index_test.go b/manifest/index_test.go new file mode 100644 index 0000000..752db67 --- /dev/null +++ b/manifest/index_test.go @@ -0,0 +1,123 @@ +package manifest + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestBuilDirectories(t *testing.T) { + wixFile := &WixManifest{} + wixFile.Directories = []Directory{ + { + Name: "testdata", + }, + { + Name: "testdata2", + }, + } + + err := wixFile.buildDirectoriesRecursive() + require.NoError(t, err) + require.Equal(t, "testdata", wixFile.Directories[0].Name) + + expect := &WixManifest{} + expect.Directories = []Directory{ + { + Name: "testdata", + Directories: []Directory{ + { + Name: "path_a", + Files: []File{ + { + Path: "testdata/path_a/a", + }, + { + Path: "testdata/path_a/a2", + }, + }, + }, + { + Name: "path_b", + Files: []File{ + { + Path: "testdata/path_b/b", + }, + }, + }, + { + Name: "path_c", + Directories: []Directory{ + { + Name: "path_c_sub", + Files: []File{ + { + Path: "testdata/path_c/path_c_sub/csub", + }, + }, + }, + }, + }, + }, + Files: []File{ + { + Path: "testdata/testdata", + }, + }, + }, + { + Name: "testdata2", + Directories: []Directory{ + { + Name: "path_a", + Files: []File{ + { + Path: "testdata2/path_a/a", + }, + { + Path: "testdata2/path_a/a2", + }, + }, + }, + { + Name: "path_b", + Files: []File{ + { + Path: "testdata2/path_b/b", + }, + }, + }, + { + Name: "path_c", + Directories: []Directory{ + { + Name: "path_c_sub", + Files: []File{ + { + Path: "testdata2/path_c/path_c_sub/csub", + }, + }, + }, + }, + }, + }, + Files: []File{ + { + Path: "testdata2/testdata", + }, + }, + }, + } + + require.Equal(t, expect, wixFile) + +} + +func TestEmptyDir(t *testing.T) { + wixFile := &WixManifest{} + d := Directory{Name: "fakedir"} + wixFile.Directories = append(wixFile.Directories, d) + + err := wixFile.buildDirectoriesRecursive() + require.Error(t, err) +} diff --git a/manifest/testdata/path_a/a b/manifest/testdata/path_a/a new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata/path_a/a2 b/manifest/testdata/path_a/a2 new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata/path_b/b b/manifest/testdata/path_b/b new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata/path_c/path_c_sub/csub b/manifest/testdata/path_c/path_c_sub/csub new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata/testdata b/manifest/testdata/testdata new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata2/path_a/a b/manifest/testdata2/path_a/a new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata2/path_a/a2 b/manifest/testdata2/path_a/a2 new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata2/path_b/b b/manifest/testdata2/path_b/b new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata2/path_c/path_c_sub/csub b/manifest/testdata2/path_c/path_c_sub/csub new file mode 100644 index 0000000..e69de29 diff --git a/manifest/testdata2/testdata b/manifest/testdata2/testdata new file mode 100644 index 0000000..e69de29 diff --git a/manifest/wix.dynamic.json b/manifest/wix.dynamic.json new file mode 100644 index 0000000..3de9d39 --- /dev/null +++ b/manifest/wix.dynamic.json @@ -0,0 +1,92 @@ +{ + "product": "", + "company": "", + "upgrade-code": "", + "directories": [ + { + "name": "testdata", + "files": [ + { + "path": "testdata/testdata" + } + ], + "directories": [ + { + "name": "path_a", + "files": [ + { + "path": "testdata/path_a/a" + }, + { + "path": "testdata/path_a/a2" + } + ] + }, + { + "name": "path_b", + "files": [ + { + "path": "testdata/path_b/b" + } + ] + }, + { + "name": "path_c", + "directories": [ + { + "name": "path_c_sub", + "files": [ + { + "path": "testdata/path_c/path_c_sub/csub" + } + ] + } + ] + } + ] + }, + { + "name": "testdata2", + "files": [ + { + "path": "testdata2/testdata" + } + ], + "directories": [ + { + "name": "path_a", + "files": [ + { + "path": "testdata2/path_a/a" + }, + { + "path": "testdata2/path_a/a2" + } + ] + }, + { + "name": "path_b", + "files": [ + { + "path": "testdata2/path_b/b" + } + ] + }, + { + "name": "path_c", + "directories": [ + { + "name": "path_c_sub", + "files": [ + { + "path": "testdata2/path_c/path_c_sub/csub" + } + ] + } + ] + } + ] + } + ], + "choco": {} +} \ No newline at end of file