diff --git a/asset.go b/asset.go
new file mode 100644
index 0000000..6f9e50d
--- /dev/null
+++ b/asset.go
@@ -0,0 +1,12 @@
+// 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
+
+// File is an asset entry for the table of contents.
+type Asset struct {
+ Path string // Full file path.
+ Name string // Key used in TOC -- name by which asset is referenced.
+ Func string // Function name for the procedure returning the asset contents.
+}
diff --git a/bytewriter.go b/bytewriter.go
new file mode 100644
index 0000000..c9b602c
--- /dev/null
+++ b/bytewriter.go
@@ -0,0 +1,37 @@
+// 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"
+ "io"
+)
+
+var newline = []byte{'\n'}
+
+type ByteWriter struct {
+ io.Writer
+ c int
+}
+
+func (w *ByteWriter) Write(p []byte) (n int, err error) {
+ if len(p) == 0 {
+ return
+ }
+
+ for n = range p {
+ if w.c%12 == 0 {
+ w.Writer.Write(newline)
+ w.c = 0
+ }
+
+ fmt.Fprintf(w.Writer, "0x%02x,", p[n])
+ w.c++
+ }
+
+ n++
+
+ return
+}
diff --git a/config.go b/config.go
index c9d7f96..e27a860 100644
--- a/config.go
+++ b/config.go
@@ -6,11 +6,14 @@ package bindata
// 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
+ Tags string
// Input defines the directory path, containing all asset files.
// This may contain sub directories, which will be included in the
@@ -86,7 +89,16 @@ type Config struct {
/*
Compress means the assets are GZIP compressed before being turned
into Go code. The generated function will automatically unzip
- the file data when called.
+ the file data when called. Defaults to true.
*/
Compress bool
}
+
+// NewConfig returns a default configuration struct.
+func NewConfig() *Config {
+ c := new(Config)
+ c.Package = "main"
+ c.NoMemCopy = false
+ c.Compress = true
+ return c
+}
diff --git a/convert.go b/convert.go
index 757add6..7f77ddc 100644
--- a/convert.go
+++ b/convert.go
@@ -27,32 +27,67 @@ type ProgressFunc func(file string, current, total int) bool
// to Go code and writes new files to the output directory specified
// in the given configuration.
func Translate(c *Config, pf ProgressFunc) error {
- toc := make(map[string]string)
- err := findFiles(c.Input, c.Prefix, toc)
+ var toc []Asset
+ err := findFiles(c.Input, c.Prefix, &toc)
if err != nil {
return err
}
+ // Open output files.
+ debug, release, err := openOutput(c.Output)
+ if err != nil {
+ return err
+ }
+
+ defer func() {
+ debug.Close()
+ release.Close()
+ }()
+
+ // Prepare files -- write package header and build tags.
+ writeDebugHeader(debug, c)
+ writeReleaseHeader(release, c)
+
+ // Convert assets and write them to the output files.
var current int
- for key, value := range toc {
+ for i := range toc {
if pf != nil {
current++
- if pf(key, current, len(toc)) {
+ if pf(toc[i].Path, current, len(toc)) {
return nil
}
}
- _ = value
+ writeDebug(debug, c, &toc[i])
+ writeRelease(release, c, &toc[i])
}
+ // Generate TOC file.
return nil
}
+// openOutput opens two output files. One for debug code and
+// one for release code.
+func openOutput(dir string) (*os.File, *os.File, error) {
+ debug, err := os.Create(filepath.Join(dir, "bindata_debug.go"))
+ if err != nil {
+ return nil, nil, err
+ }
+
+ release, err := os.Create(filepath.Join(dir, "bindata_release.go"))
+ if err != nil {
+ debug.Close()
+ return nil, nil, err
+ }
+
+ return debug, release, nil
+}
+
// fillTOC recursively finds all the file paths in the given directory tree.
// They are added to the given map as keys. Values will be safe function names
// for each file, which will be used when generating the output code.
-func findFiles(dir, prefix string, toc map[string]string) error {
+func findFiles(dir, prefix string, toc *[]Asset) error {
if len(prefix) > 0 {
dir, _ = filepath.Abs(dir)
prefix, _ = filepath.Abs(prefix)
@@ -71,28 +106,32 @@ func findFiles(dir, prefix string, toc map[string]string) error {
}
for _, file := range list {
- key := filepath.Join(dir, file.Name())
+ var asset Asset
+ asset.Path = filepath.Join(dir, file.Name())
+ asset.Name = asset.Path
if file.IsDir() {
- findFiles(key, prefix, toc)
- } else {
- if strings.HasPrefix(key, prefix) {
- key = key[len(prefix):]
- }
-
- // If we have a leading slash, get rid of it.
- if len(key) > 0 && key[0] == '/' {
- key = key[1:]
- }
-
- // This shouldn't happen.
- if len(key) == 0 {
- return fmt.Errorf("Invalid file: %v", filepath.Join(dir, file.Name()))
- }
-
- value := safeFunctionName(key)
- toc[key] = value
+ findFiles(asset.Path, prefix, toc)
+ continue
}
+
+ if strings.HasPrefix(asset.Name, prefix) {
+ asset.Name = asset.Name[len(prefix):]
+ }
+
+ // If we have a leading slash, get rid of it.
+ if len(asset.Name) > 0 && asset.Name[0] == '/' {
+ asset.Name = asset.Name[1:]
+ }
+
+ // This shouldn't happen.
+ if len(asset.Name) == 0 {
+ return fmt.Errorf("Invalid file: %v", asset.Path)
+ }
+
+ asset.Func = safeFunctionName(asset.Name)
+ asset.Path, _ = filepath.Abs(asset.Path)
+ *toc = append(*toc, asset)
}
return nil
@@ -106,15 +145,20 @@ func safeFunctionName(name string) string {
name = strings.ToLower(name)
name = regFuncName.ReplaceAllString(name, "_")
- // Identifier can't start with a digit.
- if unicode.IsDigit(rune(name[0])) {
- name = "_" + name
- }
-
// Get rid of "__" instances for niceness.
for strings.Index(name, "__") > -1 {
name = strings.Replace(name, "__", "_", -1)
}
+ // Leading underscores are silly (unless they prefix a digit (see below)).
+ for len(name) > 1 && name[0] == '_' {
+ name = name[1:]
+ }
+
+ // Identifier can't start with a digit.
+ if unicode.IsDigit(rune(name[0])) {
+ name = "_" + name
+ }
+
return name
}
diff --git a/debug.go b/debug.go
new file mode 100644
index 0000000..0b70c8a
--- /dev/null
+++ b/debug.go
@@ -0,0 +1,69 @@
+// 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"
+ "io"
+)
+
+// writeDebugHeader writes output file headers with the given build tags.
+// This targets debug builds.
+func writeDebugHeader(w io.Writer, c *Config) {
+ // Write build tags, if applicable.
+ if len(c.Tags) > 0 {
+ fmt.Fprintf(w, "// +build !release %s\n\n", c.Tags)
+ } else {
+ fmt.Fprintf(w, "// +build !release\n\n")
+ }
+
+ // Write package declaration
+ fmt.Fprintf(w, "package %s\n\n", c.Package)
+
+ // Define packages we need to import.
+ // And add the asset_read function. This is called
+ // from asset-specific functions.
+ fmt.Fprintf(w, `import (
+ "bytes"
+ "io"
+ "log"
+ "os"
+)
+
+// bindata_read reads the given file from disk.
+// It panics if anything went wrong.
+func bindata_read(path, name string) []byte {
+ fd, err := os.Open(path)
+ if err != nil {
+ log.Fatalf("Read %%s: %%v", name, err)
+ }
+
+ defer fd.Close()
+
+ var buf bytes.Buffer
+ _, err = io.Copy(&buf, fd)
+ if err != nil {
+ log.Fatalf("Read %%s: %%v", name, err)
+ }
+
+ return buf.Bytes()
+}
+
+`)
+}
+
+// writeDebug write a debug entry for the given asset.
+// A debug entry is simply a function which reads the asset from
+// the original file (e.g.: from disk).
+func writeDebug(w io.Writer, c *Config, asset *Asset) {
+ fmt.Fprintf(w, `func %s() []byte {
+ return bindata_read(
+ %q,
+ %q,
+ )
+}
+
+`, asset.Func, asset.Path, asset.Name)
+}
diff --git a/go-bindata/main.go b/go-bindata/main.go
index bd07afe..df3f006 100644
--- a/go-bindata/main.go
+++ b/go-bindata/main.go
@@ -10,7 +10,6 @@ import (
"github.com/jteeuwen/go-bindata"
"os"
"path/filepath"
- "strings"
)
func main() {
@@ -29,19 +28,19 @@ func main() {
// any of the command line options are incorrect.
func parseArgs() (*bindata.Config, bindata.ProgressFunc) {
var version, quiet bool
- var tagstr string
- c := new(bindata.Config)
+ c := bindata.NewConfig()
flag.Usage = func() {
fmt.Printf("Usage: %s [options] [