pax_global_header00006660000000000000000000000064137663733300014525gustar00rootroot0000000000000052 comment=0634379bb7b1af96fb16686afc301ae7ae9ee8b9 go.rice-1.0.2/000077500000000000000000000000001376637333000130535ustar00rootroot00000000000000go.rice-1.0.2/.gitignore000066400000000000000000000001301376637333000150350ustar00rootroot00000000000000/example/example /example/example.exe /rice/rice /rice/rice.exe *.rice-box.go .wercker go.rice-1.0.2/.travis.yml000066400000000000000000000003111376637333000151570ustar00rootroot00000000000000language: go go: - master - 1.11.x - 1.10.x - 1.9.x - 1.8.x install: - go get -t ./... - env script: - go build -x ./... - go test -cover ./... - go vet ./... go.rice-1.0.2/AUTHORS000066400000000000000000000002041376637333000141170ustar00rootroot00000000000000Geert-Johan Riemer Paul Maddox Vincent Petithory go.rice-1.0.2/LICENSE000066400000000000000000000024271376637333000140650ustar00rootroot00000000000000Copyright (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.go.rice-1.0.2/README.md000066400000000000000000000136061376637333000143400ustar00rootroot00000000000000# 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 easy. During development `go.rice` will load required files directly from disk. Upon deployment it's easy to add all resource files to a executable using the `rice` tool, without changing the source code for your package. go.rice provides methods to add resources to a binary in different scenarios. ## What does it do The first thing go.rice does is finding the correct absolute path for your resource files. Say you are executing a binary in your home directory, but your `html-files` are in `$GOPATH/src/yourApplication/html-files`. `go.rice` will lookup the correct path for that directory (relative to the location of yourApplication). All you have to do is include the resources using `rice.FindBox("html-files")`. This works fine when the source is available to the machine executing the binary, which is the case when installing the executable with `go get` or `go install`. But it does not work when you wish to provide a single binary without source. This is where the `rice` tool comes in. It analyses source code and finds call's to `rice.FindBox(..)`. Then it adds the required directories to the executable binary, There are two strategies to do this. You can 'embed' the assets by generating go source code and then compile them into the executable binary, or you can 'append' the assets to the executable binary after compiling. In both cases the `rice.FindBox(..)` call detects 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. ```bash 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) ``` Serve 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 there is no guarantee the boxes are loaded at that time. ### Calling FindBox and MustFindBox Always call `FindBox()` or `MustFindBox()` with string literals e.g. `FindBox("example")`. Do not use string constants or variables. This will prevent the rice tool to fail with error `Error: found call to rice.FindBox, but argument must be a string literal.`. ## 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 multiple strategies to add the resources and assets to a binary, each has pro's and con's but all will work without requiring changes to the way you load the resources. ### `rice embed-go`: Embed resources by generating Go source code Execute this method before building. It generates a single Go source file called *rice-box.go* for each package. The generated go file contains all assets. The Go tool compiles this into the binary. The downside with this option is that the generated go source file can become large, which may slow down compilation and requires more memory to compile. Execute the following commands: ```bash 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. When creating a box, be aware that any symbolic links inside your box's directory are not followed. When the box itself is a symbolic link, the rice tool resolves its actual location before adding the contents. ### `rice 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. Using the append method works great for adding large assets to an executable binary. A downside for appending is that it does not provide a working Seek method. Run the following commands to create a standalone executable. ```bash go build -o example rice append --exec example ``` ## Help information Run `rice --help` for information about all flags and subcommands. You can use the `--help` flag on each sub-command. For example: `rice append --help`. ## Order of precedence When opening a new box, the `rice.FindBox(..)` tries to locate the resources in the following order: - embedded (generated as `rice-box.go`) - appended (appended to the binary executable after compiling) - 'live' from filesystem ## License This project is licensed under a Simplified BSD license. Please read the [LICENSE file][license]. ## 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 go.rice-1.0.2/appended.go000066400000000000000000000070201376637333000151610ustar00rootroot00000000000000package rice import ( "archive/zip" "log" "os" "path/filepath" "strings" "time" "github.com/daaku/go.zipexe" ) // appendedBox defines an appended box type appendedBox struct { Name string // box name Files map[string]*appendedFile // appended files (*zip.File) by full path Time time.Time } type appendedFile struct { zipFile *zip.File dir bool dirInfo *appendedDirInfo children []*appendedFile content []byte } // appendedBoxes is a public register of appendes boxes var appendedBoxes = make(map[string]*appendedBox) func init() { // find if exec is appended thisFile, err := os.Executable() if err != nil { return // not appended or cant find self executable } thisFile, err = filepath.EvalSymlinks(thisFile) if err != nil { return } closer, rd, err := zipexe.OpenCloser(thisFile) if err != nil { return // not appended } defer closer.Close() for _, f := range rd.File { // get box and file name from f.Name fileParts := strings.SplitN(strings.TrimLeft(filepath.ToSlash(f.Name), "/"), "/", 2) boxName := fileParts[0] var fileName string if len(fileParts) > 1 { fileName = fileParts[1] } // find box or create new one if doesn't exist box := appendedBoxes[boxName] if box == nil { box = &appendedBox{ Name: boxName, Files: make(map[string]*appendedFile), Time: f.ModTime(), } appendedBoxes[boxName] = box } // create and add file to box af := &appendedFile{ zipFile: f, } if f.Comment == "dir" { af.dir = true af.dirInfo = &appendedDirInfo{ name: filepath.Base(af.zipFile.Name), time: af.zipFile.ModTime(), } } else { // this is a file, we need it's contents so we can create a bytes.Reader when the file is opened // make a new byteslice af.content = make([]byte, af.zipFile.FileInfo().Size()) // ignore reading empty files from zip (empty file still is a valid file to be read though!) if len(af.content) > 0 { // open io.ReadCloser rc, err := af.zipFile.Open() if err != nil { af.content = nil // this will cause an error when the file is being opened or seeked (which is good) // TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet.. log.Printf("error opening appended file %s: %v", af.zipFile.Name, err) } else { _, err = rc.Read(af.content) rc.Close() if err != nil { af.content = nil // this will cause an error when the file is being opened or seeked (which is good) // TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet.. log.Printf("error reading data for appended file %s: %v", af.zipFile.Name, err) } } } } // add appendedFile to box file list box.Files[fileName] = af // add to parent dir (if any) dirName := filepath.Dir(fileName) if dirName == "." { dirName = "" } if fileName != "" { // don't make box root dir a child of itself if dir := box.Files[dirName]; dir != nil { dir.children = append(dir.children, af) } } } } // implements os.FileInfo. // used for Readdir() type appendedDirInfo struct { name string time time.Time } func (adi *appendedDirInfo) Name() string { return adi.name } func (adi *appendedDirInfo) Size() int64 { return 0 } func (adi *appendedDirInfo) Mode() os.FileMode { return os.ModeDir } func (adi *appendedDirInfo) ModTime() time.Time { return adi.time } func (adi *appendedDirInfo) IsDir() bool { return true } func (adi *appendedDirInfo) Sys() interface{} { return nil } go.rice-1.0.2/box.go000066400000000000000000000175441376637333000142050ustar00rootroot00000000000000package rice import ( "bytes" "errors" "fmt" "io/ioutil" "os" "path/filepath" "runtime" "strings" "time" "github.com/GeertJohan/go.rice/embedded" ) // Box abstracts a directory for resources/files. // It can either load files from disk, or from embedded code (when `rice --embed` was ran). type Box struct { name string absolutePath string embed *embedded.EmbeddedBox appendd *appendedBox } var defaultLocateOrder = []LocateMethod{LocateEmbedded, LocateAppended, LocateFS} func findBox(name string, order []LocateMethod) (*Box, error) { b := &Box{name: name} // no support for absolute paths since gopath can be different on different machines. // therefore, required box must be located relative to package requiring it. if filepath.IsAbs(name) { return nil, errors.New("given name/path is absolute") } var err error for _, method := range order { switch method { case LocateEmbedded: if embed := embedded.EmbeddedBoxes[name]; embed != nil { b.embed = embed return b, nil } case LocateAppended: appendedBoxName := strings.Replace(name, `/`, `-`, -1) if appendd := appendedBoxes[appendedBoxName]; appendd != nil { b.appendd = appendd return b, nil } case LocateFS: // resolve absolute directory path err := b.resolveAbsolutePathFromCaller() if err != nil { continue } // check if absolutePath exists on filesystem info, err := os.Stat(b.absolutePath) if err != nil { continue } // check if absolutePath is actually a directory if !info.IsDir() { err = errors.New("given name/path is not a directory") continue } return b, nil case LocateWorkingDirectory: // resolve absolute directory path err := b.resolveAbsolutePathFromWorkingDirectory() if err != nil { continue } // check if absolutePath exists on filesystem info, err := os.Stat(b.absolutePath) if err != nil { continue } // check if absolutePath is actually a directory if !info.IsDir() { err = errors.New("given name/path is not a directory") continue } return b, nil } } if err == nil { err = fmt.Errorf("could not locate box %q", name) } return nil, err } // FindBox returns a Box instance for given name. // When the given name is a relative path, it's base path will be the calling pkg/cmd's source root. // When the given name is absolute, it's absolute. derp. // Make sure the path doesn't contain any sensitive information as it might be placed into generated go source (embedded). func FindBox(name string) (*Box, error) { return findBox(name, defaultLocateOrder) } // MustFindBox returns a Box instance for given name, like FindBox does. // It does not return an error, instead it panics when an error occurs. func MustFindBox(name string) *Box { box, err := findBox(name, defaultLocateOrder) if err != nil { panic(err) } return box } // This is injected as a mutable function literal so that we can mock it out in // tests and return a fixed test file. var resolveAbsolutePathFromCaller = func(name string, nStackFrames int) (string, error) { _, callingGoFile, _, ok := runtime.Caller(nStackFrames) if !ok { return "", errors.New("couldn't find caller on stack") } // resolve to proper path pkgDir := filepath.Dir(callingGoFile) // fix for go cover const coverPath = "_test/_obj_test" if !filepath.IsAbs(pkgDir) { if i := strings.Index(pkgDir, coverPath); i >= 0 { pkgDir = pkgDir[:i] + pkgDir[i+len(coverPath):] // remove coverPath pkgDir = filepath.Join(os.Getenv("GOPATH"), "src", pkgDir) // make absolute } } return filepath.Join(pkgDir, name), nil } func (b *Box) resolveAbsolutePathFromCaller() error { path, err := resolveAbsolutePathFromCaller(b.name, 4) if err != nil { return err } b.absolutePath = path return nil } func (b *Box) resolveAbsolutePathFromWorkingDirectory() error { path, err := os.Getwd() if err != nil { return err } b.absolutePath = filepath.Join(path, b.name) return nil } // IsEmbedded indicates wether this box was embedded into the application func (b *Box) IsEmbedded() bool { return b.embed != nil } // IsAppended indicates wether this box was appended to the application func (b *Box) IsAppended() bool { return b.appendd != nil } // Time returns how actual the box is. // When the box is embedded, it's value is saved in the embedding code. // When the box is live, this methods returns time.Now() func (b *Box) Time() time.Time { if b.IsEmbedded() { return b.embed.Time } if b.IsAppended() { return b.appendd.Time } return time.Now() } // Open opens a File from the box // If there is an error, it will be of type *os.PathError. func (b *Box) Open(name string) (*File, error) { if Debug { fmt.Printf("Open(%s)\n", name) } if b.IsEmbedded() { if Debug { fmt.Println("Box is embedded") } // trim prefix (paths are relative to box) name = strings.TrimLeft(name, "/") if Debug { fmt.Printf("Trying %s\n", name) } // search for file ef := b.embed.Files[name] if ef == nil { if Debug { fmt.Println("Didn't find file in embed") } // file not found, try dir ed := b.embed.Dirs[name] if ed == nil { if Debug { fmt.Println("Didn't find dir in embed") } // dir not found, error out return nil, &os.PathError{ Op: "open", Path: name, Err: os.ErrNotExist, } } if Debug { fmt.Println("Found dir. Returning virtual dir") } vd := newVirtualDir(ed) return &File{virtualD: vd}, nil } // box is embedded if Debug { fmt.Println("Found file. Returning virtual file") } vf := newVirtualFile(ef) return &File{virtualF: vf}, nil } if b.IsAppended() { // trim prefix (paths are relative to box) name = strings.TrimLeft(name, "/") // search for file appendedFile := b.appendd.Files[name] if appendedFile == nil { return nil, &os.PathError{ Op: "open", Path: name, Err: os.ErrNotExist, } } // create new file f := &File{ appendedF: appendedFile, } // if this file is a directory, we want to be able to read and seek if !appendedFile.dir { // looks like malformed data in zip, error now if appendedFile.content == nil { return nil, &os.PathError{ Op: "open", Path: "name", Err: errors.New("error reading data from zip file"), } } // create new bytes.Reader f.appendedFileReader = bytes.NewReader(appendedFile.content) } // all done return f, nil } // perform os open if Debug { fmt.Printf("Using os.Open(%s)", filepath.Join(b.absolutePath, name)) } file, err := os.Open(filepath.Join(b.absolutePath, name)) if err != nil { return nil, err } return &File{realF: file}, nil } // Bytes returns the content of the file with given name as []byte. func (b *Box) Bytes(name string) ([]byte, error) { file, err := b.Open(name) if err != nil { return nil, err } defer file.Close() content, err := ioutil.ReadAll(file) if err != nil { return nil, err } return content, nil } // MustBytes returns the content of the file with given name as []byte. // panic's on error. func (b *Box) MustBytes(name string) []byte { bts, err := b.Bytes(name) if err != nil { panic(err) } return bts } // String returns the content of the file with given name as string. func (b *Box) String(name string) (string, error) { // check if box is embedded, optimized fast path if b.IsEmbedded() { // find file in embed ef := b.embed.Files[name] if ef == nil { return "", os.ErrNotExist } // return as string return ef.Content, nil } bts, err := b.Bytes(name) if err != nil { return "", err } return string(bts), nil } // MustString returns the content of the file with given name as string. // panic's on error. func (b *Box) MustString(name string) string { str, err := b.String(name) if err != nil { panic(err) } return str } // Name returns the name of the box func (b *Box) Name() string { return b.name } go.rice-1.0.2/config.go000066400000000000000000000027371376637333000146600ustar00rootroot00000000000000package rice // LocateMethod defines how a box is located. type LocateMethod int const ( LocateFS = LocateMethod(iota) // Locate on the filesystem according to package path. LocateAppended // Locate boxes appended to the executable. LocateEmbedded // Locate embedded boxes. LocateWorkingDirectory // Locate on the binary working directory ) // Config allows customizing the box lookup behavior. type Config struct { // LocateOrder defines the priority order that boxes are searched for. By // default, the package global FindBox searches for embedded boxes first, // then appended boxes, and then finally boxes on the filesystem. That // search order may be customized by provided the ordered list here. Leaving // out a particular method will omit that from the search space. For // example, []LocateMethod{LocateEmbedded, LocateAppended} will never search // the filesystem for boxes. LocateOrder []LocateMethod } // FindBox searches for boxes using the LocateOrder of the config. func (c *Config) FindBox(boxName string) (*Box, error) { return findBox(boxName, c.LocateOrder) } // MustFindBox searches for boxes using the LocateOrder of the config, like // FindBox does. It does not return an error, instead it panics when an error // occurs. func (c *Config) MustFindBox(boxName string) *Box { box, err := findBox(boxName, c.LocateOrder) if err != nil { panic(err) } return box } go.rice-1.0.2/config_test.go000066400000000000000000000066251376637333000157170ustar00rootroot00000000000000package 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) } } } go.rice-1.0.2/debug.go000066400000000000000000000001211376637333000144620ustar00rootroot00000000000000package rice // Debug can be set to true to enable debugging. var Debug = false go.rice-1.0.2/embedded.go000066400000000000000000000043241376637333000151360ustar00rootroot00000000000000package rice import ( "os" "time" "github.com/GeertJohan/go.rice/embedded" ) // re-type to make exported methods invisible to user (godoc) // they're not required for the user // embeddedDirInfo implements os.FileInfo type embeddedDirInfo embedded.EmbeddedDir // Name returns the base name of the directory // (implementing os.FileInfo) func (ed *embeddedDirInfo) Name() string { return ed.Filename } // Size always returns 0 // (implementing os.FileInfo) func (ed *embeddedDirInfo) Size() int64 { return 0 } // Mode returns the file mode bits // (implementing os.FileInfo) func (ed *embeddedDirInfo) Mode() os.FileMode { return os.FileMode(0555 | os.ModeDir) // dr-xr-xr-x } // ModTime returns the modification time // (implementing os.FileInfo) func (ed *embeddedDirInfo) ModTime() time.Time { return ed.DirModTime } // IsDir returns the abbreviation for Mode().IsDir() (always true) // (implementing os.FileInfo) func (ed *embeddedDirInfo) IsDir() bool { return true } // Sys returns the underlying data source (always nil) // (implementing os.FileInfo) func (ed *embeddedDirInfo) Sys() interface{} { return nil } // re-type to make exported methods invisible to user (godoc) // they're not required for the user // embeddedFileInfo implements os.FileInfo type embeddedFileInfo embedded.EmbeddedFile // Name returns the base name of the file // (implementing os.FileInfo) func (ef *embeddedFileInfo) Name() string { return ef.Filename } // Size returns the length in bytes for regular files; system-dependent for others // (implementing os.FileInfo) func (ef *embeddedFileInfo) Size() int64 { return int64(len(ef.Content)) } // Mode returns the file mode bits // (implementing os.FileInfo) func (ef *embeddedFileInfo) Mode() os.FileMode { return os.FileMode(0555) // r-xr-xr-x } // ModTime returns the modification time // (implementing os.FileInfo) func (ef *embeddedFileInfo) ModTime() time.Time { return ef.FileModTime } // IsDir returns the abbreviation for Mode().IsDir() (always false) // (implementing os.FileInfo) func (ef *embeddedFileInfo) IsDir() bool { return false } // Sys returns the underlying data source (always nil) // (implementing os.FileInfo) func (ef *embeddedFileInfo) Sys() interface{} { return nil } go.rice-1.0.2/embedded/000077500000000000000000000000001376637333000146045ustar00rootroot00000000000000go.rice-1.0.2/embedded/embedded.go000066400000000000000000000047331376637333000166730ustar00rootroot00000000000000// Package embedded defines embedded data types that are shared between the go.rice package and generated code. package embedded import ( "fmt" "path/filepath" "strings" "time" ) const ( EmbedTypeGo = 0 ) // EmbeddedBox defines an embedded box type EmbeddedBox struct { Name string // box name Time time.Time // embed time EmbedType int // kind of embedding Files map[string]*EmbeddedFile // ALL embedded files by full path Dirs map[string]*EmbeddedDir // ALL embedded dirs by full path } // Link creates the ChildDirs and ChildFiles links in all EmbeddedDir's func (e *EmbeddedBox) Link() { for _, ed := range e.Dirs { ed.ChildDirs = make([]*EmbeddedDir, 0) ed.ChildFiles = make([]*EmbeddedFile, 0) } for path, ed := range e.Dirs { // skip for root, it'll create a recursion if path == "" { continue } parentDirpath, _ := filepath.Split(path) if strings.HasSuffix(parentDirpath, "/") { parentDirpath = parentDirpath[:len(parentDirpath)-1] } parentDir := e.Dirs[parentDirpath] if parentDir == nil { panic("parentDir `" + parentDirpath + "` is missing in embedded box") } parentDir.ChildDirs = append(parentDir.ChildDirs, ed) } for path, ef := range e.Files { dirpath, _ := filepath.Split(path) if strings.HasSuffix(dirpath, "/") { dirpath = dirpath[:len(dirpath)-1] } dir := e.Dirs[dirpath] if dir == nil { panic("dir `" + dirpath + "` is missing in embedded box") } dir.ChildFiles = append(dir.ChildFiles, ef) } } // EmbeddedDir is instanced in the code generated by the rice tool and contains all necicary information about an embedded file type EmbeddedDir struct { Filename string DirModTime time.Time ChildDirs []*EmbeddedDir // direct childs, as returned by virtualDir.Readdir() ChildFiles []*EmbeddedFile // direct childs, as returned by virtualDir.Readdir() } // EmbeddedFile is instanced in the code generated by the rice tool and contains all necicary information about an embedded file type EmbeddedFile struct { Filename string // filename FileModTime time.Time Content string } // EmbeddedBoxes is a public register of embedded boxes var EmbeddedBoxes = make(map[string]*EmbeddedBox) // RegisterEmbeddedBox registers an EmbeddedBox func RegisterEmbeddedBox(name string, box *EmbeddedBox) { if _, exists := EmbeddedBoxes[name]; exists { panic(fmt.Sprintf("EmbeddedBox with name `%s` exists already", name)) } EmbeddedBoxes[name] = box } go.rice-1.0.2/example/000077500000000000000000000000001376637333000145065ustar00rootroot00000000000000go.rice-1.0.2/example/example-files/000077500000000000000000000000001376637333000172415ustar00rootroot00000000000000go.rice-1.0.2/example/example-files/file.txt000066400000000000000000000000221376637333000207130ustar00rootroot00000000000000test content breakgo.rice-1.0.2/example/example-files/img/000077500000000000000000000000001376637333000200155ustar00rootroot00000000000000go.rice-1.0.2/example/example-files/img/doge.jpg000066400000000000000000001504551376637333000214470ustar00rootroot00000000000000JFIF,,ExifII*  1 2i %ИJ  NIKON CORPORATIONNIKON D5000Ver.1.00 2010:02:03 21:08:31 )  "'0221 . B  J R   Z |b Pd5050500100m6    Đ T 2 2010:02:03 21:08:312010:02:03 21:08:31/ h NikonMM*40210~       $ "#: $%F+T,^d@ Y<B!#X #z&######$NORMAL AUTO AF-A '  4 4212323401000100STANDARDSTANDARDd d 01000100d & # 8 0215jLML#76=#3LI5/ힳ!^S w _"E08NC\LZGHm& rUs`Ӈ  ׃x֛8!`z.b=lث5TwtT/ 5@D3rAn;c }ɐ6be$?x ݌`KUd5۩@?2 d8ҖIE"[{uP n|)qh[!hBjn6Ja밀]$3&a=M݇!0D%k[t)ÖJP 2xG>,DVAPFB4sh).Sz܅/&𡱠+-R[E*Ԓ/Jsl}iAXaH;jBbbFt4q~p^t7,&೨w>an`Xkr} \>d%ľ Љ b#6ݣ|+Vh Qh/&0948m"GEg| ~ÀJM8n>1nov*45f9``S]ŜW!pNގd+aHѷӦ ᾱUl h*5K@YQ(s:l}m)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0& HZM\˖N8&$"_{vP n|-,\IhFkoR5̀3'='4' ѧE(gq^$ƖHNƑ35wMw13 e7t|^X֎pV[BU.4nX.|("sx,FpMKj 0A츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G1)d=ۚz{Do6'QCE W.&?yPPy?&.W ECQ'6oD{z=d)>|("sx,FpMKj 0NA츥25輱Vi$Z;ݠ^\HUBӅXLafJk-9nSRgv/  ]:ڛ}O~G11yOt>2f9q~S ]WAipWB:]`L/v<}:r)QX@.Ԓӫ@P(s:m}l̝MJθ)[d%DЉ!#7*='3Ҕ5RokFhz,-|n Pw{^"Eږ18OC]L[GI ' rUJaӆ  ׂyכ>%ec6دcjg^+UutT*Ш_fkbȐ9Dzj)·|sx鴀MjZ }0/HC£L7ϙ$ZJ;-t_a\UsҲuXagI`Jϔ,9.7#ꑡ/"E$f}YGÖJNǒ?r?Mv62'e9p6~FSfkkWC;BaX,vgc+<d3E(PQH)0)1@)J@GҘz{өvZWq܈8_Po5wo9 ')p֕CҴIlUޮ@ZZif)7+Gپh;(mY{8oj'pHjSGӻ4KJ^˚npDs=(JD Ҡ.qZ=41d(uN9@')e1jUAac+`W4u:zհv6~žutD( 4@ 0'0Hn(6 bg4ILDgFzRP8(30昌z%WX&:҇_ aO|=?TlT2jr3ieu5|RkG`UbS3L-T֩Ȭ:Qg]F``SҨ:F-6(UK&~Z1UnΪML4M9#xڌ߁pS`Ҩ/gf=Xՙx"9P+٧O${C%q0բ: CpA#^h'w)ϥ7s&ZHdkKYXk.j2@C6mvhJjP5(%GSQ(k'Bǻ[N UYY$\V\HZq^UegpSM{ښXny/zJ;U%:%N1I@)C@!ҘS !bLLvL< 22Ok]c/{)2kr-W5w[7e_sXZ0r;wsW«ix<[v0,Ѧ-^k[A>fQxBj"NL±otYd[I_{r V6BQϨ5(GK5ɮGNۥ\`fr9RKˋ6I=pƍFZCf[[c޽JxfZWgIQTWCkBJ 5E@n@Y=#X$V2y$8-<(R.Fƹ&zUWtօ4m>T<+cb S/jSrV8X2I$OٝYQ^@2qZ0hۯUW)nʜ{z0Wv}-:)5#!k57'#hkzi43ȧ +Ռjk[QAdDťTzqst:(}aWlJ}.Fnp+xj飬K6h@Nwxʬ&tHZdKڐ4,u5ڇ(q^]z %;Ùs/qS1?gֱNRMIׂP;qHaMJbޘz4ڠiFbbFM000mDz0!]"N Jl?Lu˄zꍪ !p+/Q5c|Q6W:d*yڹ,uK7O},:QLedz 5 PsvqVޠi1XܹۚUm;ffKd<NjI|~rlp$QcBp5 y&d鞃א]|e\Jg<#ɝKϧ4 ߷v$ CI8Ϊa:qR0q@ 4@'jLC):{gafi1 LS0w >oUuacLԽ |zޡ4[޶|OEFGL=CYVd:kaVY2(2+ d3#:^%lrS#S@P}Yx$. ṛh*z+8䇊*ힴp:^oQW=}-QV75fS5'Ky xrg}yy DH[yI$}:;Kd`6+6Zw;WCF+z=W %W4FR=*YM(+>MB4“va˭D¹y@?5sWIDQ9|DGkNNNI/fl"ZV<N_o -r\M,KP+!P9sIX. O17̌\-]A,^۫Jqٙ[C-ݾ 9^=+'{cr' :$VյjJ$RIBWBnpJ'X;r/\k鿇u@1OGj#C i)ie6L1 2 4Lu'ZaDd U7M5k'mc?TuW}>mt:&@5.k}*j"بu #S|z⩇Sw8CMHb"6gtLd ^q^e-Y^wz*n"wW +mZ&:HO)^ HcC,fWg4t;xB}C1zto>t}-ؒ^U:PpWGkQ~+JTVXs5U Ly^\o 2чq}synjB1^AEyQ;X덥/e[Y#:R<,,E&TTv!=*@I݇LNuR/X9_Dt(gNPhƺɔ\Q>yUmsХP9+I'<354h\.pSYΡ\ _ĞmLl~tι'˄sOl`љ#+¦[C=Z_P|) 1i)CL(4LSOLޔ@ QT!gR[2E~E|`yo_~/_Ʃ_HWn/ gԒ 0 .g2+ +˯~DC1PUg-J0y&彃 ך_xXH`?pk*9=? KHdHe*;;e< W&>g%ˮ5(8&7#I.O%s_: \f+(0S:ƣq:潕SX@1pOVo^bȸSտ juMWAM+ч?kz*kbs)([lDdEk!#K8꠯çfҖ)Ħ(@ LCpiPr)P!L8bhiFx\]/Chk$evȿUuac>;ǭ~q-ϸF=ȵy!!lXyUhS]CZc󭤺+t ͖zjaҸ/f]P7*yu O&cRIe(F[sDK8ފ')ԑ9Ygp }ۄZciMvZqXI5t5O]:3\d-k滫C' H\ws~7cf2n}|L 5'{fVkv;LiU8k89]"1FK/:̚M+DZtbm:ֺ)Qugʂu#s9`J>ws$msV0󯣕8IjUv:BXFهťNv 2' RGKm MZnξZp=2ٗV7m>{9 Zvfc5٥|kg/Aj^ '̜U5oc^,"rn!6iub)ٗ>p;y#!#m#:fp yy''1MJqZ:wB\f,GZ SSzsrE_f6jk"+^TMK,(a}kSSu988_s0R48 pIͿI=XYlj qLKRZnHm$·]j_#"X@l}y[P|X^*=<DM9Dž^;HRzJt/8/KvMg"L=W=2C-A !U~Mo!IW^i)SRszMksqOɔj%, 뜁ⲧi>VAtۺppzr:S7DDavzxN*JV={OlDc1_tb_3`ׅw)9>e+\.#!=+5R}=%3@gϾ2IJdhWoM]Mb[+)MsթEBG͹{'&kb/V?ryOEq&3^mۉdHm@b,Gj eImf_eRci_ ~L';+xGvz]ѨQԱ4$? j)C~kؼ/}3cC iW^I܌m̊',M2NU%y7o g\"DNkέћ4&Y% 3Vxe J3צV*Ȓ59P Ps[vMGn}kѭl&مsa(S]Tl%$pj`A>.yeaH]H\(͔vVGSZ|qi8K#X4NWG|ܩ4FiD+azUqYrJ5zל]XଫkΖXOCd}%ڴc~ls5ۙƲ9` TQҤ>}UuײC|p xUj{i%Ə{Vr3c7$[qSA\U tz#9ORs|}wG6MiKJ:VAI@ F}i)a7nyHLC 7GI+!W㞑=:JWG*1ק?O~]iW\$oti ̭<K`ktx|9\å|mW˺/ʠ B#IjtFj285&Ƥ@i3k5-*7RW_ 2gyI؉n޽RK+X5?ݶa AQI) m|&#q^Fridb MLm34aVC99ƽbZcW/*1ׯ?O9kUvSħ+G bt)k}+-cK\.VCjc?kOBwiڤ L~7nSks|HkyV>UҪ^xGWEȻ/Ss%pPwԱcg |'G= .}u5\bqnH<7A=sS$=(׊]OfojK lקN䴏3l d)-|: @IvI,60z ʚՙMdp2eBױz4ɥAN(DFBc=HKfc);֩h*rޱ^QY>cz2;/V0Sѭvl?rME&t38[6~0]YxtZއXK]W^7w5v!ILg#?J^q1pHE}"8XKwB&G-=~iq),YN~ _R6iĸڮ̹e #R(?5vR=kkr͎טxP{bd}z\:bfT1sgh~!QW}&<޸^{6ŦUm9RJe7Zi 0i82#4SRoYgҾ?Hף_?kD^]/OU~ѫdzU08pzI*M0U܋ #ZUX۳gn> 'IlD<|tT.}rWٝ FKiJ=eW?JgFuZkA֬?5ZKY0W7i#}$3OkIR+)+8I3Xh\4k܍hjvB|ޥ|@#lpkdarƴsWsiR[<{$<~#rDɆA~|d޾n]UN:~Q$jܬIG{m?8WT~=ltdG'^CŤc ۱> @pNV3φ㯭qI1E&qMSu*2OOz▧R97?=Fa6ͷ3[ 0pa^hw <=诣_S_A[ x BN~S#4=ix!lí|~륡ٝ PAo+X65Fq*U8>T'qvfoF}[Yn^ąv5yt*=)R_9m"#)M|훎19c 1[:JZiP!i(@ 5@ M80m0"4 @PE|F!$7*1׿?OaCv요6 fJ%Se$ISW*WD=jA/5W3%dTLw3&Jpl.A3UaSVOrnэ.a0f[fg۝-V_ίٹf`Vhtˎb+̼KIh09\vf߈3sK ?w95o ({zWBwW+!ی&]r־e۱o ^ܖ ^ ZH:4bIHi!y)qM! 2j2h.SjZGd">/V?^81?^AZ'niR0sKD)0{\DeLqN=j<.1Qy'֕AZo}iC T~SzWGڟ2 ښc>s ,2 1ޛޟ2g=i.aآ19Ȩ zP9Db?~=c]u={ .W+#ϯ;njL<i vPAAC{U\w@(j5H0jq!ZěrZ@?CfA%X Z&d(jMYF 㞵L99gԶ3y`VtTklQ5rzsA7=j=EX9nFV85HFlϵh `AcH~}aNIrs&" A޵[(7=sܖ'h'Њ,ZH6GRV15i -xZیc]_i^n29v f -QXni3&M#&Ȥ3eFi">LɨL_k_DG^~%M MH |HSS슐i٠CT!xn)ԁp0z7(lUH=UXWm$8?xK# 1UHB\c&Yr JeXNzg)ǽtЪ=xng"o,c!HSֺ۱Α?7oaYv!GpIH͘ 9S\ #L`sb n{W[mh71=7;'- `A;]m/#:L ,u_Wf2vs@4@3HP Q *"riBqLZa4fj2j$!Jl?Du~7r[`G Pu$v80RP1@y$4D(jpj@L50nqT"\SP"Unj9 \@8)&oPo `U+>A5B+0'<x'HxvʀVV!AvYp1 Dć'֩܋X9>ŹaFHHhƸ xOۥs2['=h;AhL=uD]@¨a'#j8:`:ض]^GKm Q=3LCM&p)i4􅩈43'4LDd7PIɠDYfj"is@ _8":8l~jLYjnf)njJ5 8@ǃR0$N LD۩Ԁ5KD6EP(8%Ƒ1Y4Y#5̭ȯ>Q:S1[P=`qV*f2|WO4  ǥN!b׎պM\`(7#e,Ўޣdsw7K90\ctds.{6t576>mS+סs6J1O֬Z} ԽF_4fM!4ٰ0:b(q@ ϥFM1 )!@曞i{fZb#&Ҁs_?k?DG^~%MԭT_(\v] oJ5P݊\RXN L査Ҁvb$O 8UqS$7r@) smm .`H=1Xd qg94 d{O9Bmр*O>K3*>*t6𷯽n$q@zVGeifN r &rK'{f!;ecKn kT ~؆Tcʁ3?pOҴZ"o*wgOS\Ut:zTm~*Mנ22ԛ7Rga~j-Ĝg ) -MQ@Hi5q@SsSI$5Jγl?Du~7sTC?v+v=۹PdžK3N Hw@ }H O@R.vi(juPO L]jE!Wnug3ֱ&lV55srǽsHr6 Uy@+z\ Eh`[ zLXHe'30_ԁ^9IC 8gJ.+VtlsRHw57ZGmc1Cv1({j;2J祑 ;fJCӦ=N&Z*lqlylnyR$23L-@wqɥza"w @0fiM?FM!7=$41'zŝg?DG^g%M\<3NJ (4isCԙA(cRT;5&*pj6*;}8?4vplPR+fW#y^tQ(fh[N~Vd9RyJr W@G7v=* _lWgAYda.эޜC#>nNm) Rsg֘$RAq9N3/ʠ_OqN z8]!ԷҳkN K yng{0FV ZɎɎuCشsI#I.e^5|y]$z\Ue,;HM=i͊$ MݟZ`&qIZi?0X3M i4GMjCByMP`_DG^g-M95 S0QAAFj@\;41wR 5&i❻=~5P IC$ 6cϥs\n7!jBa1\ԣԺfMk׬1r>OwIs\豛,YlĚQ.TI?.UHU_G>qWN$#ocҝV SWc]c2^=%;bTLwO_AN6Hs3`$TL Tќbٝt͖&. $SJ#fmq̴9'H" zVDM,ex==4%¸'&*صI# OC]l ;NIa5i]D,ZS|W}Ob9I'1"PeG=[r_yO>N0Q7u!l/ 35!c@()AҘ#3wq=餁!3M~77"[ޝIL%WX?&:9jl~o5JZ6x1sOi M,hW(;u4أB-HcwRbP zz8Hڛشϭt0œyGnL-_K|崹s7Z:Q18X׏3DXs֭ڈ11X n$Rp+ԉ  s֧ݸIr#Z<2cV3n s׵_L8zz2$5H1 "Bۃ ^yҹ%fu)_cI|ԞnShk6W * iuG&W/$Tc+ܫ3VѲpjK%){fxRq%3b 3`k"ѳpKb6I)M8ڵ7R>&duYyvr{Wᴧsįp!sY`^U[KUکHp0{);ǭPvE2Jn"h++jWB/nn5zN3]jh`=s2o4mTgs1Q{z0B5|. [4@G5&Ilv#E2ZI+~}O#N]`Z6־%3c !&Ga"Z Eleӷ<ʔL sJycSqإߐ:ێިAs;v:B?š) z`3w_ojn;zd<3__q CV1)^g%M=W҉=ADOzs&T}7jGZ6đ5$=OXœ̷8kyԜt!VHT;׭tp5aF@FĂAP MWRO"# j~5Ka p*XD>R[X~EFg5>` O~H`)sT>p01Z/}zX0s?'9QqZMĞAN@ 4]N)+\#D$&PӷsߥR T%9j؃w]zTL D[i@f=ƿ*+;V#)^~%Mƿ1aSSo[#2=dJ5\2V~u"/žF% YOWDDOdjxV^͌oTON,e8|QfMZVh#43?'=K)!ZksKS[ n:*u{ dDv<`b3dv|W$p5rXU>גم-ֹ,a(iܡ&a}cT@nBG59r5Ez S0Nqې(\~Qӵik3; ւsⰜͣKbu0T,W4kZJB,GE -޷l#MYL ߕu'ԛ_AwT9Xڢrv4.ϯEEp҆=y-,hLRWOq^&ddgU#sZfI?:}D!)A?t#\H\ (ܜv_y=WG5M&Ӭ߭G*_ 3'F>+5!c?V2xDq͢~ވ܈Y~EMGsPq8Շ[/INk4fxSISޔF>ʿge #NV6*ƼQ mOYt`bDZG'z2:nC[JӹEFGr#S dΒz=գPo8v}7mJ!ws#^3FbpzqںH'T{ }hqkC8ɧsnʰ8sǵtE}$cWU ;QyEnxW5du0^]$7>YFLsSv96* evEa"tG#ҰnpTF@0A;$xqR+cVɑaw#~*LqUaJø ɷ8K[k)+'byTnX?CXrKAzʨ'PՋNj&9xuGg,+:vlٮVs\7;r=v_C.DVb03ך> X]b9˰A-4ZD',k/pk=,{VS._1BF s~~sզ6NGqZTJ62mf̌hLW6"'qgFZOt z:q^(FԮZ_z̿5x'HE<E=<:.VMx &tgSaku%u#CSVrI=L3ѽkaǭqeHR!߃NesJaniCI<)˟h(=94{VdqN>VeK6ю+>Flڎ$_铞O;Ǻ-k谩y>T:D# ;QLh=i{s@9 %.꫈ Rdԁ֕?pV "hպʠf|d ԸHXw8K-3g̊iŶnIzzW=NK9S53d1ڸjlQrs^M&Qcz]-´9cOgJݓҷ0XwLޢډir1vY,n>kS<Uwuh/0_3BR- H$ٮ8漕>ŵ%s]Z](b 6e 0FE`ǹ5Rb:kɜ,4z1)FHRxp$_ZXw3Rv5 g۱:^ny49)5p>qoƾ2tWS@ZPg's[4kLxӸbNT&)}iӁOL ~iE1Zx}E_ Z P#8eN֮2+*cf/5*X.SqF$zn^URvܭ<-; {{P;LI6ν RJ6TP&9y]cI4}Y嵂* V~NU%x\pIW=Qͼ3o!0}Wϕsĵ9lhA7i޵-9"&W+ryѥyHMl&`͟^TO9JM:OCf~myUs, c} Duv"kzEc:v+K  k"ЌlgiZǦ4TdR RiɃT@3IPj!UxҰUmE+Y v S)c`Ϟ%>=+ԡ*g7yW۟~4)bjAHcO LCKMԥJ PxƝҁqO?4Ҙ@S  S`4. `ɧFc/R7Ѵr.{ʷ-Fsھ"f`w gWfz Igֱܛ 00STغAy_ҙ\+n"n)Y8 ֩-J .:VzbS3>=h$/@Ry.Gjȥ5df.7T P3ԔV2UVދTi깞zu9{پS|Is^<|G|)̭">UƟ&>=s?RPp&zsN<~sLRS Zx4'tgnCI)Ӄucy WAHzwjp@/4w484h=iݩ(րz\sH2)!8Oza8# 5 ) ǵ4䚲FqE4cҀ"1) +qBXP(HNk[S27>,nҤ;a/;X[絩ԵDQS*V*Z:-ܐkN;ɚk/Y[nX$UsKМ\RLD&⫛X0+XY >i(I2NGz c˔5eZ>燈yַָW֟ UNICODE 8http://ns.adobe.com/xap/1.0/ 1000 C    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222m" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?.r_:fTҚR1-ϠS͐o[Km3}6l>D'YpNjIh$avwk>eV4ҚN*N{a֛zknHXn;]386S*عA[v:44Чl(8VMКwZ׀~WJJJ¤\]: u")h/Z(撠$)1\Ǿ yݮW+h 4bE%!ؤqx<ӻRP! /J4MRb>COW`Uh[:WdG'J8ZYe+i)*6T\li]|7ᶎ ؃&:sW48Ey0#8ϭu\L0f#h^GKgt^핊5: hIsHDYf6EgC1[k"ܚwY}íH$#ӳt+ҕšP15(cWӽjX J2 (zNHe+imc^Q݇7c$HlQ@p*VM[#qI&6a`$5WRp"P;w~ra6[6d7"-9uYW"xՏ5dxZP-v5O7[-Ar{gCzi@qYږqVQVjcFLr\lڏY$翽sUbmNV6UJ]y V|U%A9汧== 3Lwmn3b+ԗ4Zg٢(E%!4JCK&hi3ڊC@M%-&(hULOo,g" ע{5ak AI 6\cY2mte V͵wHp~bEt L?s.+C1[vj;`rάP0?:A΋ƈ1R@;UY+ZӱQ*3iδF* u(}^vg72 O$wk(8aYx{8rO֧HG/g݆&p'{LH2@Ѥe (5\+F9{dBBCeFQpOaގ[OS5`ڣ Uw)hGZv`9&KAչ*ʳl{TBҦJL`ʔ9!es}vU! 8;AFjŬw0N0]D^'&7I8~sݛ('tlӯvH7ѱڳImof~}+yڊ*G*GxWEoKn^GֹOZ=ҹ9=we[͸kj(ruKEpEPIKIڀRZ() %%-&h !i(?JSIp[̸o{ iYj1Zդod,׆Z{]eu0\H= wp-4حFxcU9`=剫;);[+ 0JWDVp=MЀ77`ґhZ,gML Z'FKq*5## Im}]MYXqnTOa/nb;kCćvVx6[2ǽiow.hMtV*{UڵEQu5K"8ϥYHmGVO{ A3uQOLU>cqҴ'ҥ@Rmj XҡRWF- bA*=OZ#Cykxxnj:\^]luh"P=^}IڄZ|Ζ8ˆySkȾq8sB.TQaÃ) U=sA*u).i\>UbVc`.:s"RB;UgQQkkuwp]C)ݐA|a$ aZxl`:tl+՛-ŪGa[ҼTP4&&FnðQ4M!FqVL&\yWMHMt%Gjrc9Pxv7yMѿ}լUVܹv"^e̮yVvKITH\sI@ !N4Ju%!SI@ ғ;7xc>rdjMR20@q]Vw#dp=kxcGK;2YgM')Z9+5. },ԚX[gq dKg;@F>\eJ8Iv(R$ۧ-NqVUz~j*%Q[s*sJ[s#MQ-rE%Ny Oe~cX%bv708u먆Ν[ipB0d,qQV cKniQfRW!,};Q U%O,dlYzLŧv< QHH #\s:Tf@T$Hl4hGNOeko!^=+_vF(#etzYԺQ. 9^GUYn|WWUVvQ1ևm%;b6OfK!c=YTkA#]Z>rkzQ+(XX6gjĺvTur>%f|3M+"\E+p8HAc57I$>nMK;[!}ֽZ5iF:3)#Xw+,N{z޽(9Ng,68g#֭IQpԌjTrDdd HǭhK hA'AL0+ f軕w:W?؛[uPY$=yf]ΈNtRZ2OJ֬- ̧^h񰤢E%%/JJ;M4){PR^E'jCMKAJh~@^R[Y[$%N^<a&sIb#{n5tQc+%Vz5ו}kO F؎fд OR3XgLjQh:~s"~l[h/|UHˎWQ4 pfTga1OcMyd\kZmV]&Ѱ(E},yYe<1v;OaRCoBAj#Ԗ[B7QWʓ帆+~8" &yn^T޶שJ.lM[c W:|I}ckeT\'CNԣI$_Eh}:IsiKĉ'vd$;.J%T 4QؚKh7~ WZu乸&E2{WkiƬc%#<+=h.7%<3*<J좒F2r)p~oSK ּCYL{=VbO'WR1kQ&DrA_ `g{i->C}qXYUI!r }@"ufN+0XYCDs0+e?fBnP}J"\z9kDdr~U@ҩb\)u5z< SFs&lur }e췺\\:y2xV CR AM)nV6n|ֆwɩrk@-a#Jz9b/2GY}:һY ;S֬D\`Mg'hޕs2Oz;y0TV@^ZΈ- 0ɺ^{wKrTF;W/'ҷt8gުQ^&J)-zQE'z %-%IڀMߐc5w}I%V>`! ~7~j 8B=jɛIkj$m LV6.ZHvV=>i6jhVKpOBJ ;HS5cP&\c&T2lٵ!F*KFQ٤&7qLf7u&M;4Ey4&4fހ[4I;?BudjK\;ߚC% N N Epj585;u;540=҆0' N Pn LEf PYFxnc\Ps+BgF) bEiH OS|#av$)~jOB?ʬ*T@*Q{M3jqGb! $ Ӌ~b;[c&1#)x!қ,`\9 rF,;>RdH8YF\n?hQ 1fџ,}h;LӔV^VIBc=sS1a8JϸqeVI#Jj"|ļ"Z۰0!0*]٭oq((aڙzM٥ϽG\!٤$ M3L&4})3ni3@٣u74vsa٢J )AFhCRAu;>R7R>)CTxKtqWcSQvبrW 5,0m]b|oY sKHQۜչdM\ZߕRu(0>w:w|cޡ$L49T8vR5Q]DǕ8>X>b8E `gZy'oιBF+nTmu#`1Q4-8>:'DAj I=*X6􈜁=:Ӛ%^T*JS7my =%;"4 bg##?Z{r .fjϙTc|[ T۽*, ޻Q=6nMD{T{ЇJv:2}j2@!lS7qI?J`I^GLϥH }ԻRK~PF.2PiKT[EĹQ^Q.;ӣW;а$ڋqZE>YgkzPZ)GP!pj1$ Ie >5Фs5bggA[ SsYܸ$6F):@)ڼd+dF9b9Po==))Bke",!$/N"y-߸OSZ\;h~RǵGrZT94]İHvĂ8ݽHCߎ'i]7*@>[!ZX|qNd<z Rv6'}jLC'95ޱ>p\S,uBW7xY篽X^?s7T>g@⬂r- 7ր'IҢ7v*ލm٤KP1IQ@^oIzQ'h9k.o=T=wu [  Ci)RefS*$[ rhrH(>: ԂeTPqҦ"unili)Aҷ,gՁHOiLvQi娹b}ZnUxa57d8ʠGO9դ#8<皅U cAP;qTvCi FGYCc#ڑ<K\b S;N409\O-Qa\pod{S]Oj`K 1L 4c8 tSpd/^$rcju;Fߩh@~U:?-8elVn\wib @~LA`DJ\Ʃ!h$ub9 qsT놐5m:u+63"c#WlZJ$kwzUCqqN8)V&,r9Żxlp>zu9rsFh6{ݞq}g)C¡GsK=hP&rzIt{8:{bãrrm\W}j\|cFLQՁKoXsuZ\T8;8=V,$ay-;%8t"P`u#QEaFhq;VU$șV,h<\Y'"F܃kHi…_ǚ|smdx ۖR"XOg3΃ѱ &ET;\q ;1X2=d`> )\9 HQAlNdʩBjZ;Ɗ.KQ$iUo/Jox$J܎ gxȮhI6gޘW3)R1r7N iIH0 S*N)]J[=(n*3TlM׭j0isOV$ysQԠ:ӸH3Qzp p4ӺZ1IK Ri{m@ ~`ԠQExjLfo.Bѳع<> ?2R7x.4|spܨG(ɜp2ǥR)35x6XVLcDmˌ mi v5JWΉ'TFHG.j[SRG'iEJe OUA[>H]nI"VhfAAVDK&Ak\M[bPI$gB搕"@]puS:۞fiArii\E(4)x4!4dPOjSk)d҇Cȭn]HғԚ1'x홡pclf$30xojA+NICaW=AFs^%n$2yM?۶խ5e̮9y G8bt D8/^kEg$;;YBk0؄(O vp[˩e>rstTg5_ ϔgf`Wc6i ­Yo =:b3ߜGƹ8仂Gb*\Ҥ5Rn:Ɇ\qWz8=LfG98P&&e<<w(sޘa|}*rxM) !>dc-P2cqw mⷥ=&oPje1Tq*xngk"aq`GҵZQJZtRN/BY^*ҵ7=M;n*4KI@M 2&H5Qd=+NT7Z\2ltUBAK:`E.qQNlsg=hqL9ffKh4f ;54(4fϭ 4`QvZ4)7R@綎eF}qYToVv+iꚼ@[Atb@DC>lq TmmuZQΕKIm#t,Һ-VpYxyXק e=Jʺtzʜ+4 ,uH)'޺k[u)F"@\"!+@&+&.+G(:fp)@' (ji&ϸ?yAHXr6,tSS vO}=WUa*̧ދ>VlS J*r*tM??ޓގcEcSޓ X5*Xi 0 { fmt.Printf("Unexpected arguments: %s\nUse --help to view available options.", args) os.Exit(1) } // default ImportPath to pwd when not set if len(flags.ImportPaths) == 0 { pwd, err := os.Getwd() if err != nil { fmt.Printf("error getting pwd: %s\n", err) os.Exit(1) } verbosef("using pwd as import path\n") // find non-absolute path for this pwd pkg, err := build.ImportDir(pwd, build.FindOnly) if err != nil { fmt.Printf("error using current directory as import path: %s\n", err) os.Exit(1) } flags.ImportPaths = append(flags.ImportPaths, pkg.ImportPath) verbosef("using import paths: %s\n", flags.ImportPaths) return } } go.rice-1.0.2/rice/helpers_test.go000066400000000000000000000416131376637333000170320ustar00rootroot00000000000000package main import ( "fmt" "go/ast" "go/build" "go/parser" "go/token" "io" "io/ioutil" "os" "path" "path/filepath" "strconv" "strings" "testing" ) type sourceFile struct { Name string Contents []byte } 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 } 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 } // 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 validateBoxFile(t *testing.T, filename string, src io.Reader, sourceFiles []sourceFile) { fset := token.NewFileSet() f, err := parser.ParseFile(fset, filename, src, 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) } } 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 } } } } go.rice-1.0.2/rice/identifier.go000066400000000000000000000004021376637333000164420ustar00rootroot00000000000000package main import ( "strconv" "github.com/GeertJohan/go.incremental" ) var identifierCount incremental.Uint64 func nextIdentifier() string { num := identifierCount.Next() return strconv.FormatUint(num, 36) // 0123456789abcdefghijklmnopqrstuvwxyz } go.rice-1.0.2/rice/main.go000066400000000000000000000033561376637333000152570ustar00rootroot00000000000000package main import ( "fmt" "go/build" "log" "os" "runtime/pprof" ) func main() { // parser arguments parseArguments() if flags.CpuProfile != "" { f, err := os.Create(flags.CpuProfile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } // find package for path var pkgs []*build.Package for _, importPath := range flags.ImportPaths { pkg := pkgForPath(importPath) pkg.AllTags = flags.Tags pkgs = append(pkgs, pkg) } // switch on the operation to perform switch flagsParser.Active.Name { case "embed", "embed-go": for _, pkg := range pkgs { operationEmbedGo(pkg) } case "embed-syso": log.Println("WARNING: embedding .syso is experimental..") log.Fatalln("FATAL: embed-syso is broken and will remain unusable until further notice. Please see https://github.com/GeertJohan/go.rice/issues/162") case "append": operationAppend(pkgs) case "clean": for _, pkg := range pkgs { operationClean(pkg) } } // all done verbosef("\n") verbosef("rice finished successfully\n") if flags.MemProfile != "" { f, err := os.Create(flags.MemProfile) if err != nil { log.Fatal(err) } pprof.WriteHeapProfile(f) f.Close() } } // helper function to get *build.Package for given path func pkgForPath(path string) *build.Package { // get pwd for relative imports pwd, err := os.Getwd() if err != nil { fmt.Printf("error getting pwd (required for relative imports): %s\n", err) os.Exit(1) } // read full package information pkg, err := build.Import(path, pwd, 0) if err != nil { fmt.Printf("error reading package: %s\n", err) os.Exit(1) } return pkg } func verbosef(format string, stuff ...interface{}) { if flags.Verbose { log.Printf(format, stuff...) } } go.rice-1.0.2/rice/templates.go000066400000000000000000000103711376637333000163240ustar00rootroot00000000000000package main import ( "fmt" "io" "os" "strconv" "strings" "text/template" "github.com/nkovacs/streamquote" "github.com/valyala/fasttemplate" ) var ( tmplEmbeddedBox *template.Template tagEscaper, tagUnescaper *strings.Replacer ) const ( unescapeTag = "unescape:" injectTag = "injectfile:" ) func init() { var err error // $ is used as the escaping character, // because it has no special meaning in go strings, // so it won't be changed by strconv.Quote. replacements := []string{"$", "$$", "{%", "{$%", "%}", "%$}"} reverseReplacements := make([]string, len(replacements)) l := len(reverseReplacements) - 1 for i := range replacements { reverseReplacements[l-i] = replacements[i] } tagEscaper = strings.NewReplacer(replacements...) tagUnescaper = strings.NewReplacer(reverseReplacements...) // parse embedded box template tmplEmbeddedBox, err = template.New("embeddedBox").Funcs(template.FuncMap{ "tagescape": func(s string) string { return fmt.Sprintf("{%%%v%v%%}", unescapeTag, tagEscaper.Replace(s)) }, "injectfile": func(s string) string { return fmt.Sprintf("{%%%v%v%%}", injectTag, tagEscaper.Replace(s)) }, }).Parse(`package {{.Package}} import ( "time" "github.com/GeertJohan/go.rice/embedded" ) {{range .Boxes}} func init() { // define files {{range .Files}}{{.Identifier}} := &embedded.EmbeddedFile{ Filename: {{.FileName | tagescape | printf "%q"}}, FileModTime: time.Unix({{.ModTime}}, 0), Content: string({{.Path | injectfile | printf "%q"}}), } {{end}} // define dirs {{range .Dirs}}{{.Identifier}} := &embedded.EmbeddedDir{ Filename: {{.FileName | tagescape | printf "%q"}}, DirModTime: time.Unix({{.ModTime}}, 0), ChildFiles: []*embedded.EmbeddedFile{ {{range .ChildFiles}}{{.Identifier}}, // {{.FileName | tagescape | printf "%q"}} {{end}} }, } {{end}} // link ChildDirs {{range .Dirs}}{{.Identifier}}.ChildDirs = []*embedded.EmbeddedDir{ {{range .ChildDirs}}{{.Identifier}}, // {{.FileName | tagescape | printf "%q"}} {{end}} } {{end}} // register embeddedBox embedded.RegisterEmbeddedBox(` + "`" + `{{.BoxName}}` + "`" + `, &embedded.EmbeddedBox{ Name: ` + "`" + `{{.BoxName}}` + "`" + `, Time: time.Unix({{.UnixNow}}, 0), Dirs: map[string]*embedded.EmbeddedDir{ {{range .Dirs}}{{.FileName | tagescape | printf "%q"}}: {{.Identifier}}, {{end}} }, Files: map[string]*embedded.EmbeddedFile{ {{range .Files}}{{.FileName | tagescape | printf "%q"}}: {{.Identifier}}, {{end}} }, }) } {{end}}`) if err != nil { fmt.Printf("error parsing embedded box template: %s\n", err) os.Exit(-1) } } // embeddedBoxFasttemplate will inject file contents and unescape {% and %}. func embeddedBoxFasttemplate(w io.Writer, src string) error { ft, err := fasttemplate.NewTemplate(src, "{%", "%}") if err != nil { return fmt.Errorf("error compiling fasttemplate: %s\n", err) } converter := streamquote.New() _, err = ft.ExecuteFunc(w, func(w io.Writer, tag string) (int, error) { if strings.HasPrefix(tag, unescapeTag) { tag = strings.TrimPrefix(tag, unescapeTag) return w.Write([]byte(tagUnescaper.Replace(tag))) } if !strings.HasPrefix(tag, injectTag) { return 0, fmt.Errorf("invalid fasttemplate tag: %v", tag) } tag = strings.TrimPrefix(tag, injectTag) fileName, err := strconv.Unquote("\"" + tag + "\"") if err != nil { return 0, fmt.Errorf("error unquoting filename %v: %v\n", tag, err) } f, err := os.Open(tagUnescaper.Replace(fileName)) if err != nil { return 0, fmt.Errorf("error opening file %v: %v\n", fileName, err) } n, err := converter.Convert(f, w) f.Close() if err != nil { return n, fmt.Errorf("error converting file %v: %v\n", fileName, err) } return n, nil }) if err != nil { return fmt.Errorf("error executing fasttemplate: %s\n", err) } return nil } type embedFileDataType struct { Package string Boxes []*boxDataType } type boxDataType struct { BoxName string UnixNow int64 Files []*fileDataType Dirs map[string]*dirDataType } type fileDataType struct { Identifier string FileName string Path string ModTime int64 } type dirDataType struct { Identifier string FileName string Content []byte ModTime int64 ChildDirs []*dirDataType ChildFiles []*fileDataType } go.rice-1.0.2/rice/util.go000066400000000000000000000013211376637333000152760ustar00rootroot00000000000000package main import ( "math/rand" "path/filepath" "strings" "time" ) // generated tests if a filename was generated by rice func generated(filename string) bool { return filepath.Base(filename) == boxFilename || strings.HasSuffix(filename, "."+boxFilename) } // randomString generates a pseudo-random alpha-numeric string with given length. func randomString(length int) string { rand.Seed(time.Now().UnixNano()) k := make([]rune, length) for i := 0; i < length; i++ { c := rand.Intn(35) if c < 10 { c += 48 // numbers (0-9) (0+48 == 48 == '0', 9+48 == 57 == '9') } else { c += 87 // lower case alphabets (a-z) (10+87 == 97 == 'a', 35+87 == 122 = 'z') } k[i] = rune(c) } return string(k) } go.rice-1.0.2/rice/writecoff.go000066400000000000000000000015121376637333000163130ustar00rootroot00000000000000package main import ( "fmt" "os" "reflect" "github.com/akavel/rsrc/binutil" "github.com/akavel/rsrc/coff" ) // copied from github.com/akavel/rsrc // LICENSE: MIT // Copyright 2013-2014 The rsrc Authors. (https://github.com/akavel/rsrc/blob/master/AUTHORS) func writeCoff(coff *coff.Coff, fnameout string) error { out, err := os.Create(fnameout) if err != nil { return err } defer out.Close() w := binutil.Writer{W: out} // write the resulting file to disk binutil.Walk(coff, func(v reflect.Value, path string) error { if binutil.Plain(v.Kind()) { w.WriteLE(v.Interface()) return nil } vv, ok := v.Interface().(binutil.SizedReader) if ok { w.WriteFromSized(vv) return binutil.WALK_SKIP } return nil }) if w.Err != nil { return fmt.Errorf("Error writing output file: %s", w.Err) } return nil } go.rice-1.0.2/sort.go000066400000000000000000000014271376637333000143750ustar00rootroot00000000000000package rice import "os" // SortByName allows an array of os.FileInfo objects // to be easily sorted by filename using sort.Sort(SortByName(array)) type SortByName []os.FileInfo func (f SortByName) Len() int { return len(f) } func (f SortByName) Less(i, j int) bool { return f[i].Name() < f[j].Name() } func (f SortByName) Swap(i, j int) { f[i], f[j] = f[j], f[i] } // SortByModified allows an array of os.FileInfo objects // to be easily sorted by modified date using sort.Sort(SortByModified(array)) type SortByModified []os.FileInfo func (f SortByModified) Len() int { return len(f) } func (f SortByModified) Less(i, j int) bool { return f[i].ModTime().Unix() > f[j].ModTime().Unix() } func (f SortByModified) Swap(i, j int) { f[i], f[j] = f[j], f[i] } go.rice-1.0.2/virtual.go000066400000000000000000000156111376637333000150740ustar00rootroot00000000000000package rice import ( "errors" "io" "os" "path/filepath" "sort" "github.com/GeertJohan/go.rice/embedded" ) //++ TODO: IDEA: merge virtualFile and virtualDir, this decreases work done by rice.File // virtualFile is a 'stateful' virtual file. // virtualFile wraps an *EmbeddedFile for a call to Box.Open() and virtualizes 'read cursor' (offset) and 'closing'. // virtualFile is only internally visible and should be exposed through rice.File type virtualFile struct { *embedded.EmbeddedFile // the actual embedded file, embedded to obtain methods offset int64 // read position on the virtual file closed bool // closed when true } // create a new virtualFile for given EmbeddedFile func newVirtualFile(ef *embedded.EmbeddedFile) *virtualFile { vf := &virtualFile{ EmbeddedFile: ef, offset: 0, closed: false, } return vf } //++ TODO check for nil pointers in all these methods. When so: return os.PathError with Err: os.ErrInvalid func (vf *virtualFile) close() error { if vf.closed { return &os.PathError{ Op: "close", Path: vf.EmbeddedFile.Filename, Err: errors.New("already closed"), } } vf.EmbeddedFile = nil vf.closed = true return nil } func (vf *virtualFile) stat() (os.FileInfo, error) { if vf.closed { return nil, &os.PathError{ Op: "stat", Path: vf.EmbeddedFile.Filename, Err: errors.New("bad file descriptor"), } } return (*embeddedFileInfo)(vf.EmbeddedFile), nil } func (vf *virtualFile) readdir(count int) ([]os.FileInfo, error) { if vf.closed { return nil, &os.PathError{ Op: "readdir", Path: vf.EmbeddedFile.Filename, Err: errors.New("bad file descriptor"), } } return nil, os.ErrInvalid } func (vf *virtualFile) readdirnames(count int) ([]string, error) { if vf.closed { return nil, &os.PathError{ Op: "readdirnames", Path: vf.EmbeddedFile.Filename, Err: errors.New("bad file descriptor"), } } return nil, os.ErrInvalid } func (vf *virtualFile) read(bts []byte) (int, error) { if vf.closed { return 0, &os.PathError{ Op: "read", Path: vf.EmbeddedFile.Filename, Err: errors.New("bad file descriptor"), } } end := vf.offset + int64(len(bts)) if end >= int64(len(vf.Content)) { // end of file, so return what we have + EOF n := copy(bts, vf.Content[vf.offset:]) vf.offset = 0 return n, io.EOF } n := copy(bts, vf.Content[vf.offset:end]) vf.offset += int64(n) return n, nil } func (vf *virtualFile) seek(offset int64, whence int) (int64, error) { if vf.closed { return 0, &os.PathError{ Op: "seek", Path: vf.EmbeddedFile.Filename, Err: errors.New("bad file descriptor"), } } var e error //++ TODO: check if this is correct implementation for seek switch whence { case os.SEEK_SET: //++ check if new offset isn't out of bounds, set e when it is, then break out of switch vf.offset = offset case os.SEEK_CUR: //++ check if new offset isn't out of bounds, set e when it is, then break out of switch vf.offset += offset case os.SEEK_END: //++ check if new offset isn't out of bounds, set e when it is, then break out of switch vf.offset = int64(len(vf.EmbeddedFile.Content)) - offset } if e != nil { return 0, &os.PathError{ Op: "seek", Path: vf.Filename, Err: e, } } return vf.offset, nil } // virtualDir is a 'stateful' virtual directory. // virtualDir wraps an *EmbeddedDir for a call to Box.Open() and virtualizes 'closing'. // virtualDir is only internally visible and should be exposed through rice.File type virtualDir struct { *embedded.EmbeddedDir offset int // readdir position on the directory closed bool } // create a new virtualDir for given EmbeddedDir func newVirtualDir(ed *embedded.EmbeddedDir) *virtualDir { vd := &virtualDir{ EmbeddedDir: ed, offset: 0, closed: false, } return vd } func (vd *virtualDir) close() error { //++ TODO: needs sync mutex? if vd.closed { return &os.PathError{ Op: "close", Path: vd.EmbeddedDir.Filename, Err: errors.New("already closed"), } } vd.closed = true return nil } func (vd *virtualDir) stat() (os.FileInfo, error) { if vd.closed { return nil, &os.PathError{ Op: "stat", Path: vd.EmbeddedDir.Filename, Err: errors.New("bad file descriptor"), } } return (*embeddedDirInfo)(vd.EmbeddedDir), nil } func (vd *virtualDir) readdir(n int) ([]os.FileInfo, error) { if vd.closed { return nil, &os.PathError{ Op: "readdir", Path: vd.EmbeddedDir.Filename, Err: errors.New("bad file descriptor"), } } // Build up the array of our contents var files []os.FileInfo // Add the child directories for _, child := range vd.ChildDirs { child.Filename = filepath.Base(child.Filename) files = append(files, (*embeddedDirInfo)(child)) } // Add the child files for _, child := range vd.ChildFiles { child.Filename = filepath.Base(child.Filename) files = append(files, (*embeddedFileInfo)(child)) } // Sort it by filename (lexical order) sort.Sort(SortByName(files)) // Return all contents if that's what is requested if n <= 0 { vd.offset = 0 return files, nil } // If user has requested past the end of our list // return what we can and send an EOF if vd.offset+n >= len(files) { offset := vd.offset vd.offset = 0 return files[offset:], io.EOF } offset := vd.offset vd.offset += n return files[offset : offset+n], nil } func (vd *virtualDir) readdirnames(n int) ([]string, error) { if vd.closed { return nil, &os.PathError{ Op: "readdir", Path: vd.EmbeddedDir.Filename, Err: errors.New("bad file descriptor"), } } // Build up the array of our contents var files []string // Add the child directories for _, child := range vd.ChildDirs { files = append(files, filepath.Base(child.Filename)) } // Add the child files for _, child := range vd.ChildFiles { files = append(files, filepath.Base(child.Filename)) } // Sort it by filename (lexical order) sort.Strings(files) // Return all contents if that's what is requested if n <= 0 { vd.offset = 0 return files, nil } // If user has requested past the end of our list // return what we can and send an EOF if vd.offset+n >= len(files) { offset := vd.offset vd.offset = 0 return files[offset:], io.EOF } offset := vd.offset vd.offset += n return files[offset : offset+n], nil } func (vd *virtualDir) read(bts []byte) (int, error) { if vd.closed { return 0, &os.PathError{ Op: "read", Path: vd.EmbeddedDir.Filename, Err: errors.New("bad file descriptor"), } } return 0, &os.PathError{ Op: "read", Path: vd.EmbeddedDir.Filename, Err: errors.New("is a directory"), } } func (vd *virtualDir) seek(offset int64, whence int) (int64, error) { if vd.closed { return 0, &os.PathError{ Op: "seek", Path: vd.EmbeddedDir.Filename, Err: errors.New("bad file descriptor"), } } return 0, &os.PathError{ Op: "seek", Path: vd.Filename, Err: errors.New("is a directory"), } } go.rice-1.0.2/walk.go000066400000000000000000000045461376637333000143510ustar00rootroot00000000000000package rice import ( "os" "path/filepath" "sort" "strings" ) // Walk is like filepath.Walk() // Visit http://golang.org/pkg/path/filepath/#Walk for more information func (b *Box) Walk(path string, walkFn filepath.WalkFunc) error { pathFile, err := b.Open(path) if err != nil { return err } defer pathFile.Close() pathInfo, err := pathFile.Stat() if err != nil { return err } if b.IsAppended() || b.IsEmbedded() { return b.walk(path, pathInfo, walkFn) } // We don't have any embedded or appended box so use live filesystem mode return filepath.Walk(filepath.Join(b.absolutePath, path), func(path string, info os.FileInfo, err error) error { // Strip out the box name from the returned paths path = strings.TrimPrefix(path, b.absolutePath+string(os.PathSeparator)) return walkFn(path, info, err) }) } // walk recursively descends path. // See walk() in $GOROOT/src/pkg/path/filepath/path.go func (b *Box) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { err := walkFn(path, info, nil) if err != nil { if info.IsDir() && err == filepath.SkipDir { return nil } return err } if !info.IsDir() { return nil } names, err := b.readDirNames(path) if err != nil { return walkFn(path, info, err) } for _, name := range names { filename := filepath.ToSlash(filepath.Join(path, name)) fileObject, err := b.Open(filename) if err != nil { return err } defer fileObject.Close() fileInfo, err := fileObject.Stat() if err != nil { if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { return err } } else { err = b.walk(filename, fileInfo, walkFn) if err != nil { if !fileInfo.IsDir() || err != filepath.SkipDir { return err } } } } return nil } // readDirNames reads the directory named by path and returns a sorted list of directory entries. // See readDirNames() in $GOROOT/pkg/path/filepath/path.go func (b *Box) readDirNames(path string) ([]string, error) { f, err := b.Open(path) if err != nil { return nil, err } defer f.Close() stat, err := f.Stat() if err != nil { return nil, err } if !stat.IsDir() { return nil, nil } infos, err := f.Readdir(0) if err != nil { return nil, err } var names []string for _, info := range infos { names = append(names, info.Name()) } sort.Strings(names) return names, nil }