Codebase list golang-bindata / b564b9a
Imported Upstream version 3.0.7 Dmitry Smirnov 8 years ago
10 changed file(s) with 371 addition(s) and 115 deletion(s). Raw diff Collapse all Expand all
6969 > the rest of the API. This addresses issue #32
7070
7171 Do not pile a lot of unrelated changes into a single commit.
72 Pick and chose only those changes for a single commit, which are
72 Pick and choose only those changes for a single commit, which are
7373 directly related. We would much rather see a hundred commits
7474 saying nothing but `"Runs go fmt"` in between any real fixes
7575 than have these style changes embedded in those real fixes.
4141 $ go-bindata dir1/... /path/to/dir2/... dir3
4242
4343
44 The following paragraphs detail some of the command line options which can
44 The following paragraphs detail some of the command line options which can be
4545 supplied to `go-bindata`. Refer to the `testdata/out` directory for various
4646 output examples from the assets in `testdata/in`. Each example uses different
4747 command line options.
4848
49 To ignore files, pass in regexes using -ignore, for example:
50
51 $ go-bindata -ignore=\\.gitignore data/...
4952
5053 ### Accessing an asset
5154
52 To access asset data, we use the `Asset(string) []byte` function which
55 To access asset data, we use the `Asset(string) ([]byte, error)` function which
5356 is included in the generated output.
5457
55 data := Asset("pub/style/foo.css")
56 if len(data) == 0 {
58 data, err := Asset("pub/style/foo.css")
59 if err != nil {
5760 // Asset was not found.
5861 }
59
62
6063 // use asset data
6164
6265
178181 The tags are appended to a `// +build` line in the beginning of the output file
179182 and must follow the build tags syntax specified by the go tool.
180183
184 ### Related projects
181185
186 [go-bindata-assetfs](https://github.com/elazarl/go-bindata-assetfs#readme) -
187 implements `http.FileSystem` interface. Allows you to serve assets with `net/http`.
188
99 Name string // Key used in TOC -- name by which asset is referenced.
1010 Func string // Function name for the procedure returning the asset contents.
1111 }
12
13 // Implement sort.Interface for []Asset based on Path field
14 type ByPath []Asset
15
16 func (v ByPath) Len() int { return len(v) }
17 func (v ByPath) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
18 func (v ByPath) Less(i, j int) bool { return v[i].Path < v[j].Path }
77 "fmt"
88 "os"
99 "path/filepath"
10 "regexp"
1011 )
1112
1213 // InputConfig defines options on a asset directory to be convert.
119120 // sub directories. This defaults to false, so only files in the
120121 // input directory itself are read.
121122 Recursive bool
123
124 // Ignores any filenames matching the regex pattern specified, e.g.
125 // path/to/file.ext will ignore only that file, or \\.gitignore
126 // will match any .gitignore file.
127 //
128 // This parameter can be provided multiple times.
129 Ignore []*regexp.Regexp
122130 }
123131
124132 // NewConfig returns a default configuration struct.
130138 c.Debug = false
131139 c.Recursive = false
132140 c.Output = "./bindata.go"
141 c.Ignore = make([]*regexp.Regexp, 0)
133142 return c
134143 }
135144
141150 }
142151
143152 for _, input := range c.Input {
144 stat, err := os.Lstat(input.Path)
153 _, err := os.Lstat(input.Path)
145154 if err != nil {
146155 return fmt.Errorf("Failed to stat input path '%s': %v", input.Path, err)
147 }
148
149 if !stat.IsDir() {
150 return fmt.Errorf("Input path '%s' is not a directory.", input.Path)
151156 }
152157 }
153158
169174 // File does not exist. This is fine, just make
170175 // sure the directory it is to be in exists.
171176 dir, _ := filepath.Split(c.Output)
172 err = os.MkdirAll(dir, 0744)
177 if dir != "" {
178 err = os.MkdirAll(dir, 0744)
173179
174 if err != nil {
175 return fmt.Errorf("Create output directory: %v", err)
180 if err != nil {
181 return fmt.Errorf("Create output directory: %v", err)
182 }
176183 }
177184 }
178185
99 "os"
1010 "path/filepath"
1111 "regexp"
12 "sort"
1213 "strings"
1314 "unicode"
1415 )
2728
2829 // Locate all the assets.
2930 for _, input := range c.Input {
30 err = findFiles(input.Path, c.Prefix, input.Recursive, &toc)
31 if err != nil {
32 return err
33 }
34 }
31 err = findFiles(input.Path, c.Prefix, input.Recursive, &toc, c.Ignore)
32 if err != nil {
33 return err
34 }
35 }
36
37 // Sort to make output stable between invocations
38 sort.Sort(ByPath(toc))
3539
3640 // Create output file.
3741 fd, err := os.Create(c.Output)
7175 }
7276
7377 // Write table of contents
74 return writeTOC(bfd, toc)
78 if err := writeTOC(bfd, toc); err != nil {
79 return err
80 }
81 // Write hierarchical tree of assets
82 return writeTOCTree(bfd, toc)
7583 }
7684
7785 // findFiles recursively finds all the file paths in the given directory tree.
7886 // They are added to the given map as keys. Values will be safe function names
7987 // for each file, which will be used when generating the output code.
80 func findFiles(dir, prefix string, recursive bool, toc *[]Asset) error {
88 func findFiles(dir, prefix string, recursive bool, toc *[]Asset, ignore []*regexp.Regexp) error {
8189 if len(prefix) > 0 {
8290 dir, _ = filepath.Abs(dir)
8391 prefix, _ = filepath.Abs(prefix)
84 }
85
86 fd, err := os.Open(dir)
87 if err != nil {
88 return err
89 }
90
91 defer fd.Close()
92
93 list, err := fd.Readdir(0)
94 if err != nil {
95 return err
96 }
92 prefix = filepath.ToSlash(prefix)
93 }
94
95 fi, err := os.Stat(dir)
96 if err != nil {
97 return err
98 }
99
100 var list []os.FileInfo
101
102 if !fi.IsDir() {
103 dir = ""
104 list = []os.FileInfo{fi}
105 } else {
106 fd, err := os.Open(dir)
107 if err != nil {
108 return err
109 }
110
111 defer fd.Close()
112
113 list, err = fd.Readdir(0)
114 if err != nil {
115 return err
116 }
117 }
118
119 knownFuncs := make(map[string]int)
97120
98121 for _, file := range list {
99122 var asset Asset
100123 asset.Path = filepath.Join(dir, file.Name())
101 asset.Name = asset.Path
124 asset.Name = filepath.ToSlash(asset.Path)
125
126 ignoring := false
127 for _, re := range ignore {
128 if re.MatchString(asset.Path) {
129 ignoring = true
130 break
131 }
132 }
133 if ignoring {
134 continue
135 }
102136
103137 if file.IsDir() {
104138 if recursive {
105 findFiles(asset.Path, prefix, recursive, toc)
139 findFiles(asset.Path, prefix, recursive, toc, ignore)
106140 }
107141 continue
108142 }
121155 return fmt.Errorf("Invalid file: %v", asset.Path)
122156 }
123157
124 asset.Func = safeFunctionName(asset.Name)
158 asset.Func = safeFunctionName(asset.Name, knownFuncs)
125159 asset.Path, _ = filepath.Abs(asset.Path)
126160 *toc = append(*toc, asset)
127161 }
132166 var regFuncName = regexp.MustCompile(`[^a-zA-Z0-9_]`)
133167
134168 // safeFunctionName converts the given name into a name
135 // which qualifies as a valid function identifier.
136 func safeFunctionName(name string) string {
169 // which qualifies as a valid function identifier. It
170 // also compares against a known list of functions to
171 // prevent conflict based on name translation.
172 func safeFunctionName(name string, knownFuncs map[string]int) string {
137173 name = strings.ToLower(name)
138174 name = regFuncName.ReplaceAllString(name, "_")
139175
152188 name = "_" + name
153189 }
154190
191 if num, ok := knownFuncs[name]; ok {
192 knownFuncs[name] = num + 1
193 name = fmt.Sprintf("%s%d", name, num)
194 } else {
195 knownFuncs[name] = 2
196 }
197
155198 return name
156199 }
3131 _, err := fmt.Fprintf(w, `import (
3232 "fmt"
3333 "io/ioutil"
34 "strings"
3435 )
3536
36 // bindata_read reads the given file from disk. It returns
37 // an error on failure.
37 // bindata_read reads the given file from disk. It returns an error on failure.
3838 func bindata_read(path, name string) ([]byte, error) {
3939 buf, err := ioutil.ReadFile(path)
4040 if err != nil {
5151 // A debug entry is simply a function which reads the asset from
5252 // the original file (e.g.: from disk).
5353 func writeDebugAsset(w io.Writer, asset *Asset) error {
54 _, err := fmt.Fprintf(w, `
55 // %s reads file data from disk.
56 // It panics if something went wrong in the process.
54 _, err := fmt.Fprintf(w, `// %s reads file data from disk. It returns an error on failure.
5755 func %s() ([]byte, error) {
5856 return bindata_read(
5957 %q,
6058 %q,
6159 )
6260 }
61
6362 `, asset.Func, asset.Func, asset.Path, asset.Name)
6463 return err
6564 }
0 package main
1
2 import "strings"
3
4 // borrowed from https://github.com/hashicorp/serf/blob/master/command/agent/flag_slice_value.go
5
6 // AppendSliceValue implements the flag.Value interface and allows multiple
7 // calls to the same variable to append a list.
8 type AppendSliceValue []string
9
10 func (s *AppendSliceValue) String() string {
11 return strings.Join(*s, ",")
12 }
13
14 func (s *AppendSliceValue) Set(value string) error {
15 if *s == nil {
16 *s = make([]string, 0, 1)
17 }
18
19 *s = append(*s, value)
20 return nil
21 }
99 "github.com/jteeuwen/go-bindata"
1010 "os"
1111 "path/filepath"
12 "regexp"
1213 "strings"
1314 )
1415
3839 }
3940
4041 flag.BoolVar(&c.Debug, "debug", c.Debug, "Do not embed the assets, but provide the embedding API. Contents will still be loaded from disk.")
41 flag.StringVar(&c.Tags, "tags", c.Tags, "Optional set of uild tags to include.")
42 flag.StringVar(&c.Tags, "tags", c.Tags, "Optional set of build tags to include.")
4243 flag.StringVar(&c.Prefix, "prefix", c.Prefix, "Optional path prefix to strip off asset names.")
4344 flag.StringVar(&c.Package, "pkg", c.Package, "Package name to use in the generated code.")
4445 flag.BoolVar(&c.NoMemCopy, "nomemcopy", c.NoMemCopy, "Use a .rodata hack to get rid of unnecessary memcopies. Refer to the documentation to see what implications this carries.")
4546 flag.BoolVar(&c.NoCompress, "nocompress", c.NoCompress, "Assets will *not* be GZIP compressed when this flag is specified.")
4647 flag.StringVar(&c.Output, "o", c.Output, "Optional name of the output file to be generated.")
4748 flag.BoolVar(&version, "version", false, "Displays version information.")
49
50 ignore := make([]string, 0)
51 flag.Var((*AppendSliceValue)(&ignore), "ignore", "Regex pattern to ignore")
52
4853 flag.Parse()
54
55 patterns := make([]*regexp.Regexp, 0)
56 for _, pattern := range ignore {
57 patterns = append(patterns, regexp.MustCompile(pattern))
58 }
59 c.Ignore = patterns
4960
5061 if version {
5162 fmt.Printf("%s\n", Version())
44 package bindata
55
66 import (
7 "bytes"
78 "compress/gzip"
89 "fmt"
910 "io"
11 "io/ioutil"
1012 "os"
13 "unicode/utf8"
1114 )
1215
1316 // writeRelease writes the release code file.
6972 return compressed_memcopy(w, asset, fd)
7073 }
7174 }
72
73 return nil
75 }
76
77 // sanitize prepares a valid UTF-8 string as a raw string constant.
78 // Based on https://code.google.com/p/go/source/browse/godoc/static/makestatic.go?repo=tools
79 func sanitize(b []byte) []byte {
80 // Replace ` with `+"`"+`
81 b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)
82
83 // Replace BOM with `+"\xEF\xBB\xBF"+`
84 // (A BOM is valid UTF-8 but not permitted in Go source files.
85 // I wouldn't bother handling this, but for some insane reason
86 // jquery.js has a BOM somewhere in the middle.)
87 return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
7488 }
7589
7690 func header_compressed_nomemcopy(w io.Writer) error {
7791 _, err := fmt.Fprintf(w, `import (
78 "bytes"
79 "compress/gzip"
80 "fmt"
81 "io"
82 "reflect"
83 "unsafe"
92 "bytes"
93 "compress/gzip"
94 "fmt"
95 "io"
96 "reflect"
97 "strings"
98 "unsafe"
8499 )
85100
86101 func bindata_read(data, name string) ([]byte, error) {
114129
115130 func header_compressed_memcopy(w io.Writer) error {
116131 _, err := fmt.Fprintf(w, `import (
117 "bytes"
118 "compress/gzip"
119 "fmt"
120 "io"
132 "bytes"
133 "compress/gzip"
134 "fmt"
135 "io"
136 "strings"
121137 )
122138
123139 func bindata_read(data []byte, name string) ([]byte, error) {
143159
144160 func header_uncompressed_nomemcopy(w io.Writer) error {
145161 _, err := fmt.Fprintf(w, `import (
146 "fmt"
147 "reflect"
148 "unsafe"
162 "fmt"
163 "reflect"
164 "strings"
165 "unsafe"
149166 )
150167
151168 func bindata_read(data, name string) ([]byte, error) {
165182
166183 func header_uncompressed_memcopy(w io.Writer) error {
167184 _, err := fmt.Fprintf(w, `import (
168 "fmt"
185 "fmt"
186 "strings"
169187 )
170188 `)
171189 return err
199217 }
200218
201219 func compressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
202 _, err := fmt.Fprintf(w, `func %s() ([]byte, error) {
203 return bindata_read([]byte{`, asset.Func)
204
205 if err != nil {
206 return nil
207 }
208
209 gz := gzip.NewWriter(&ByteWriter{Writer: w})
220 _, err := fmt.Fprintf(w, `var _%s = []byte("`, asset.Func)
221 if err != nil {
222 return err
223 }
224
225 gz := gzip.NewWriter(&StringWriter{Writer: w})
210226 _, err = io.Copy(gz, r)
211227 gz.Close()
212228
214230 return err
215231 }
216232
217 _, err = fmt.Fprintf(w, `
218 },
219 %q,
220 )
221 }
222
223 `, asset.Name)
224 return err
225 }
226
227 func uncompressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
228 _, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
229 if err != nil {
230 return err
231 }
232
233 _, err = io.Copy(&StringWriter{Writer: w}, r)
234 if err != nil {
235 return err
236 }
237
238 _, err = fmt.Fprintf(w, `"
233 _, err = fmt.Fprintf(w, `")
239234
240235 func %s() ([]byte, error) {
241236 return bindata_read(
248243 return err
249244 }
250245
246 func uncompressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
247 _, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
248 if err != nil {
249 return err
250 }
251
252 _, err = io.Copy(&StringWriter{Writer: w}, r)
253 if err != nil {
254 return err
255 }
256
257 _, err = fmt.Fprintf(w, `"
258
259 func %s() ([]byte, error) {
260 return bindata_read(
261 _%s,
262 %q,
263 )
264 }
265
266 `, asset.Func, asset.Func, asset.Name)
267 return err
268 }
269
251270 func uncompressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
252 _, err := fmt.Fprintf(w, `func %s() ([]byte, error) {
253 return []byte{`, asset.Func)
254 if err != nil {
255 return err
256 }
257
258 _, err = io.Copy(&ByteWriter{Writer: w}, r)
259 if err != nil {
260 return err
261 }
262
263 _, err = fmt.Fprintf(w, `
264 }, nil
265 }
266
267 `)
268 return err
269 }
271 _, err := fmt.Fprintf(w, `var _%s = []byte(`, asset.Func)
272 if err != nil {
273 return err
274 }
275
276 b, err := ioutil.ReadAll(r)
277 if err != nil {
278 return err
279 }
280 if utf8.Valid(b) {
281 fmt.Fprintf(w, "`%s`", sanitize(b))
282 } else {
283 fmt.Fprintf(w, "%q", b)
284 }
285
286 _, err = fmt.Fprintf(w, `)
287
288 func %s() ([]byte, error) {
289 return _%s, nil
290 }
291
292 `, asset.Func, asset.Func)
293 return err
294 }
66 import (
77 "fmt"
88 "io"
9 "os"
10 "sort"
11 "strings"
912 )
13
14 type assetTree struct {
15 Asset Asset
16 Children map[string]*assetTree
17 }
18
19 func newAssetTree() *assetTree {
20 tree := &assetTree{}
21 tree.Children = make(map[string]*assetTree)
22 return tree
23 }
24
25 func (node *assetTree) child(name string) *assetTree {
26 rv, ok := node.Children[name]
27 if !ok {
28 rv = newAssetTree()
29 node.Children[name] = rv
30 }
31 return rv
32 }
33
34 func (root *assetTree) Add(route []string, asset Asset) {
35 for _, name := range route {
36 root = root.child(name)
37 }
38 root.Asset = asset
39 }
40
41 func ident(w io.Writer, n int) {
42 for i := 0; i < n; i++ {
43 w.Write([]byte{'\t'})
44 }
45 }
46
47 func (root *assetTree) funcOrNil() string {
48 if root.Asset.Func == "" {
49 return "nil"
50 } else {
51 return root.Asset.Func
52 }
53 }
54
55 func (root *assetTree) writeGoMap(w io.Writer, nident int) {
56 fmt.Fprintf(w, "&_bintree_t{%s, map[string]*_bintree_t{\n", root.funcOrNil())
57
58 // Sort to make output stable between invocations
59 filenames := make([]string, len(root.Children))
60 i := 0
61 for filename, _ := range root.Children {
62 filenames[i] = filename
63 i++
64 }
65 sort.Strings(filenames)
66
67 for _, p := range filenames {
68 ident(w, nident+1)
69 fmt.Fprintf(w, `"%s": `, p)
70 root.Children[p].writeGoMap(w, nident+1)
71 }
72 ident(w, nident)
73 io.WriteString(w, "}}")
74 if nident > 0 {
75 io.WriteString(w, ",")
76 }
77 io.WriteString(w, "\n")
78 }
79
80 func (root *assetTree) WriteAsGoMap(w io.Writer) error {
81 _, err := fmt.Fprint(w, `type _bintree_t struct {
82 Func func() ([]byte, error)
83 Children map[string]*_bintree_t
84 }
85 var _bintree = `)
86 root.writeGoMap(w, 0)
87 return err
88 }
89
90 func writeTOCTree(w io.Writer, toc []Asset) error {
91 _, err := fmt.Fprintf(w, `// AssetDir returns the file names below a certain
92 // directory embedded in the file by go-bindata.
93 // For example if you run go-bindata on data/... and data contains the
94 // following hierarchy:
95 // data/
96 // foo.txt
97 // img/
98 // a.png
99 // b.png
100 // then AssetDir("data") would return []string{"foo.txt", "img"}
101 // AssetDir("data/img") would return []string{"a.png", "b.png"}
102 // AssetDir("foo.txt") and AssetDir("notexist") would return an error
103 // AssetDir("") will return []string{"data"}.
104 func AssetDir(name string) ([]string, error) {
105 node := _bintree
106 if len(name) != 0 {
107 cannonicalName := strings.Replace(name, "\\", "/", -1)
108 pathList := strings.Split(cannonicalName, "/")
109 for _, p := range pathList {
110 node = node.Children[p]
111 if node == nil {
112 return nil, fmt.Errorf("Asset %%s not found", name)
113 }
114 }
115 }
116 if node.Func != nil {
117 return nil, fmt.Errorf("Asset %%s not found", name)
118 }
119 rv := make([]string, 0, len(node.Children))
120 for name := range node.Children {
121 rv = append(rv, name)
122 }
123 return rv, nil
124 }
125
126 `)
127 if err != nil {
128 return err
129 }
130 tree := newAssetTree()
131 for i := range toc {
132 pathList := strings.Split(toc[i].Name, string(os.PathSeparator))
133 tree.Add(pathList, toc[i])
134 }
135 return tree.WriteAsGoMap(w)
136 }
10137
11138 // writeTOC writes the table of contents file.
12139 func writeTOC(w io.Writer, toc []Asset) error {
27154
28155 // writeTOCHeader writes the table of contents file header.
29156 func writeTOCHeader(w io.Writer) error {
30 _, err := fmt.Fprintf(w, `
31 // Asset loads and returns the asset for the given name.
157 _, err := fmt.Fprintf(w, `// Asset loads and returns the asset for the given name.
32158 // It returns an error if the asset could not be found or
33159 // could not be loaded.
34160 func Asset(name string) ([]byte, error) {
35 if f, ok := _bindata[name]; ok {
161 cannonicalName := strings.Replace(name, "\\", "/", -1)
162 if f, ok := _bindata[cannonicalName]; ok {
36163 return f()
37164 }
38165 return nil, fmt.Errorf("Asset %%s not found", name)
39166 }
40167
168 // AssetNames returns the names of the assets.
169 func AssetNames() []string {
170 names := make([]string, 0, len(_bindata))
171 for name := range _bindata {
172 names = append(names, name)
173 }
174 return names
175 }
176
41177 // _bindata is a table, holding each asset generator, mapped to its name.
42 var _bindata = map[string] func() ([]byte, error) {
178 var _bindata = map[string]func() ([]byte, error){
43179 `)
44180 return err
45181 }
52188
53189 // writeTOCFooter writes the table of contents file footer.
54190 func writeTOCFooter(w io.Writer) error {
55 _, err := fmt.Fprintf(w, `
56 }
191 _, err := fmt.Fprintf(w, `}
57192 `)
58193 return err
59194 }