release.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. // This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
  2. // license. Its contents can be found at:
  3. // http://creativecommons.org/publicdomain/zero/1.0/
  4. package bindata
  5. import (
  6. "bytes"
  7. "compress/gzip"
  8. "fmt"
  9. "io"
  10. "io/ioutil"
  11. "os"
  12. "unicode/utf8"
  13. )
  14. // writeRelease writes the release code file.
  15. func writeRelease(w io.Writer, c *Config, toc []Asset) error {
  16. err := writeReleaseHeader(w, c)
  17. if err != nil {
  18. return err
  19. }
  20. err = writeAssetFS(w, c)
  21. if err != nil {
  22. return err
  23. }
  24. for i := range toc {
  25. err = writeReleaseAsset(w, c, &toc[i])
  26. if err != nil {
  27. return err
  28. }
  29. }
  30. return nil
  31. }
  32. // writeReleaseHeader writes output file headers.
  33. // This targets release builds.
  34. func writeReleaseHeader(w io.Writer, c *Config) error {
  35. var err error
  36. if c.NoCompress {
  37. if c.NoMemCopy {
  38. err = header_uncompressed_nomemcopy(w, c)
  39. } else {
  40. err = header_uncompressed_memcopy(w, c)
  41. }
  42. } else {
  43. if c.NoMemCopy {
  44. err = header_compressed_nomemcopy(w, c)
  45. } else {
  46. err = header_compressed_memcopy(w, c)
  47. }
  48. }
  49. if err != nil {
  50. return err
  51. }
  52. return header_release_common(w)
  53. }
  54. // writeReleaseAsset write a release entry for the given asset.
  55. // A release entry is a function which embeds and returns
  56. // the file's byte content.
  57. func writeReleaseAsset(w io.Writer, c *Config, asset *Asset) error {
  58. fd, err := os.Open(asset.Path)
  59. if err != nil {
  60. return err
  61. }
  62. defer fd.Close()
  63. if c.NoCompress {
  64. if c.NoMemCopy {
  65. err = uncompressed_nomemcopy(w, asset, fd)
  66. } else {
  67. err = uncompressed_memcopy(w, asset, fd)
  68. }
  69. } else {
  70. if c.NoMemCopy {
  71. err = compressed_nomemcopy(w, asset, fd)
  72. } else {
  73. err = compressed_memcopy(w, asset, fd)
  74. }
  75. }
  76. if err != nil {
  77. return err
  78. }
  79. return asset_release_common(w, c, asset)
  80. }
  81. // sanitize prepares a valid UTF-8 string as a raw string constant.
  82. // Based on https://code.google.com/p/go/source/browse/godoc/static/makestatic.go?repo=tools
  83. func sanitize(b []byte) []byte {
  84. // Replace ` with `+"`"+`
  85. b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1)
  86. // Replace BOM with `+"\xEF\xBB\xBF"+`
  87. // (A BOM is valid UTF-8 but not permitted in Go source files.
  88. // I wouldn't bother handling this, but for some insane reason
  89. // jquery.js has a BOM somewhere in the middle.)
  90. return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
  91. }
  92. func header_compressed_nomemcopy(w io.Writer, c *Config) error {
  93. var header string
  94. if c.HttpFileSystem {
  95. header = `import (
  96. "bytes"
  97. "compress/gzip"
  98. "fmt"
  99. "net/http"
  100. "io"
  101. "io/ioutil"
  102. "os"
  103. "path/filepath"
  104. "strings"
  105. "time"`
  106. } else {
  107. header = `import (
  108. "bytes"
  109. "compress/gzip"
  110. "fmt"
  111. "io"
  112. "io/ioutil"
  113. "os"
  114. "path/filepath"
  115. "strings"
  116. "time"`
  117. }
  118. _, err := fmt.Fprintf(w, `%s
  119. )
  120. func bindataRead(data, name string) ([]byte, error) {
  121. gz, err := gzip.NewReader(strings.NewReader(data))
  122. if err != nil {
  123. return nil, fmt.Errorf("read %%q: %%v", name, err)
  124. }
  125. var buf bytes.Buffer
  126. _, err = io.Copy(&buf, gz)
  127. clErr := gz.Close()
  128. if err != nil {
  129. return nil, fmt.Errorf("read %%q: %%v", name, err)
  130. }
  131. if clErr != nil {
  132. return nil, err
  133. }
  134. return buf.Bytes(), nil
  135. }
  136. `, header)
  137. return err
  138. }
  139. func header_compressed_memcopy(w io.Writer, c *Config) error {
  140. var header string
  141. if c.HttpFileSystem {
  142. header = `import (
  143. "bytes"
  144. "compress/gzip"
  145. "fmt"
  146. "net/http"
  147. "io"
  148. "io/ioutil"
  149. "os"
  150. "path/filepath"
  151. "strings"
  152. "time"`
  153. } else {
  154. header = `import (
  155. "bytes"
  156. "compress/gzip"
  157. "fmt"
  158. "io"
  159. "io/ioutil"
  160. "os"
  161. "path/filepath"
  162. "strings"
  163. "time"`
  164. }
  165. _, err := fmt.Fprintf(w, `%s
  166. )
  167. func bindataRead(data []byte, name string) ([]byte, error) {
  168. gz, err := gzip.NewReader(bytes.NewBuffer(data))
  169. if err != nil {
  170. return nil, fmt.Errorf("read %%q: %%v", name, err)
  171. }
  172. var buf bytes.Buffer
  173. _, err = io.Copy(&buf, gz)
  174. clErr := gz.Close()
  175. if err != nil {
  176. return nil, fmt.Errorf("read %%q: %%v", name, err)
  177. }
  178. if clErr != nil {
  179. return nil, err
  180. }
  181. return buf.Bytes(), nil
  182. }
  183. `, header)
  184. return err
  185. }
  186. func header_uncompressed_nomemcopy(w io.Writer, c *Config) error {
  187. var header string
  188. if c.HttpFileSystem {
  189. header = `import (
  190. "bytes"
  191. "fmt"
  192. "net/http"
  193. "io/ioutil"
  194. "os"
  195. "path/filepath"
  196. "reflect"
  197. "strings"
  198. "time"
  199. "unsafe"`
  200. } else {
  201. header = `import (
  202. "fmt"
  203. "io/ioutil"
  204. "os"
  205. "path/filepath"
  206. "reflect"
  207. "strings"
  208. "time"
  209. "unsafe"`
  210. }
  211. _, err := fmt.Fprintf(w, `%s
  212. )
  213. func bindataRead(data, name string) ([]byte, error) {
  214. var empty [0]byte
  215. sx := (*reflect.StringHeader)(unsafe.Pointer(&data))
  216. b := empty[:]
  217. bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
  218. bx.Data = sx.Data
  219. bx.Len = len(data)
  220. bx.Cap = bx.Len
  221. return b, nil
  222. }
  223. `, header)
  224. return err
  225. }
  226. func header_uncompressed_memcopy(w io.Writer, c *Config) error {
  227. var header string
  228. if c.HttpFileSystem {
  229. header = `import (
  230. "bytes"
  231. "fmt"
  232. "net/http"
  233. "io/ioutil"
  234. "os"
  235. "path/filepath"
  236. "strings"
  237. "time"`
  238. } else {
  239. header = `import (
  240. "fmt"
  241. "io/ioutil"
  242. "os"
  243. "path/filepath"
  244. "strings"
  245. "time"`
  246. }
  247. _, err := fmt.Fprintf(w, `%s
  248. )
  249. `, header)
  250. return err
  251. }
  252. func header_release_common(w io.Writer) error {
  253. _, err := fmt.Fprintf(w, `type asset struct {
  254. bytes []byte
  255. info os.FileInfo
  256. }
  257. type bindataFileInfo struct {
  258. name string
  259. size int64
  260. mode os.FileMode
  261. modTime time.Time
  262. }
  263. // Name return file name
  264. func (fi bindataFileInfo) Name() string {
  265. return fi.name
  266. }
  267. // Size return file size
  268. func (fi bindataFileInfo) Size() int64 {
  269. return fi.size
  270. }
  271. // Mode return file mode
  272. func (fi bindataFileInfo) Mode() os.FileMode {
  273. return fi.mode
  274. }
  275. // ModTime return file modify time
  276. func (fi bindataFileInfo) ModTime() time.Time {
  277. return fi.modTime
  278. }
  279. // IsDir return file whether a directory
  280. func (fi bindataFileInfo) IsDir() bool {
  281. return fi.mode&os.ModeDir != 0
  282. }
  283. // Sys return file is sys mode
  284. func (fi bindataFileInfo) Sys() interface{} {
  285. return nil
  286. }
  287. `)
  288. return err
  289. }
  290. func compressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
  291. _, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
  292. if err != nil {
  293. return err
  294. }
  295. gz := gzip.NewWriter(&StringWriter{Writer: w})
  296. _, err = io.Copy(gz, r)
  297. gz.Close()
  298. if err != nil {
  299. return err
  300. }
  301. _, err = fmt.Fprintf(w, `"
  302. func %sBytes() ([]byte, error) {
  303. return bindataRead(
  304. _%s,
  305. %q,
  306. )
  307. }
  308. `, asset.Func, asset.Func, asset.Name)
  309. return err
  310. }
  311. func compressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
  312. _, err := fmt.Fprintf(w, `var _%s = []byte("`, asset.Func)
  313. if err != nil {
  314. return err
  315. }
  316. gz := gzip.NewWriter(&StringWriter{Writer: w})
  317. _, err = io.Copy(gz, r)
  318. gz.Close()
  319. if err != nil {
  320. return err
  321. }
  322. _, err = fmt.Fprintf(w, `")
  323. func %sBytes() ([]byte, error) {
  324. return bindataRead(
  325. _%s,
  326. %q,
  327. )
  328. }
  329. `, asset.Func, asset.Func, asset.Name)
  330. return err
  331. }
  332. func uncompressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
  333. _, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
  334. if err != nil {
  335. return err
  336. }
  337. _, err = io.Copy(&StringWriter{Writer: w}, r)
  338. if err != nil {
  339. return err
  340. }
  341. _, err = fmt.Fprintf(w, `"
  342. func %sBytes() ([]byte, error) {
  343. return bindataRead(
  344. _%s,
  345. %q,
  346. )
  347. }
  348. `, asset.Func, asset.Func, asset.Name)
  349. return err
  350. }
  351. func uncompressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
  352. _, err := fmt.Fprintf(w, `var _%s = []byte(`, asset.Func)
  353. if err != nil {
  354. return err
  355. }
  356. b, err := ioutil.ReadAll(r)
  357. if err != nil {
  358. return err
  359. }
  360. if utf8.Valid(b) && !bytes.Contains(b, []byte{0}) {
  361. fmt.Fprintf(w, "`%s`", sanitize(b))
  362. } else {
  363. fmt.Fprintf(w, "%+q", b)
  364. }
  365. _, err = fmt.Fprintf(w, `)
  366. func %sBytes() ([]byte, error) {
  367. return _%s, nil
  368. }
  369. `, asset.Func, asset.Func)
  370. return err
  371. }
  372. func asset_release_common(w io.Writer, c *Config, asset *Asset) error {
  373. fi, err := os.Stat(asset.Path)
  374. if err != nil {
  375. return err
  376. }
  377. mode := uint(fi.Mode())
  378. modTime := fi.ModTime().Unix()
  379. size := fi.Size()
  380. if c.NoMetadata {
  381. mode = 0
  382. modTime = 0
  383. size = 0
  384. }
  385. if c.Mode > 0 {
  386. mode = uint(os.ModePerm) & c.Mode
  387. }
  388. if c.ModTime > 0 {
  389. modTime = c.ModTime
  390. }
  391. _, err = fmt.Fprintf(w, `func %s() (*asset, error) {
  392. bytes, err := %sBytes()
  393. if err != nil {
  394. return nil, err
  395. }
  396. info := bindataFileInfo{name: %q, size: %d, mode: os.FileMode(%d), modTime: time.Unix(%d, 0)}
  397. a := &asset{bytes: bytes, info: info}
  398. return a, nil
  399. }
  400. `, asset.Func, asset.Func, asset.Name, size, mode, modTime)
  401. return err
  402. }