From 3a21ef192628f6952eaa981bcdf718a35a4b43c7 Mon Sep 17 00:00:00 2001 From: Christine Dodrill Date: Wed, 13 Dec 2017 10:43:58 -0800 Subject: convert to go buildpack --- vendor/github.com/GeertJohan/go.rice/.gitignore | 8 + vendor/github.com/GeertJohan/go.rice/.travis.yml | 19 + vendor/github.com/GeertJohan/go.rice/AUTHORS | 4 + vendor/github.com/GeertJohan/go.rice/LICENSE | 22 + vendor/github.com/GeertJohan/go.rice/README.md | 151 +++++ .../github.com/GeertJohan/go.rice/config_test.go | 136 +++++ .../go.rice/example/example-files/file.txt | 2 + .../go.rice/example/example-files/img/doge.jpg | Bin 0 -> 53549 bytes .../go.rice/example/example-templates/message.tmpl | 1 + .../GeertJohan/go.rice/example/example.go | 69 +++ .../github.com/GeertJohan/go.rice/rice/append.go | 157 +++++ vendor/github.com/GeertJohan/go.rice/rice/clean.go | 33 + .../github.com/GeertJohan/go.rice/rice/embed-go.go | 161 +++++ .../GeertJohan/go.rice/rice/embed-go_test.go | 680 +++++++++++++++++++++ .../GeertJohan/go.rice/rice/embed-syso.go | 204 +++++++ vendor/github.com/GeertJohan/go.rice/rice/find.go | 150 +++++ .../GeertJohan/go.rice/rice/find_test.go | 302 +++++++++ vendor/github.com/GeertJohan/go.rice/rice/flags.go | 80 +++ .../GeertJohan/go.rice/rice/identifier.go | 14 + vendor/github.com/GeertJohan/go.rice/rice/main.go | 68 +++ .../GeertJohan/go.rice/rice/templates.go | 98 +++ vendor/github.com/GeertJohan/go.rice/rice/util.go | 22 + .../GeertJohan/go.rice/rice/writecoff.go | 42 ++ 23 files changed, 2423 insertions(+) create mode 100644 vendor/github.com/GeertJohan/go.rice/.gitignore create mode 100644 vendor/github.com/GeertJohan/go.rice/.travis.yml create mode 100644 vendor/github.com/GeertJohan/go.rice/AUTHORS create mode 100644 vendor/github.com/GeertJohan/go.rice/LICENSE create mode 100644 vendor/github.com/GeertJohan/go.rice/README.md create mode 100644 vendor/github.com/GeertJohan/go.rice/config_test.go create mode 100644 vendor/github.com/GeertJohan/go.rice/example/example-files/file.txt create mode 100644 vendor/github.com/GeertJohan/go.rice/example/example-files/img/doge.jpg create mode 100644 vendor/github.com/GeertJohan/go.rice/example/example-templates/message.tmpl create mode 100644 vendor/github.com/GeertJohan/go.rice/example/example.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/append.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/clean.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/embed-go.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/embed-go_test.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/find.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/find_test.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/flags.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/identifier.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/main.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/templates.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/util.go create mode 100644 vendor/github.com/GeertJohan/go.rice/rice/writecoff.go (limited to 'vendor/github.com/GeertJohan') diff --git a/vendor/github.com/GeertJohan/go.rice/.gitignore b/vendor/github.com/GeertJohan/go.rice/.gitignore new file mode 100644 index 0000000..a3c9819 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/.gitignore @@ -0,0 +1,8 @@ +/example/example +/example/example.exe +/rice/rice +/rice/rice.exe + +*.rice-box.go +*.rice-box.syso +.wercker diff --git a/vendor/github.com/GeertJohan/go.rice/.travis.yml b/vendor/github.com/GeertJohan/go.rice/.travis.yml new file mode 100644 index 0000000..b4840a1 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/.travis.yml @@ -0,0 +1,19 @@ +language: go + +go: + - master + - 1.x.x + - 1.8.x + - 1.7.x + - 1.6.x + - 1.5.x + +install: + - go get -t ./... + - env + - if [ "${TRAVIS_GO_VERSION%.*}" != "1.5" ]; then go get github.com/golang/lint/golint; fi +script: + - go build -x ./... + - go test -cover ./... + - go vet ./... + - if [ "${TRAVIS_GO_VERSION%.*}" != "1.5" ]; then golint .; fi diff --git a/vendor/github.com/GeertJohan/go.rice/AUTHORS b/vendor/github.com/GeertJohan/go.rice/AUTHORS new file mode 100644 index 0000000..20ff8ba --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/AUTHORS @@ -0,0 +1,4 @@ +Geert-Johan Riemer +Paul Maddox +Vincent Petithory + diff --git a/vendor/github.com/GeertJohan/go.rice/LICENSE b/vendor/github.com/GeertJohan/go.rice/LICENSE new file mode 100644 index 0000000..8b4409d --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013, Geert-Johan Riemer +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/GeertJohan/go.rice/README.md b/vendor/github.com/GeertJohan/go.rice/README.md new file mode 100644 index 0000000..836e671 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/README.md @@ -0,0 +1,151 @@ +## go.rice + +[![Build Status](https://travis-ci.org/GeertJohan/go.rice.png)](https://travis-ci.org/GeertJohan/go.rice) +[![Godoc](https://img.shields.io/badge/godoc-go.rice-blue.svg?style=flat-square)](https://godoc.org/github.com/GeertJohan/go.rice) + +go.rice is a [Go](http://golang.org) package that makes working with resources such as html,js,css,images and templates very easy. During development `go.rice` will load required files directly from disk. Upon deployment it is easy to add all resource files to a executable using the `rice` tool, without changing the source code for your package. go.rice provides several methods to add resources to a binary. + +### What does it do? +The first thing go.rice does is finding the correct absolute path for your resource files. Say you are executing go binary in your home directory, but your `html-files` are located in `$GOPATH/src/yourApplication/html-files`. `go.rice` will lookup the correct path for that directory (relative to the location of yourApplication). The only thing you have to do is include the resources using `rice.FindBox("html-files")`. + +This only works when the source is available to the machine executing the binary. Which is always the case when the binary was installed with `go get` or `go install`. It might occur that you wish to simply provide a binary, without source. The `rice` tool analyses source code and finds call's to `rice.FindBox(..)` and adds the required directories to the executable binary. There are several methods to add these resources. You can 'embed' by generating go source code, or append the resource to the executable as zip file. In both cases `go.rice` will detect the embedded or appended resources and load those, instead of looking up files from disk. + +### Installation + +Use `go get` to install the package the `rice` tool. +``` +go get github.com/GeertJohan/go.rice +go get github.com/GeertJohan/go.rice/rice +``` + +### Package usage + +Import the package: `import "github.com/GeertJohan/go.rice"` + +**Serving a static content folder over HTTP with a rice Box** +```go +http.Handle("/", http.FileServer(rice.MustFindBox("http-files").HTTPBox())) +http.ListenAndServe(":8080", nil) +``` + +**Service a static content folder over HTTP at a non-root location** +```go +box := rice.MustFindBox("cssfiles") +cssFileServer := http.StripPrefix("/css/", http.FileServer(box.HTTPBox())) +http.Handle("/css/", cssFileServer) +http.ListenAndServe(":8080", nil) +``` + +Note the *trailing slash* in `/css/` in both the call to +`http.StripPrefix` and `http.Handle`. + +**Loading a template** +```go +// find a rice.Box +templateBox, err := rice.FindBox("example-templates") +if err != nil { + log.Fatal(err) +} +// get file contents as string +templateString, err := templateBox.String("message.tmpl") +if err != nil { + log.Fatal(err) +} +// parse and execute the template +tmplMessage, err := template.New("message").Parse(templateString) +if err != nil { + log.Fatal(err) +} +tmplMessage.Execute(os.Stdout, map[string]string{"Message": "Hello, world!"}) + +``` + +Never call `FindBox()` or `MustFindBox()` from an `init()` function, as the boxes might have not been loaded at that time. + +### Tool usage +The `rice` tool lets you add the resources to a binary executable so the files are not loaded from the filesystem anymore. This creates a 'standalone' executable. There are several ways to add the resources to a binary, each has pro's and con's but all will work without requiring changes to the way you load the resources. + +#### embed-go +**Embed resources by generating Go source code** + +This method must be executed before building. It generates a single Go source file called *rice-box.go* for each package, that is compiled by the go compiler into the binary. + +The downside with this option is that the generated go source files can become very large, which will slow down compilation and require lots of memory to compile. + +Execute the following commands: +``` +rice embed-go +go build +``` + +*A Note on Symbolic Links*: `embed-go` uses the `os.Walk` function +from the standard library. The `os.Walk` function does **not** follow +symbolic links. So, when creating a box, be aware that any symbolic +links inside your box's directory will not be followed. **However**, +if the box itself is a symbolic link, its actual location will be +resolved first and then walked. In summary, if your box location is a +symbolic link, it will be followed but none of the symbolic links in +the box will be followed. + +#### embed-syso +**Embed resources by generating a coff .syso file and some .go source code** + +** This method is experimental and should not be used for production systems just yet ** + +This method must be executed before building. It generates a COFF .syso file and Go source file that are compiled by the go compiler into the binary. + +Execute the following commands: +``` +rice embed-syso +go build +``` + +#### append +**Append resources to executable as zip file** + +This method changes an already built executable. It appends the resources as zip file to the binary. It makes compilation a lot faster and can be used with large resource files. + +Downsides for appending are that it requires `zip` to be installed and does not provide a working Seek method. + +Run the following commands to create a standalone executable. +``` +go build -o example +rice append --exec example +``` + +**Note: requires zip command to be installed** + +On windows, install zip from http://gnuwin32.sourceforge.net/packages/zip.htm or cygwin/msys toolsets. + +#### Help information +Run `rice -h` for information about all options. + +You can run the -h option for each sub-command, e.g. `rice append -h`. + +### Order of precedence +When opening a new box, the rice package tries to locate the resources in the following order: + + - embedded in generated go source + - appended as zip + - 'live' from filesystem + + +### License +This project is licensed under a Simplified BSD license. Please read the [LICENSE file][license]. + +### TODO & Development +This package is not completed yet. Though it already provides working embedding, some important featuers are still missing. + - implement Readdir() correctly on virtualDir + - in-code TODO's + - find boxes in imported packages + +Less important stuff: + - idea, os/arch dependent embeds. rice checks if embedding file has _os_arch or build flags. If box is not requested by file without buildflags, then the buildflags are applied to the embed file. + +### Package documentation + +You will find package documentation at [godoc.org/github.com/GeertJohan/go.rice][godoc]. + + + [license]: https://github.com/GeertJohan/go.rice/blob/master/LICENSE + [godoc]: http://godoc.org/github.com/GeertJohan/go.rice diff --git a/vendor/github.com/GeertJohan/go.rice/config_test.go b/vendor/github.com/GeertJohan/go.rice/config_test.go new file mode 100644 index 0000000..b54296b --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/config_test.go @@ -0,0 +1,136 @@ +package rice + +import ( + "fmt" + "io/ioutil" + "testing" + + "github.com/GeertJohan/go.rice/embedded" +) + +// For all test code in this package, define a set of test boxes. +var eb1 *embedded.EmbeddedBox +var ab1, ab2 *appendedBox +var fsb1, fsb2, fsb3 string // paths to filesystem boxes +func init() { + var err error + + // Box1 exists in all three locations. + eb1 = &embedded.EmbeddedBox{Name: "box1"} + embedded.RegisterEmbeddedBox(eb1.Name, eb1) + ab1 = &appendedBox{Name: "box1"} + appendedBoxes["box1"] = ab1 + fsb1, err = ioutil.TempDir("", "box1") + if err != nil { + panic(err) + } + + // Box2 exists in only appended and FS. + ab2 = &appendedBox{Name: "box2"} + appendedBoxes["box2"] = ab2 + fsb2, err = ioutil.TempDir("", "box2") + if err != nil { + panic(err) + } + + // Box3 exists only on disk. + fsb3, err = ioutil.TempDir("", "box3") + if err != nil { + panic(err) + } + + // Also, replace the default filesystem lookup path to directly support the + // on-disk temp directories. + resolveAbsolutePathFromCaller = func(name string, n int) (string, error) { + if name == "box1" { + return fsb1, nil + } else if name == "box2" { + return fsb2, nil + } else if name == "box3" { + return fsb3, nil + } + return "", fmt.Errorf("Unknown box name: %q", name) + } +} + +func TestDefaultLookupOrder(t *testing.T) { + // Box1 exists in all three, so the default order should find the embedded. + b, err := FindBox("box1") + if err != nil { + t.Fatalf("Expected to find box1, got error: %v", err) + } + if b.embed != eb1 { + t.Fatalf("Expected to find embedded box, but got %#v", b) + } + + // Box2 exists in appended and FS, so find the appended. + b2, err := FindBox("box2") + if err != nil { + t.Fatalf("Expected to find box2, got error: %v", err) + } + if b2.appendd != ab2 { + t.Fatalf("Expected to find appended box, but got %#v", b2) + } + + // Box3 exists only on FS, so find it there. + b3, err := FindBox("box3") + if err != nil { + t.Fatalf("Expected to find box3, got error: %v", err) + } + if b3.absolutePath != fsb3 { + t.Fatalf("Expected to find FS box, but got %#v", b3) + } +} + +func TestConfigLocateOrder(t *testing.T) { + cfg := Config{LocateOrder: []LocateMethod{LocateFS, LocateAppended, LocateEmbedded}} + fsb := []string{fsb1, fsb2, fsb3} + // All 3 boxes have a FS backend, so we should always find that. + for i, boxName := range []string{"box1", "box2", "box3"} { + b, err := cfg.FindBox(boxName) + if err != nil { + t.Fatalf("Expected to find %q, got error: %v", boxName, err) + } + if b.absolutePath != fsb[i] { + t.Fatalf("Expected to find FS box, but got %#v", b) + } + } + + cfg.LocateOrder = []LocateMethod{LocateAppended, LocateFS, LocateEmbedded} + { + b, err := cfg.FindBox("box3") + if err != nil { + t.Fatalf("Expected to find box3, got error: %v", err) + } + if b.absolutePath != fsb3 { + t.Fatalf("Expected to find FS box, but got %#v", b) + } + } + { + b, err := cfg.FindBox("box2") + if err != nil { + t.Fatalf("Expected to find box2, got error: %v", err) + } + if b.appendd != ab2 { + t.Fatalf("Expected to find appended box, but got %#v", b) + } + } + + // What if we don't list all the locate methods? + cfg.LocateOrder = []LocateMethod{LocateEmbedded} + { + b, err := cfg.FindBox("box2") + if err == nil { + t.Fatalf("Expected not to find box2, but something was found: %#v", b) + } + } + { + b, err := cfg.FindBox("box1") + if err != nil { + t.Fatalf("Expected to find box2, got error: %v", err) + } + if b.embed != eb1 { + t.Fatalf("Expected to find embedded box, but got %#v", b) + } + } +} diff --git a/vendor/github.com/GeertJohan/go.rice/example/example-files/file.txt b/vendor/github.com/GeertJohan/go.rice/example/example-files/file.txt new file mode 100644 index 0000000..3154578 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/example/example-files/file.txt @@ -0,0 +1,2 @@ +test content +break \ No newline at end of file diff --git a/vendor/github.com/GeertJohan/go.rice/example/example-files/img/doge.jpg b/vendor/github.com/GeertJohan/go.rice/example/example-files/img/doge.jpg new file mode 100644 index 0000000..6660dc9 Binary files /dev/null and b/vendor/github.com/GeertJohan/go.rice/example/example-files/img/doge.jpg differ diff --git a/vendor/github.com/GeertJohan/go.rice/example/example-templates/message.tmpl b/vendor/github.com/GeertJohan/go.rice/example/example-templates/message.tmpl new file mode 100644 index 0000000..4b7638d --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/example/example-templates/message.tmpl @@ -0,0 +1 @@ +I have a message for you: {{.Message}} diff --git a/vendor/github.com/GeertJohan/go.rice/example/example.go b/vendor/github.com/GeertJohan/go.rice/example/example.go new file mode 100644 index 0000000..68f189f --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/example/example.go @@ -0,0 +1,69 @@ +package main + +import ( + "encoding/hex" + "fmt" + "log" + "net/http" + "os" + "text/template" + + "github.com/GeertJohan/go.rice" + "github.com/davecgh/go-spew/spew" +) + +func main() { + conf := rice.Config{ + LocateOrder: []rice.LocateMethod{rice.LocateEmbedded, rice.LocateAppended, rice.LocateFS}, + } + box, err := conf.FindBox("example-files") + if err != nil { + log.Fatalf("error opening rice.Box: %s\n", err) + } + // spew.Dump(box) + + contentString, err := box.String("file.txt") + if err != nil { + log.Fatalf("could not read file contents as string: %s\n", err) + } + log.Printf("Read some file contents as string:\n%s\n", contentString) + + contentBytes, err := box.Bytes("file.txt") + if err != nil { + log.Fatalf("could not read file contents as byteSlice: %s\n", err) + } + log.Printf("Read some file contents as byteSlice:\n%s\n", hex.Dump(contentBytes)) + + file, err := box.Open("file.txt") + if err != nil { + log.Fatalf("could not open file: %s\n", err) + } + spew.Dump(file) + + // find/create a rice.Box + templateBox, err := rice.FindBox("example-templates") + if err != nil { + log.Fatal(err) + } + // get file contents as string + templateString, err := templateBox.String("message.tmpl") + if err != nil { + log.Fatal(err) + } + // parse and execute the template + tmplMessage, err := template.New("message").Parse(templateString) + if err != nil { + log.Fatal(err) + } + tmplMessage.Execute(os.Stdout, map[string]string{"Message": "Hello, world!"}) + + http.Handle("/", http.FileServer(box.HTTPBox())) + go func() { + fmt.Println("Serving files on :8080, press ctrl-C to exit") + err := http.ListenAndServe(":8080", nil) + if err != nil { + log.Fatalf("error serving files: %v", err) + } + }() + select {} +} diff --git a/vendor/github.com/GeertJohan/go.rice/rice/append.go b/vendor/github.com/GeertJohan/go.rice/rice/append.go new file mode 100644 index 0000000..8ab0130 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/rice/append.go @@ -0,0 +1,157 @@ +package main + +import ( + "archive/zip" + "fmt" + "go/build" + "io" + "os" + "path/filepath" + "strings" + "time" + + zipexe "github.com/daaku/go.zipexe" +) + +func operationAppend(pkgs []*build.Package) { + // create tmp zipfile + tmpZipfileName := filepath.Join(os.TempDir(), fmt.Sprintf("ricebox-%d-%s.zip", time.Now().Unix(), randomString(10))) + verbosef("Will create tmp zipfile: %s\n", tmpZipfileName) + tmpZipfile, err := os.Create(tmpZipfileName) + if err != nil { + fmt.Printf("Error creating tmp zipfile: %s\n", err) + os.Exit(1) + } + defer func() { + tmpZipfile.Close() + os.Remove(tmpZipfileName) + }() + + // find abs path for binary file + binfileName, err := filepath.Abs(flags.Append.Executable) + if err != nil { + fmt.Printf("Error finding absolute path for executable to append: %s\n", err) + os.Exit(1) + } + verbosef("Will append to file: %s\n", binfileName) + + // check that command doesn't already have zip appended + if rd, _ := zipexe.Open(binfileName); rd != nil { + fmt.Printf("Cannot append to already appended executable. Please remove %s and build a fresh one.\n", binfileName) + os.Exit(1) + } + + // open binfile + binfile, err := os.OpenFile(binfileName, os.O_WRONLY, os.ModeAppend) + if err != nil { + fmt.Printf("Error: unable to open executable file: %s\n", err) + os.Exit(1) + } + defer binfile.Close() + + binfileInfo, err := binfile.Stat() + if err != nil { + fmt.Printf("Error: unable to stat executable file: %s\n", err) + os.Exit(1) + } + + // create zip.Writer + zipWriter := zip.NewWriter(tmpZipfile) + + // write the zip offset into the zip data + zipWriter.SetOffset(binfileInfo.Size()) + + for _, pkg := range pkgs { + // find boxes for this command + boxMap := findBoxes(pkg) + + // notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ? + if len(boxMap) == 0 { + fmt.Printf("no calls to rice.FindBox() or rice.MustFindBox() found in import path `%s`\n", pkg.ImportPath) + continue + } + + verbosef("\n") + + for boxname := range boxMap { + appendedBoxName := strings.Replace(boxname, `/`, `-`, -1) + + // walk box path's and insert files + boxPath := filepath.Clean(filepath.Join(pkg.Dir, boxname)) + filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error { + if info == nil { + fmt.Printf("Error: box \"%s\" not found on disk\n", path) + os.Exit(1) + } + // create zipFilename + zipFileName := filepath.Join(appendedBoxName, strings.TrimPrefix(path, boxPath)) + // write directories as empty file with comment "dir" + if info.IsDir() { + _, err := zipWriter.CreateHeader(&zip.FileHeader{ + Name: zipFileName, + Comment: "dir", + }) + if err != nil { + fmt.Printf("Error creating dir in tmp zip: %s\n", err) + os.Exit(1) + } + return nil + } + + // create zipFileWriter + zipFileHeader, err := zip.FileInfoHeader(info) + if err != nil { + fmt.Printf("Error creating zip FileHeader: %v\n", err) + os.Exit(1) + } + zipFileHeader.Name = zipFileName + zipFileWriter, err := zipWriter.CreateHeader(zipFileHeader) + if err != nil { + fmt.Printf("Error creating file in tmp zip: %s\n", err) + os.Exit(1) + } + srcFile, err := os.Open(path) + if err != nil { + fmt.Printf("Error opening file to append: %s\n", err) + os.Exit(1) + } + _, err = io.Copy(zipFileWriter, srcFile) + if err != nil { + fmt.Printf("Error copying file contents to zip: %s\n", err) + os.Exit(1) + } + srcFile.Close() + + return nil + }) + } + } + + err = zipWriter.Close() + if err != nil { + fmt.Printf("Error closing tmp zipfile: %s\n", err) + os.Exit(1) + } + + err = tmpZipfile.Sync() + if err != nil { + fmt.Printf("Error syncing tmp zipfile: %s\n", err) + os.Exit(1) + } + _, err = tmpZipfile.Seek(0, 0) + if err != nil { + fmt.Printf("Error seeking tmp zipfile: %s\n", err) + os.Exit(1) + } + _, err = binfile.Seek(0, 2) + if err != nil { + fmt.Printf("Error seeking bin file: %s\n", err) + os.Exit(1) + } + + _, err = io.Copy(binfile, tmpZipfile) + if err != nil { + fmt.Printf("Error appending zipfile to executable: %s\n", err) + os.Exit(1) + } +} diff --git a/vendor/github.com/GeertJohan/go.rice/rice/clean.go b/vendor/github.com/GeertJohan/go.rice/rice/clean.go new file mode 100644 index 0000000..6155c06 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/rice/clean.go @@ -0,0 +1,33 @@ +package main + +import ( + "fmt" + "go/build" + "os" + "path/filepath" + "strings" +) + +func operationClean(pkg *build.Package) { + filepath.Walk(pkg.Dir, func(filename string, info os.FileInfo, err error) error { + if err != nil { + fmt.Printf("error walking pkg dir to clean files: %v\n", err) + os.Exit(1) + } + if info.IsDir() { + return nil + } + verbosef("checking file '%s'\n", filename) + if filepath.Base(filename) == "rice-box.go" || + strings.HasSuffix(filename, ".rice-box.go") || + strings.HasSuffix(filename, ".rice-box.syso") { + err := os.Remove(filename) + if err != nil { + fmt.Printf("error removing file (%s): %s\n", filename, err) + os.Exit(-1) + } + verbosef("removed file '%s'\n", filename) + } + return nil + }) +} diff --git a/vendor/github.com/GeertJohan/go.rice/rice/embed-go.go b/vendor/github.com/GeertJohan/go.rice/rice/embed-go.go new file mode 100644 index 0000000..3706cca --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/rice/embed-go.go @@ -0,0 +1,161 @@ +package main + +import ( + "bytes" + "fmt" + "go/build" + "go/format" + "io" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" +) + +const boxFilename = "rice-box.go" + +func writeBoxesGo(pkg *build.Package, out io.Writer) error { + boxMap := findBoxes(pkg) + + // notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ? + if len(boxMap) == 0 { + fmt.Println("no calls to rice.FindBox() found") + return nil + } + + verbosef("\n") + + var boxes []*boxDataType + + for boxname := range boxMap { + // find path and filename for this box + boxPath := filepath.Join(pkg.Dir, boxname) + + // Check to see if the path for the box is a symbolic link. If so, simply + // box what the symbolic link points to. Note: the filepath.Walk function + // will NOT follow any nested symbolic links. This only handles the case + // where the root of the box is a symbolic link. + symPath, serr := os.Readlink(boxPath) + if serr == nil { + boxPath = symPath + } + + // verbose info + verbosef("embedding box '%s' to '%s'\n", boxname, boxFilename) + + // read box metadata + boxInfo, ierr := os.Stat(boxPath) + if ierr != nil { + return fmt.Errorf("Error: unable to access box at %s\n", boxPath) + } + + // create box datastructure (used by template) + box := &boxDataType{ + BoxName: boxname, + UnixNow: boxInfo.ModTime().Unix(), + Files: make([]*fileDataType, 0), + Dirs: make(map[string]*dirDataType), + } + + if !boxInfo.IsDir() { + return fmt.Errorf("Error: Box %s must point to a directory but points to %s instead\n", + boxname, boxPath) + } + + // fill box datastructure with file data + err := filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + return fmt.Errorf("error walking box: %s\n", err) + } + + filename := strings.TrimPrefix(path, boxPath) + filename = strings.Replace(filename, "\\", "/", -1) + filename = strings.TrimPrefix(filename, "/") + if info.IsDir() { + dirData := &dirDataType{ + Identifier: "dir" + nextIdentifier(), + FileName: filename, + ModTime: info.ModTime().Unix(), + ChildFiles: make([]*fileDataType, 0), + ChildDirs: make([]*dirDataType, 0), + } + verbosef("\tincludes dir: '%s'\n", dirData.FileName) + box.Dirs[dirData.FileName] = dirData + + // add tree entry (skip for root, it'll create a recursion) + if dirData.FileName != "" { + pathParts := strings.Split(dirData.FileName, "/") + parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")] + parentDir.ChildDirs = append(parentDir.ChildDirs, dirData) + } + } else { + fileData := &fileDataType{ + Identifier: "file" + nextIdentifier(), + FileName: filename, + ModTime: info.ModTime().Unix(), + } + verbosef("\tincludes file: '%s'\n", fileData.FileName) + fileData.Content, err = ioutil.ReadFile(path) + if err != nil { + return fmt.Errorf("error reading file content while walking box: %s\n", err) + } + box.Files = append(box.Files, fileData) + + // add tree entry + pathParts := strings.Split(fileData.FileName, "/") + parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")] + if parentDir == nil { + return fmt.Errorf("Error: parent of %s is not within the box\n", path) + } + parentDir.ChildFiles = append(parentDir.ChildFiles, fileData) + } + return nil + }) + if err != nil { + return err + } + boxes = append(boxes, box) + + } + + embedSourceUnformated := bytes.NewBuffer(make([]byte, 0)) + + // execute template to buffer + err := tmplEmbeddedBox.Execute( + embedSourceUnformated, + embedFileDataType{pkg.Name, boxes}, + ) + if err != nil { + return fmt.Errorf("error writing embedded box to file (template execute): %s\n", err) + } + + // format the source code + embedSource, err := format.Source(embedSourceUnformated.Bytes()) + if err != nil { + return fmt.Errorf("error formatting embedSource: %s\n", err) + } + + // write source to file + _, err = io.Copy(out, bytes.NewBuffer(embedSource)) + if err != nil { + return fmt.Errorf("error writing embedSource to file: %s\n", err) + } + return nil +} + +func operationEmbedGo(pkg *build.Package) { + // create go file for box + boxFile, err := os.Create(filepath.Join(pkg.Dir, boxFilename)) + if err != nil { + log.Printf("error creating embedded box file: %s\n", err) + os.Exit(1) + } + defer boxFile.Close() + + err = writeBoxesGo(pkg, boxFile) + if err != nil { + log.Printf("error creating embedded box file: %s\n", err) + os.Exit(1) + } +} diff --git a/vendor/github.com/GeertJohan/go.rice/rice/embed-go_test.go b/vendor/github.com/GeertJohan/go.rice/rice/embed-go_test.go new file mode 100644 index 0000000..b75f060 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/rice/embed-go_test.go @@ -0,0 +1,680 @@ +package main + +import ( + "bytes" + "fmt" + "go/ast" + "go/parser" + "go/token" + "path" + "path/filepath" + "strconv" + "strings" + "testing" +) + +type registeredDir struct { + Filename string + ModTime int + ChildFiles []*registeredFile + ChildDirs []*registeredDir +} + +type registeredFile struct { + Filename string + ModTime int + Content string +} + +type registeredBox struct { + Name string + Time int + // key is path + Dirs map[string]*registeredDir + // key is path + Files map[string]*registeredFile +} + +// isSimpleSelector returns true if expr is pkgName.ident +func isSimpleSelector(pkgName, ident string, expr ast.Expr) bool { + if sel, ok := expr.(*ast.SelectorExpr); ok { + if pkgIdent, ok := sel.X.(*ast.Ident); ok && pkgIdent.Name == pkgName && sel.Sel != nil && sel.Sel.Name == ident { + return true + } + } + return false +} + +func isIdent(ident string, expr ast.Expr) bool { + if expr, ok := expr.(*ast.Ident); ok && expr.Name == ident { + return true + } + return false +} + +func getIdentName(expr ast.Expr) (string, bool) { + if expr, ok := expr.(*ast.Ident); ok { + return expr.Name, true + } + return "", false +} + +func getKey(expr *ast.KeyValueExpr) string { + if ident, ok := expr.Key.(*ast.Ident); ok { + return ident.Name + } + return "" +} + +// parseModTime parses a time.Unix call, and returns the unix time. +func parseModTime(expr ast.Expr) (int, error) { + if expr, ok := expr.(*ast.CallExpr); ok { + if !isSimpleSelector("time", "Unix", expr.Fun) { + return 0, fmt.Errorf("ModTime is not time.Unix: %#v", expr.Fun) + } + if len(expr.Args) == 0 { + return 0, fmt.Errorf("not enough args to time.Unix") + } + arg0 := expr.Args[0] + if lit, ok := arg0.(*ast.BasicLit); ok && lit.Kind == token.INT { + return strconv.Atoi(lit.Value) + } + } + return 0, fmt.Errorf("not time.Unix: %#v", expr) +} + +func parseString(expr ast.Expr) (string, error) { + if expr, ok := expr.(*ast.CallExpr); ok && isIdent("string", expr.Fun) && len(expr.Args) == 1 { + return parseString(expr.Args[0]) + } + if lit, ok := expr.(*ast.BasicLit); ok && lit.Kind == token.STRING { + return strconv.Unquote(lit.Value) + } + return "", fmt.Errorf("not string: %#v", expr) +} + +// parseDir parses an embedded.EmbeddedDir literal. +// It can be either a variable name or a composite literal. +// Returns nil if the literal is not embedded.EmbeddedDir. +func parseDir(expr ast.Expr, dirs map[string]*registeredDir, files map[string]*registeredFile) (*registeredDir, []error) { + + if varName, ok := getIdentName(expr); ok { + dir, ok := dirs[varName] + if !ok { + return nil, []error{fmt.Errorf("unknown variable %v", varName)} + } + return dir, nil + } + + lit, ok := expr.(*ast.CompositeLit) + if !ok { + return nil, []error{fmt.Errorf("dir is not a composite literal: %#v", expr)} + } + + var errors []error + if !isSimpleSelector("embedded", "EmbeddedDir", lit.Type) { + return nil, nil + } + ret := ®isteredDir{} + for _, el := range lit.Elts { + if el, ok := el.(*ast.KeyValueExpr); ok { + key := getKey(el) + if key == "" { + continue + } + switch key { + case "DirModTime": + var err error + ret.ModTime, err = parseModTime(el.Value) + if err != nil { + errors = append(errors, fmt.Errorf("DirModTime %s", err)) + } + case "Filename": + var err error + ret.Filename, err = parseString(el.Value) + if err != nil { + errors = append(errors, fmt.Errorf("Filename %s", err)) + } + case "ChildDirs": + var errors2 []error + ret.ChildDirs, errors2 = parseDirsSlice(el.Value, dirs, files) + errors = append(errors, errors2...) + case "ChildFiles": + var errors2 []error + ret.ChildFiles, errors2 = parseFilesSlice(el.Value, files) + errors = append(errors, errors2...) + default: + errors = append(errors, fmt.Errorf("Unknown field: %v: %#v", key, el.Value)) + } + } + } + return ret, errors +} + +// parseFile parses an embedded.EmbeddedFile literal. +// It can be either a variable name or a composite literal. +// Returns nil if the literal is not embedded.EmbeddedFile. +func parseFile(expr ast.Expr, files map[string]*registeredFile) (*registeredFile, []error) { + if varName, ok := getIdentName(expr); ok { + file, ok := files[varName] + if !ok { + return nil, []error{fmt.Errorf("unknown variable %v", varName)} + } + return file, nil + } + + lit, ok := expr.(*ast.CompositeLit) + if !ok { + return nil, []error{fmt.Errorf("file is not a composite literal: %#v", expr)} + } + + var errors []error + if !isSimpleSelector("embedded", "EmbeddedFile", lit.Type) { + return nil, nil + } + ret := ®isteredFile{} + for _, el := range lit.Elts { + if el, ok := el.(*ast.KeyValueExpr); ok { + key := getKey(el) + if key == "" { + continue + } + switch key { + case "FileModTime": + var err error + ret.ModTime, err = parseModTime(el.Value) + if err != nil { + errors = append(errors, fmt.Errorf("DirModTime %s", err)) + } + case "Filename": + var err error + ret.Filename, err = parseString(el.Value) + if err != nil { + errors = append(errors, fmt.Errorf("Filename %s", err)) + } + case "Content": + var err error + ret.Content, err = parseString(el.Value) + if err != nil { + errors = append(errors, fmt.Errorf("Content %s", err)) + } + default: + errors = append(errors, fmt.Errorf("Unknown field: %v: %#v", key, el.Value)) + } + } + } + return ret, errors +} + +func parseRegistration(lit *ast.CompositeLit, dirs map[string]*registeredDir, files map[string]*registeredFile) (*registeredBox, []error) { + var errors []error + if !isSimpleSelector("embedded", "EmbeddedBox", lit.Type) { + return nil, nil + } + ret := ®isteredBox{ + Dirs: make(map[string]*registeredDir), + Files: make(map[string]*registeredFile), + } + for _, el := range lit.Elts { + if el, ok := el.(*ast.KeyValueExpr); ok { + key := getKey(el) + if key == "" { + continue + } + switch key { + case "Time": + var err error + ret.Time, err = parseModTime(el.Value) + if err != nil { + errors = append(errors, fmt.Errorf("Time %s", err)) + } + case "Name": + var err error + ret.Name, err = parseString(el.Value) + if err != nil { + errors = append(errors, fmt.Errorf("Name %s", err)) + } + case "Dirs": + var errors2 []error + ret.Dirs, errors2 = parseDirsMap(el.Value, dirs, files) + errors = append(errors, errors2...) + case "Files": + var errors2 []error + ret.Files, errors2 = parseFilesMap(el.Value, files) + errors = append(errors, errors2...) + default: + errors = append(errors, fmt.Errorf("Unknown field: %v: %#v", key, el.Value)) + } + } + } + return ret, errors +} + +func parseDirsSlice(expr ast.Expr, dirs map[string]*registeredDir, files map[string]*registeredFile) (childDirs []*registeredDir, errors []error) { + valid := false + lit, ok := expr.(*ast.CompositeLit) + if ok { + if arrType, ok := lit.Type.(*ast.ArrayType); ok { + if star, ok := arrType.Elt.(*ast.StarExpr); ok { + if isSimpleSelector("embedded", "EmbeddedDir", star.X) { + valid = true + } + } + } + } + + if !valid { + return nil, []error{fmt.Errorf("not a []*embedded.EmbeddedDir: %#v", expr)} + } + for _, el := range lit.Elts { + child, childErrors := parseDir(el, dirs, files) + errors = append(errors, childErrors...) + childDirs = append(childDirs, child) + } + return +} + +func parseFilesSlice(expr ast.Expr, files map[string]*registeredFile) (childFiles []*registeredFile, errors []error) { + valid := false + lit, ok := expr.(*ast.CompositeLit) + if ok { + if arrType, ok := lit.Type.(*ast.ArrayType); ok { + if star, ok := arrType.Elt.(*ast.StarExpr); ok { + if isSimpleSelector("embedded", "EmbeddedFile", star.X) { + valid = true + } + } + } + } + + if !valid { + return nil, []error{fmt.Errorf("not a []*embedded.EmbeddedFile: %#v", expr)} + } + for _, el := range lit.Elts { + child, childErrors := parseFile(el, files) + errors = append(errors, childErrors...) + childFiles = append(childFiles, child) + } + return +} + +func parseDirsMap(expr ast.Expr, dirs map[string]*registeredDir, files map[string]*registeredFile) (childDirs map[string]*registeredDir, errors []error) { + valid := false + lit, ok := expr.(*ast.CompositeLit) + if ok { + if mapType, ok := lit.Type.(*ast.MapType); ok { + if star, ok := mapType.Value.(*ast.StarExpr); ok { + if isSimpleSelector("embedded", "EmbeddedDir", star.X) && isIdent("string", mapType.Key) { + valid = true + } + } + } + } + + if !valid { + return nil, []error{fmt.Errorf("not a map[string]*embedded.EmbeddedDir: %#v", expr)} + } + childDirs = make(map[string]*registeredDir) + for _, el := range lit.Elts { + kv, ok := el.(*ast.KeyValueExpr) + if !ok { + errors = append(errors, fmt.Errorf("not a KeyValueExpr: %#v", el)) + continue + } + key, err := parseString(kv.Key) + if err != nil { + errors = append(errors, fmt.Errorf("key %s", err)) + continue + } + + child, childErrors := parseDir(kv.Value, dirs, files) + errors = append(errors, childErrors...) + childDirs[key] = child + } + return +} + +func parseFilesMap(expr ast.Expr, files map[string]*registeredFile) (childFiles map[string]*registeredFile, errors []error) { + valid := false + lit, ok := expr.(*ast.CompositeLit) + if ok { + if mapType, ok := lit.Type.(*ast.MapType); ok { + if star, ok := mapType.Value.(*ast.StarExpr); ok { + if isSimpleSelector("embedded", "EmbeddedFile", star.X) && isIdent("string", mapType.Key) { + valid = true + } + } + } + } + + if !valid { + return nil, []error{fmt.Errorf("not a map[string]*embedded.EmbeddedFile: %#v", expr)} + } + childFiles = make(map[string]*registeredFile) + for _, el := range lit.Elts { + kv, ok := el.(*ast.KeyValueExpr) + if !ok { + errors = append(errors, fmt.Errorf("not a KeyValueExpr: %#v", el)) + continue + } + key, err := parseString(kv.Key) + if err != nil { + errors = append(errors, fmt.Errorf("key %s", err)) + continue + } + + child, childErrors := parseFile(kv.Value, files) + errors = append(errors, childErrors...) + childFiles[key] = child + } + return +} + +// unpoint returns the expression expr points to +// if expr is a & unary expression. +func unpoint(expr ast.Expr) ast.Expr { + if expr, ok := expr.(*ast.UnaryExpr); ok { + if expr.Op == token.AND { + return expr.X + } + } + return expr +} + +func validateBox(t *testing.T, box *registeredBox, files []sourceFile) { + dirsToBeChecked := make(map[string]struct{}) + filesToBeChecked := make(map[string]string) + for _, file := range files { + if !strings.HasPrefix(file.Name, box.Name) { + continue + } + pathParts := strings.Split(file.Name, "/") + dirs := pathParts[:len(pathParts)-1] + dirPath := "" + for _, dir := range dirs { + if dir != box.Name { + dirPath = path.Join(dirPath, dir) + } + dirsToBeChecked[dirPath] = struct{}{} + } + filesToBeChecked[path.Join(dirPath, pathParts[len(pathParts)-1])] = string(file.Contents) + } + + if len(box.Files) != len(filesToBeChecked) { + t.Errorf("box %v has incorrect number of files; expected %v, got %v", box.Name, len(filesToBeChecked), len(box.Files)) + } + + if len(box.Dirs) != len(dirsToBeChecked) { + t.Errorf("box %v has incorrect number of dirs; expected %v, got %v", box.Name, len(dirsToBeChecked), len(box.Dirs)) + } + + for name, content := range filesToBeChecked { + f, ok := box.Files[name] + if !ok { + t.Errorf("file %v not present in box %v", name, box.Name) + continue + } + if f.Filename != name { + t.Errorf("box %v: filename mismatch: key: %v; Filename: %v", box.Name, name, f.Filename) + } + if f.Content != content { + t.Errorf("box %v: file %v content does not match: got %v, expected %v", box.Name, name, f.Content, content) + } + dirPath, _ := path.Split(name) + dirPath = strings.TrimSuffix(dirPath, "/") + dir, ok := box.Dirs[dirPath] + if !ok { + t.Errorf("directory %v not present in box %v", dirPath, box.Name) + continue + } + found := false + for _, file := range dir.ChildFiles { + if file == f { + found = true + } + } + if !found { + t.Errorf("file %v not found in directory %v in box %v", name, dirPath, box.Name) + continue + } + } + for name := range dirsToBeChecked { + d, ok := box.Dirs[name] + if !ok { + t.Errorf("directory %v not present in box %v", name, box.Name) + continue + } + if d.Filename != name { + t.Errorf("box %v: filename mismatch: key: %v; Filename: %v", box.Name, name, d.Filename) + } + if name != "" { + dirPath, _ := path.Split(name) + dirPath = strings.TrimSuffix(dirPath, "/") + dir, ok := box.Dirs[dirPath] + if !ok { + t.Errorf("directory %v not present in box %v", dirPath, box.Name) + continue + } + found := false + for _, dir := range dir.ChildDirs { + if dir == d { + found = true + } + } + if !found { + t.Errorf("directory %v not found in directory %v in box %v", name, dirPath, box.Name) + continue + } + } + } +} + +func TestEmbedGo(t *testing.T) { + sourceFiles := []sourceFile{ + { + "boxes.go", + []byte(`package main + +import ( + "github.com/GeertJohan/go.rice" +) + +func main() { + rice.MustFindBox("foo") +} +`), + }, + { + "foo/test1.txt", + []byte(`This is test 1`), + }, + { + "foo/test2.txt", + []byte(`This is test 2`), + }, + { + "foo/bar/test1.txt", + []byte(`This is test 1 in bar`), + }, + { + "foo/bar/baz/test1.txt", + []byte(`This is test 1 in bar/baz`), + }, + { + "foo/bar/baz/backtick`.txt", + []byte(`Backtick filename`), + }, + { + "foo/bar/baz/\"quote\".txt", + []byte(`double quoted filename`), + }, + { + "foo/bar/baz/'quote'.txt", + []byte(`single quoted filename`), + }, + { + "foo/`/`/`.txt", + []byte(`Backticks everywhere!`), + }, + { + "foo/new\nline", + []byte("File with newline in name. Yes, this is possible."), + }, + } + pkg, cleanup, err := setUpTestPkg("foobar", sourceFiles) + defer cleanup() + if err != nil { + t.Error(err) + return + } + + var buffer bytes.Buffer + + err = writeBoxesGo(pkg, &buffer) + if err != nil { + t.Error(err) + return + } + + t.Logf("Generated file: \n%s", buffer.String()) + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, filepath.Join(pkg.Dir, "rice-box.go"), &buffer, 0) + if err != nil { + t.Error(err) + return + } + + var initFunc *ast.FuncDecl + for _, decl := range f.Decls { + if decl, ok := decl.(*ast.FuncDecl); ok && decl.Name != nil && decl.Name.Name == "init" { + initFunc = decl + break + } + } + if initFunc == nil { + t.Fatal("init function not found in generated file") + } + if initFunc.Body == nil { + t.Fatal("init function has no body in generated file") + } + var registrations []*ast.CallExpr + directories := make(map[string]*registeredDir) + files := make(map[string]*registeredFile) + _ = directories + _ = files + for _, stmt := range initFunc.Body.List { + if stmt, ok := stmt.(*ast.ExprStmt); ok { + if call, ok := stmt.X.(*ast.CallExpr); ok { + registrations = append(registrations, call) + } + continue + } + if stmt, ok := stmt.(*ast.AssignStmt); ok { + for i, rhs := range stmt.Rhs { + // Rhs can be EmbeddedDir or EmbeddedFile. + var literal *ast.CompositeLit + literal, ok := unpoint(rhs).(*ast.CompositeLit) + if !ok { + continue + } + if lhs, ok := stmt.Lhs[i].(*ast.Ident); ok { + // variable + edir, direrrs := parseDir(literal, directories, files) + efile, fileerrs := parseFile(literal, files) + abort := false + for _, err := range direrrs { + t.Error("error while parsing dir: ", err) + abort = true + } + for _, err := range fileerrs { + t.Error("error while parsing file: ", err) + abort = true + } + if abort { + return + } + + if edir == nil && efile == nil { + continue + } + if edir != nil { + directories[lhs.Name] = edir + } else { + files[lhs.Name] = efile + } + } else if lhs, ok := stmt.Lhs[i].(*ast.SelectorExpr); ok { + selName, ok := getIdentName(lhs.Sel) + if !ok || selName != "ChildDirs" { + continue + } + varName, ok := getIdentName(lhs.X) + if !ok { + t.Fatalf("cannot parse ChildDirs assignment: %#v", lhs) + } + dir, ok := directories[varName] + if !ok { + t.Fatalf("variable %v not found", varName) + } + + var errors []error + dir.ChildDirs, errors = parseDirsSlice(rhs, directories, files) + + abort := false + for _, err := range errors { + t.Errorf("error parsing child dirs: %s", err) + abort = true + } + if abort { + return + } + } + } + } + } + if len(registrations) == 0 { + t.Fatal("could not find registration of embedded box") + } + + boxes := make(map[string]*registeredBox) + + for _, call := range registrations { + if isSimpleSelector("embedded", "RegisterEmbeddedBox", call.Fun) { + if len(call.Args) != 2 { + t.Fatalf("incorrect arguments to embedded.RegisterEmbeddedBox: %#v", call.Args) + } + boxArg := unpoint(call.Args[1]) + name, err := parseString(call.Args[0]) + if err != nil { + t.Fatalf("first argument to embedded.RegisterEmbeddedBox incorrect: %s", err) + } + boxLit, ok := boxArg.(*ast.CompositeLit) + if !ok { + t.Fatalf("second argument to embedded.RegisterEmbeddedBox is not a composite literal: %#v", boxArg) + } + abort := false + box, errors := parseRegistration(boxLit, directories, files) + for _, err := range errors { + t.Error("error while parsing box: ", err) + abort = true + } + if abort { + return + } + if box == nil { + t.Fatalf("second argument to embedded.RegisterEmbeddedBox is not an embedded.EmbeddedBox: %#v", boxArg) + } + if box.Name != name { + t.Fatalf("first argument to embedded.RegisterEmbeddedBox is not the same as the name in the second argument: %v, %#v", name, boxArg) + } + boxes[name] = box + } + } + + // Validate that all boxes are present. + if _, ok := boxes["foo"]; !ok { + t.Error("box \"foo\" not found") + } + for _, box := range boxes { + validateBox(t, box, sourceFiles) + } +} diff --git a/vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go b/vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go new file mode 100644 index 0000000..beef3ea --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go @@ -0,0 +1,204 @@ +package main + +import ( + "bytes" + "encoding/gob" + "fmt" + "go/build" + "io" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "strings" + "text/template" + + "github.com/GeertJohan/go.rice/embedded" + "github.com/akavel/rsrc/coff" +) + +type sizedReader struct { + *bytes.Reader +} + +func (s sizedReader) Size() int64 { + return int64(s.Len()) +} + +var tmplEmbeddedSysoHelper *template.Template + +func init() { + var err error + tmplEmbeddedSysoHelper, err = template.New("embeddedSysoHelper").Parse(`package {{.Package}} +// ############# GENERATED CODE ##################### +// ## This file was generated by the rice tool. +// ## Do not edit unless you know what you're doing. +// ################################################## + +// extern char _bricebox_{{.Symname}}[], _ericebox_{{.Symname}}; +// int get_{{.Symname}}_length() { +// return &_ericebox_{{.Symname}} - _bricebox_{{.Symname}}; +// } +import "C" +import ( + "bytes" + "encoding/gob" + "github.com/GeertJohan/go.rice/embedded" + "unsafe" +) + +func init() { + ptr := unsafe.Pointer(&C._bricebox_{{.Symname}}) + bts := C.GoBytes(ptr, C.get_{{.Symname}}_length()) + embeddedBox := &embedded.EmbeddedBox{} + err := gob.NewDecoder(bytes.NewReader(bts)).Decode(embeddedBox) + if err != nil { + panic("error decoding embedded box: "+err.Error()) + } + embeddedBox.Link() + embedded.RegisterEmbeddedBox(embeddedBox.Name, embeddedBox) +}`) + if err != nil { + panic("could not parse template embeddedSysoHelper: " + err.Error()) + } +} + +type embeddedSysoHelperData struct { + Package string + Symname string +} + +func operationEmbedSyso(pkg *build.Package) { + + regexpSynameReplacer := regexp.MustCompile(`[^a-z0-9_]`) + + boxMap := findBoxes(pkg) + + // notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ? + if len(boxMap) == 0 { + fmt.Println("no calls to rice.FindBox() found") + return + } + + verbosef("\n") + + for boxname := range boxMap { + // find path and filename for this box + boxPath := filepath.Join(pkg.Dir, boxname) + boxFilename := strings.Replace(boxname, "/", "-", -1) + boxFilename = strings.Replace(boxFilename, "..", "back", -1) + boxFilename = strings.Replace(boxFilename, ".", "-", -1) + + // verbose info + verbosef("embedding box '%s'\n", boxname) + verbosef("\tto file %s\n", boxFilename) + + // read box metadata + boxInfo, ierr := os.Stat(boxPath) + if ierr != nil { + fmt.Printf("Error: unable to access box at %s\n", boxPath) + os.Exit(1) + } + + // create box datastructure (used by template) + box := &embedded.EmbeddedBox{ + Name: boxname, + Time: boxInfo.ModTime(), + EmbedType: embedded.EmbedTypeSyso, + Files: make(map[string]*embedded.EmbeddedFile), + Dirs: make(map[string]*embedded.EmbeddedDir), + } + + // fill box datastructure with file data + filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error { + if err != nil { + fmt.Printf("error walking box: %s\n", err) + os.Exit(1) + } + + filename := strings.TrimPrefix(path, boxPath) + filename = strings.Replace(filename, "\\", "/", -1) + filename = strings.TrimPrefix(filename, "/") + if info.IsDir() { + embeddedDir := &embedded.EmbeddedDir{ + Filename: filename, + DirModTime: info.ModTime(), + } + verbosef("\tincludes dir: '%s'\n", embeddedDir.Filename) + box.Dirs[embeddedDir.Filename] = embeddedDir + + // add tree entry (skip for root, it'll create a recursion) + if embeddedDir.Filename != "" { + pathParts := strings.Split(embeddedDir.Filename, "/") + parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")] + parentDir.ChildDirs = append(parentDir.ChildDirs, embeddedDir) + } + } else { + embeddedFile := &embedded.EmbeddedFile{ + Filename: filename, + FileModTime: info.ModTime(), + Content: "", + } + verbosef("\tincludes file: '%s'\n", embeddedFile.Filename) + contentBytes, err := ioutil.ReadFile(path) + if err != nil { + fmt.Printf("error reading file content while walking box: %s\n", err) + os.Exit(1) + } + embeddedFile.Content = string(contentBytes) + box.Files[embeddedFile.Filename] = embeddedFile + } + return nil + }) + + // encode embedded box to gob file + boxGobBuf := &bytes.Buffer{} + err := gob.NewEncoder(boxGobBuf).Encode(box) + if err != nil { + fmt.Printf("error encoding box to gob: %v\n", err) + os.Exit(1) + } + + verbosef("gob-encoded embeddedBox is %d bytes large\n", boxGobBuf.Len()) + + // write coff + symname := regexpSynameReplacer.ReplaceAllString(boxname, "_") + createCoffSyso(boxname, symname, "386", boxGobBuf.Bytes()) + createCoffSyso(boxname, symname, "amd64", boxGobBuf.Bytes()) + + // write go + sysoHelperData := embeddedSysoHelperData{ + Package: pkg.Name, + Symname: symname, + } + fileSysoHelper, err := os.Create(boxFilename + ".rice-box.go") + if err != nil { + fmt.Printf("error creating syso helper: %v\n", err) + os.Exit(1) + } + err = tmplEmbeddedSysoHelper.Execute(fileSysoHelper, sysoHelperData) + if err != nil { + fmt.Printf("error executing tmplEmbeddedSysoHelper: %v\n", err) + os.Exit(1) + } + } +} + +func createCoffSyso(boxFilename string, symname string, arch string, data []byte) { + boxCoff := coff.NewRDATA() + switch arch { + case "386": + case "amd64": + boxCoff.FileHeader.Machine = 0x8664 + default: + panic("invalid arch") + } + boxCoff.AddData("_bricebox_"+symname, sizedReader{bytes.NewReader(data)}) + boxCoff.AddData("_ericebox_"+symname, io.NewSectionReader(strings.NewReader("\000\000"), 0, 2)) // TODO: why? copied from rsrc, which copied it from as-generated + boxCoff.Freeze() + err := writeCoff(boxCoff, boxFilename+"_"+arch+".rice-box.syso") + if err != nil { + fmt.Printf("error writing %s coff/.syso: %v\n", arch, err) + os.Exit(1) + } +} diff --git a/vendor/github.com/GeertJohan/go.rice/rice/find.go b/vendor/github.com/GeertJohan/go.rice/rice/find.go new file mode 100644 index 0000000..6d78eea --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/rice/find.go @@ -0,0 +1,150 @@ +package main + +import ( + "fmt" + "go/ast" + "go/build" + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" +) + +func badArgument(fileset *token.FileSet, p token.Pos) { + pos := fileset.Position(p) + filename := pos.Filename + base, err := os.Getwd() + if err == nil { + rpath, perr := filepath.Rel(base, pos.Filename) + if perr == nil { + filename = rpath + } + } + msg := fmt.Sprintf("%s:%d: Error: found call to rice.FindBox, "+ + "but argument must be a string literal.\n", filename, pos.Line) + fmt.Println(msg) + os.Exit(1) +} + +func findBoxes(pkg *build.Package) map[string]bool { + // create map of boxes to embed + var boxMap = make(map[string]bool) + + // create one list of files for this package + filenames := make([]string, 0, len(pkg.GoFiles)+len(pkg.CgoFiles)) + filenames = append(filenames, pkg.GoFiles...) + filenames = append(filenames, pkg.CgoFiles...) + + // loop over files, search for rice.FindBox(..) calls + for _, filename := range filenames { + // find full filepath + fullpath := filepath.Join(pkg.Dir, filename) + if strings.HasSuffix(filename, "rice-box.go") { + // Ignore *.rice-box.go files + verbosef("skipping file %q\n", fullpath) + continue + } + verbosef("scanning file %q\n", fullpath) + + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, fullpath, nil, 0) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + var riceIsImported bool + ricePkgName := "rice" + for _, imp := range f.Imports { + if strings.HasSuffix(imp.Path.Value, "go.rice\"") { + if imp.Name != nil { + ricePkgName = imp.Name.Name + } + riceIsImported = true + break + } + } + if !riceIsImported { + // Rice wasn't imported, so we won't find a box. + continue + } + if ricePkgName == "_" { + // Rice pkg is unnamed, so we won't find a box. + continue + } + + // Inspect AST, looking for calls to (Must)?FindBox. + // First parameter of the func must be a basic literal. + // Identifiers won't be resolved. + var nextIdentIsBoxFunc bool + var nextBasicLitParamIsBoxName bool + var boxCall token.Pos + var variableToRemember string + var validVariablesForBoxes map[string]bool = make(map[string]bool) + + ast.Inspect(f, func(node ast.Node) bool { + if node == nil { + return false + } + switch x := node.(type) { + // this case fixes the var := func() style assignments, not assignments to vars declared separately from the assignment. + case *ast.AssignStmt: + var assign = node.(*ast.AssignStmt) + name, found := assign.Lhs[0].(*ast.Ident) + if found { + variableToRemember = name.Name + composite, first := assign.Rhs[0].(*ast.CompositeLit) + if first { + riceSelector, second := composite.Type.(*ast.SelectorExpr) + + if second { + callCorrect := riceSelector.Sel.Name == "Config" + packageName, third := riceSelector.X.(*ast.Ident) + + if third && callCorrect && packageName.Name == ricePkgName { + validVariablesForBoxes[name.Name] = true + verbosef("\tfound variable, saving to scan for boxes: %q\n", name.Name) + } + } + } + } + case *ast.Ident: + if nextIdentIsBoxFunc || ricePkgName == "." { + nextIdentIsBoxFunc = false + if x.Name == "FindBox" || x.Name == "MustFindBox" { + nextBasicLitParamIsBoxName = true + boxCall = x.Pos() + } + } else { + if x.Name == ricePkgName || validVariablesForBoxes[x.Name] { + nextIdentIsBoxFunc = true + } + } + case *ast.BasicLit: + if nextBasicLitParamIsBoxName { + if x.Kind == token.STRING { + nextBasicLitParamIsBoxName = false + // trim "" or `` + name := x.Value[1 : len(x.Value)-1] + boxMap[name] = true + verbosef("\tfound box %q\n", name) + } else { + badArgument(fset, boxCall) + } + } + + default: + if nextIdentIsBoxFunc { + nextIdentIsBoxFunc = false + } + if nextBasicLitParamIsBoxName { + badArgument(fset, boxCall) + } + } + return true + }) + } + + return boxMap +} diff --git a/vendor/github.com/GeertJohan/go.rice/rice/find_test.go b/vendor/github.com/GeertJohan/go.rice/rice/find_test.go new file mode 100644 index 0000000..e5289e9 --- /dev/null +++ b/vendor/github.com/GeertJohan/go.rice/rice/find_test.go @@ -0,0 +1,302 @@ +package main + +import ( + "fmt" + "go/build" + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +type sourceFile struct { + Name string + Contents []byte +} + +func expectBoxes(expected []string, actual map[string]bool) error { + if len(expected) != len(actual) { + return fmt.Errorf("expected %v, got %v", expected, actual) + } + for _, box := range expected { + if _, ok := actual[box]; !ok { + return fmt.Errorf("expected %v, got %v", expected, actual) + } + } + return nil +} + +func setUpTestPkg(pkgName string, files []sourceFile) (*build.Package, func(), error) { + temp, err := ioutil.TempDir("", "go.rice-test") + if err != nil { + return nil, func() {}, err + } + cleanup := func() { + os.RemoveAll(temp) + } + dir := filepath.Join(temp, pkgName) + if err := os.Mkdir(dir, 0770); err != nil { + return nil, cleanup, err + } + for _, f := range files { + fullPath := filepath.Join(dir, f.Name) + if err := os.MkdirAll(filepath.Dir(fullPath), 0770); err != nil { + return nil, cleanup, err + } + if err := ioutil.WriteFile(fullPath, f.Contents, 0660); err != nil { + return nil, cleanup, err + } + } + pkg, err := build.ImportDir(dir, 0) + return pkg, cleanup, err +} + +func TestFindOneBox(t *testing.T) { + pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{ + { + "boxes.go", + []byte(`package main + +import ( + "github.com/GeertJohan/go.rice" +) + +func main() { + rice.MustFindBox("foo") +} +`), + }, + }) + defer cleanup() + if err != nil { + t.Error(err) + return + } + + expectedBoxes := []string{"foo"} + boxMap := findBoxes(pkg) + if err := expectBoxes(expectedBoxes, boxMap); err != nil { + t.Error(err) + } +} + +func TestFindOneBoxViaVariable(t *testing.T) { + + pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{ + { + "boxes.go", + []byte(`package main + +import ( + "github.com/GeertJohan/go.rice" +) + +func main() { + conf := rice.Config{ + LocateOrder: []rice.LocateMethod{rice.LocateEmbedded, rice.LocateAppended, rice.LocateFS}, + } + conf.MustFindBox("foo") +} +`), + }, + }) + defer cleanup() + if err != nil { + t.Error(err) + return + } + + expectedBoxes := []string{"foo"} + boxMap := findBoxes(pkg) + if err := expectBoxes(expectedBoxes, boxMap); err != nil { + t.Error(err) + } +} + +func TestFindMultipleBoxes(t *testing.T) { + pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{ + { + "boxes.go", + []byte(`package main + +import ( + "github.com/GeertJohan/go.rice" +) + +func main() { + rice.MustFindBox("foo") + rice.MustFindBox("bar") +} +`), + }, + }) + defer cleanup() + if err != nil { + t.Error(err) + return + } + + expectedBoxes := []string{"foo", "bar"} + boxMap := findBoxes(pkg) + if err := expectBoxes(expectedBoxes, boxMap); err != nil { + t.Error(err) + } +} + +func TestNoBoxFoundIfRiceNotImported(t *testing.T) { + pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{ + { + "boxes.go", + []byte(`package main +type fakerice struct {} + +func (fr fakerice) FindBox(s string) { +} + +func main() { + rice := fakerice{} + rice.FindBox("foo") +} +`), + }, + }) + defer cleanup() + if err != nil { + t.Error(err) + return + } + + boxMap := findBoxes(pkg) + if _, ok := boxMap["foo"]; ok { + t.Errorf("Unexpected box %q was found", "foo") + } +} + +func TestUnrelatedBoxesAreNotFound(t *testing.T) { + pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{ + { + "boxes.go", + []byte(`package foobar + +import ( + _ "github.com/GeertJohan/go.rice" +) + +type fakerice struct {} + +func (fr fakerice) FindBox(s string) { +} + +func FindBox(s string) { + +} + +func LoadBoxes() { + rice := fakerice{} + rice.FindBox("foo") + + FindBox("bar") +} +`), + }, + }) + defer cleanup() + if err != nil { + t.Error(err) + return + } + + boxMap := findBoxes(pkg) + for _, box := range []string{"foo", "bar"} { + if _, ok := boxMap[box]; ok { + t.Errorf("Unexpected box %q was found", box) + } + } +} + +func TestMixGoodAndBadBoxes(t *testing.T) { + pkg, cleanup, err := setUpTestPkg("foobar", []sourceFile{ + { + "boxes1.go", + []byte(`package foobar + +import ( + _ "github.com/GeertJohan/go.rice" +) + +type fakerice struct {} + +func (fr fakerice) FindBox(s string) { +} + +func FindBox(s string) { + +} + +func LoadBoxes1() { + rice := fakerice{} + rice.FindBox("foo") + + FindBox("bar") +} +`), + }, + { + "boxes2.go", + []byte(`package foobar + +import ( + noodles "github.com/GeertJohan/go.rice" +) + +func LoadBoxes2() { + FindBox("baz") + noodles.FindBox("veggies") +} +`), + }, + { + "boxes3.go", + []byte(`package foobar + +import ( + "github.com/GeertJohan/go.rice" +) + +func LoadBoxes3() { + rice.FindBox("fish") +} +`), + }, + { + "boxes4.go", + []byte(`package foobar + +import ( + . "github.com/GeertJohan/go.rice" +) + +func LoadBoxes3() { + MustFindBox("chicken") +} +`), + }, + }) + defer cleanup() + if err != nil { + t.Error(err) + return + } + + boxMap := findBoxes(pkg) + for _, box := range []string{"foo", "bar", "baz"} { + if _, ok := boxMap[box]; ok { + t.Errorf("Unexpected box %q was found", box) + } + } + for _, box := range []string{"veggies", "fish", "chicken"} { + if _, ok := boxMap[box]; !ok { + t.Errorf("Ex