| // This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication |
| // license. Its contents can be found at: |
| // http://creativecommons.org/publicdomain/zero/1.0/ |
| |
| package bindata |
| |
| import ( |
| "fmt" |
| "os" |
| "path/filepath" |
| "regexp" |
| ) |
| |
| // InputConfig defines options on a asset directory to be convert. |
| type InputConfig struct { |
| // Path defines a directory containing asset files to be included |
| // in the generated output. |
| Path string |
| |
| // Recusive defines whether subdirectories of Path |
| // should be recursively included in the conversion. |
| Recursive bool |
| } |
| |
| // Config defines a set of options for the asset conversion. |
| type Config struct { |
| // Name of the package to use. Defaults to 'main'. |
| Package string |
| |
| // Tags specify a set of optional build tags, which should be |
| // included in the generated output. The tags are appended to a |
| // `// +build` line in the beginning of the output file |
| // and must follow the build tags syntax specified by the go tool. |
| Tags string |
| |
| // Input defines the directory path, containing all asset files as |
| // well as whether to recursively process assets in any sub directories. |
| Input []InputConfig |
| |
| // Output defines the output file for the generated code. |
| // If left empty, this defaults to 'bindata.go' in the current |
| // working directory. |
| Output string |
| |
| // Prefix defines a path prefix which should be stripped from all |
| // file names when generating the keys in the table of contents. |
| // For example, running without the `-prefix` flag, we get: |
| // |
| // $ go-bindata /path/to/templates |
| // go_bindata["/path/to/templates/foo.html"] = _path_to_templates_foo_html |
| // |
| // Running with the `-prefix` flag, we get: |
| // |
| // $ go-bindata -prefix "/path/to/" /path/to/templates/foo.html |
| // go_bindata["templates/foo.html"] = templates_foo_html |
| Prefix string |
| |
| // NoMemCopy will alter the way the output file is generated. |
| // |
| // It will employ a hack that allows us to read the file data directly from |
| // the compiled program's `.rodata` section. This ensures that when we call |
| // call our generated function, we omit unnecessary mem copies. |
| // |
| // The downside of this, is that it requires dependencies on the `reflect` and |
| // `unsafe` packages. These may be restricted on platforms like AppEngine and |
| // thus prevent you from using this mode. |
| // |
| // Another disadvantage is that the byte slice we create, is strictly read-only. |
| // For most use-cases this is not a problem, but if you ever try to alter the |
| // returned byte slice, a runtime panic is thrown. Use this mode only on target |
| // platforms where memory constraints are an issue. |
| // |
| // The default behaviour is to use the old code generation method. This |
| // prevents the two previously mentioned issues, but will employ at least one |
| // extra memcopy and thus increase memory requirements. |
| // |
| // For instance, consider the following two examples: |
| // |
| // This would be the default mode, using an extra memcopy but gives a safe |
| // implementation without dependencies on `reflect` and `unsafe`: |
| // |
| // func myfile() []byte { |
| // return []byte{0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a} |
| // } |
| // |
| // Here is the same functionality, but uses the `.rodata` hack. |
| // The byte slice returned from this example can not be written to without |
| // generating a runtime error. |
| // |
| // var _myfile = "\x89\x50\x4e\x47\x0d\x0a\x1a" |
| // |
| // func myfile() []byte { |
| // var empty [0]byte |
| // sx := (*reflect.StringHeader)(unsafe.Pointer(&_myfile)) |
| // b := empty[:] |
| // bx := (*reflect.SliceHeader)(unsafe.Pointer(&b)) |
| // bx.Data = sx.Data |
| // bx.Len = len(_myfile) |
| // bx.Cap = bx.Len |
| // return b |
| // } |
| NoMemCopy bool |
| |
| // NoCompress means the assets are /not/ GZIP compressed before being turned |
| // into Go code. The generated function will automatically unzip |
| // the file data when called. Defaults to false. |
| NoCompress bool |
| |
| // Perform a debug build. This generates an asset file, which |
| // loads the asset contents directly from disk at their original |
| // location, instead of embedding the contents in the code. |
| // |
| // This is mostly useful if you anticipate that the assets are |
| // going to change during your development cycle. You will always |
| // want your code to access the latest version of the asset. |
| // Only in release mode, will the assets actually be embedded |
| // in the code. The default behaviour is Release mode. |
| Debug bool |
| |
| // Perform a dev build, which is nearly identical to the debug option. The |
| // only difference is that instead of absolute file paths in generated code, |
| // it expects a variable, `rootDir`, to be set in the generated code's |
| // package (the author needs to do this manually), which it then prepends to |
| // an asset's name to construct the file path on disk. |
| // |
| // This is mainly so you can push the generated code file to a shared |
| // repository. |
| Dev bool |
| |
| // When true, size, mode and modtime are not preserved from files |
| NoMetadata bool |
| // When nonzero, use this as mode for all files. |
| Mode uint |
| // When nonzero, use this as unix timestamp for all files. |
| ModTime int64 |
| |
| // Ignores any filenames matching the regex pattern specified, e.g. |
| // path/to/file.ext will ignore only that file, or \\.gitignore |
| // will match any .gitignore file. |
| // |
| // This parameter can be provided multiple times. |
| Ignore []*regexp.Regexp |
| } |
| |
| // NewConfig returns a default configuration struct. |
| func NewConfig() *Config { |
| c := new(Config) |
| c.Package = "main" |
| c.NoMemCopy = false |
| c.NoCompress = false |
| c.Debug = false |
| c.Output = "./bindata.go" |
| c.Ignore = make([]*regexp.Regexp, 0) |
| return c |
| } |
| |
| // validate ensures the config has sane values. |
| // Part of which means checking if certain file/directory paths exist. |
| func (c *Config) validate() error { |
| if len(c.Package) == 0 { |
| return fmt.Errorf("Missing package name") |
| } |
| |
| for _, input := range c.Input { |
| _, err := os.Lstat(input.Path) |
| if err != nil { |
| return fmt.Errorf("Failed to stat input path '%s': %v", input.Path, err) |
| } |
| } |
| |
| if len(c.Output) == 0 { |
| cwd, err := os.Getwd() |
| if err != nil { |
| return fmt.Errorf("Unable to determine current working directory.") |
| } |
| |
| c.Output = filepath.Join(cwd, "bindata.go") |
| } |
| |
| stat, err := os.Lstat(c.Output) |
| if err != nil { |
| if !os.IsNotExist(err) { |
| return fmt.Errorf("Output path: %v", err) |
| } |
| |
| // File does not exist. This is fine, just make |
| // sure the directory it is to be in exists. |
| dir, _ := filepath.Split(c.Output) |
| if dir != "" { |
| err = os.MkdirAll(dir, 0744) |
| |
| if err != nil { |
| return fmt.Errorf("Create output directory: %v", err) |
| } |
| } |
| } |
| |
| if stat != nil && stat.IsDir() { |
| return fmt.Errorf("Output path is a directory.") |
| } |
| |
| return nil |
| } |