2013-10-29 17:23:52 +00:00
|
|
|
// 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"
|
|
|
|
"strings"
|
|
|
|
"unicode"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ProgressFunc is a callback handler which is fired whenever
|
|
|
|
// bindata begins translating a new file.
|
|
|
|
//
|
|
|
|
// It takes the file path and the current and total file counts.
|
|
|
|
// This can be used to indicate progress of the conversion.
|
|
|
|
//
|
|
|
|
// If this handler returns true, the processing is stopped and
|
|
|
|
// Translate() returns immediately.
|
|
|
|
type ProgressFunc func(file string, current, total int) bool
|
|
|
|
|
|
|
|
// Translate reads assets from an input directory, converts them
|
|
|
|
// to Go code and writes new files to the output directory specified
|
|
|
|
// in the given configuration.
|
|
|
|
func Translate(c *Config, pf ProgressFunc) error {
|
2013-10-30 01:11:04 +00:00
|
|
|
var toc []Asset
|
2013-10-29 17:23:52 +00:00
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
err := findFiles(c.Input, c.Prefix, &toc)
|
2013-10-29 17:23:52 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
// 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.
|
2013-10-29 17:23:52 +00:00
|
|
|
var current int
|
2013-10-30 01:11:04 +00:00
|
|
|
for i := range toc {
|
2013-10-29 17:23:52 +00:00
|
|
|
if pf != nil {
|
|
|
|
current++
|
2013-10-30 01:11:04 +00:00
|
|
|
if pf(toc[i].Path, current, len(toc)) {
|
2013-10-29 17:23:52 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
writeDebug(debug, c, &toc[i])
|
|
|
|
writeRelease(release, c, &toc[i])
|
2013-10-29 17:23:52 +00:00
|
|
|
}
|
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
// Generate TOC file.
|
2013-10-29 17:23:52 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:23:52 +00:00
|
|
|
// 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.
|
2013-10-30 01:11:04 +00:00
|
|
|
func findFiles(dir, prefix string, toc *[]Asset) error {
|
2013-10-29 17:23:52 +00:00
|
|
|
if len(prefix) > 0 {
|
|
|
|
dir, _ = filepath.Abs(dir)
|
|
|
|
prefix, _ = filepath.Abs(prefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
fd, err := os.Open(dir)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer fd.Close()
|
|
|
|
|
|
|
|
list, err := fd.Readdir(0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range list {
|
2013-10-30 01:11:04 +00:00
|
|
|
var asset Asset
|
|
|
|
asset.Path = filepath.Join(dir, file.Name())
|
|
|
|
asset.Name = asset.Path
|
2013-10-29 17:23:52 +00:00
|
|
|
|
|
|
|
if file.IsDir() {
|
2013-10-30 01:11:04 +00:00
|
|
|
findFiles(asset.Path, prefix, toc)
|
|
|
|
continue
|
|
|
|
}
|
2013-10-29 17:23:52 +00:00
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
if strings.HasPrefix(asset.Name, prefix) {
|
|
|
|
asset.Name = asset.Name[len(prefix):]
|
|
|
|
}
|
2013-10-29 17:23:52 +00:00
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
// If we have a leading slash, get rid of it.
|
|
|
|
if len(asset.Name) > 0 && asset.Name[0] == '/' {
|
|
|
|
asset.Name = asset.Name[1:]
|
|
|
|
}
|
2013-10-29 17:23:52 +00:00
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
// This shouldn't happen.
|
|
|
|
if len(asset.Name) == 0 {
|
|
|
|
return fmt.Errorf("Invalid file: %v", asset.Path)
|
2013-10-29 17:23:52 +00:00
|
|
|
}
|
2013-10-30 01:11:04 +00:00
|
|
|
|
|
|
|
asset.Func = safeFunctionName(asset.Name)
|
|
|
|
asset.Path, _ = filepath.Abs(asset.Path)
|
|
|
|
*toc = append(*toc, asset)
|
2013-10-29 17:23:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var regFuncName = regexp.MustCompile(`[^a-zA-Z0-9_]`)
|
|
|
|
|
|
|
|
// safeFunctionName converts the given name into a name
|
|
|
|
// which qualifies as a valid function identifier.
|
|
|
|
func safeFunctionName(name string) string {
|
|
|
|
name = strings.ToLower(name)
|
|
|
|
name = regFuncName.ReplaceAllString(name, "_")
|
|
|
|
|
|
|
|
// Get rid of "__" instances for niceness.
|
|
|
|
for strings.Index(name, "__") > -1 {
|
|
|
|
name = strings.Replace(name, "__", "_", -1)
|
|
|
|
}
|
|
|
|
|
2013-10-30 01:11:04 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:23:52 +00:00
|
|
|
return name
|
|
|
|
}
|