release.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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. for i := range toc {
  21. err = writeReleaseAsset(w, c, &toc[i])
  22. if err != nil {
  23. return err
  24. }
  25. }
  26. return nil
  27. }
  28. // writeReleaseHeader writes output file headers.
  29. // This targets release builds.
  30. func writeReleaseHeader(w io.Writer, c *Config) error {
  31. var err error
  32. if c.NoCompress {
  33. if c.NoMemCopy {
  34. err = header_uncompressed_nomemcopy(w)
  35. } else {
  36. err = header_uncompressed_memcopy(w)
  37. }
  38. } else {
  39. if c.NoMemCopy {
  40. err = header_compressed_nomemcopy(w)
  41. } else {
  42. err = header_compressed_memcopy(w)
  43. }
  44. }
  45. if err != nil {
  46. return err
  47. }
  48. return header_release_common(w)
  49. }
  50. // writeReleaseAsset write a release entry for the given asset.
  51. // A release entry is a function which embeds and returns
  52. // the file's byte content.
  53. func writeReleaseAsset(w io.Writer, c *Config, asset *Asset) error {
  54. fd, err := os.Open(asset.Path)
  55. if err != nil {
  56. return err
  57. }
  58. defer fd.Close()
  59. if c.NoCompress {
  60. if c.NoMemCopy {
  61. err = uncompressed_nomemcopy(w, asset, fd)
  62. } else {
  63. err = uncompressed_memcopy(w, asset, fd)
  64. }
  65. } else {
  66. if c.NoMemCopy {
  67. err = compressed_nomemcopy(w, asset, fd)
  68. } else {
  69. err = compressed_memcopy(w, asset, fd)
  70. }
  71. }
  72. if err != nil {
  73. return err
  74. }
  75. return asset_release_common(w, c, asset)
  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. // Replace BOM with `+"\xEF\xBB\xBF"+`
  83. // (A BOM is valid UTF-8 but not permitted in Go source files.
  84. // I wouldn't bother handling this, but for some insane reason
  85. // jquery.js has a BOM somewhere in the middle.)
  86. return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1)
  87. }
  88. func header_compressed_nomemcopy(w io.Writer) error {
  89. _, err := fmt.Fprintf(w, `import (
  90. "bytes"
  91. "compress/gzip"
  92. "fmt"
  93. "io"
  94. "io/ioutil"
  95. "os"
  96. "path/filepath"
  97. "strings"
  98. "time"
  99. )
  100. func bindataRead(data, name string) ([]byte, error) {
  101. gz, err := gzip.NewReader(strings.NewReader(data))
  102. if err != nil {
  103. return nil, fmt.Errorf("Read %%q: %%v", name, err)
  104. }
  105. var buf bytes.Buffer
  106. _, err = io.Copy(&buf, gz)
  107. clErr := gz.Close()
  108. if err != nil {
  109. return nil, fmt.Errorf("Read %%q: %%v", name, err)
  110. }
  111. if clErr != nil {
  112. return nil, err
  113. }
  114. return buf.Bytes(), nil
  115. }
  116. `)
  117. return err
  118. }
  119. func header_compressed_memcopy(w io.Writer) error {
  120. _, err := fmt.Fprintf(w, `import (
  121. "bytes"
  122. "compress/gzip"
  123. "fmt"
  124. "io"
  125. "io/ioutil"
  126. "os"
  127. "path/filepath"
  128. "strings"
  129. "time"
  130. )
  131. func bindataRead(data []byte, name string) ([]byte, error) {
  132. gz, err := gzip.NewReader(bytes.NewBuffer(data))
  133. if err != nil {
  134. return nil, fmt.Errorf("Read %%q: %%v", name, err)
  135. }
  136. var buf bytes.Buffer
  137. _, err = io.Copy(&buf, gz)
  138. clErr := gz.Close()
  139. if err != nil {
  140. return nil, fmt.Errorf("Read %%q: %%v", name, err)
  141. }
  142. if clErr != nil {
  143. return nil, err
  144. }
  145. return buf.Bytes(), nil
  146. }
  147. `)
  148. return err
  149. }
  150. func header_uncompressed_nomemcopy(w io.Writer) error {
  151. _, err := fmt.Fprintf(w, `import (
  152. "fmt"
  153. "io/ioutil"
  154. "os"
  155. "path/filepath"
  156. "reflect"
  157. "strings"
  158. "time"
  159. "unsafe"
  160. )
  161. func bindataRead(data, name string) ([]byte, error) {
  162. var empty [0]byte
  163. sx := (*reflect.StringHeader)(unsafe.Pointer(&data))
  164. b := empty[:]
  165. bx := (*reflect.SliceHeader)(unsafe.Pointer(&b))
  166. bx.Data = sx.Data
  167. bx.Len = len(data)
  168. bx.Cap = bx.Len
  169. return b, nil
  170. }
  171. `)
  172. return err
  173. }
  174. func header_uncompressed_memcopy(w io.Writer) error {
  175. _, err := fmt.Fprintf(w, `import (
  176. "fmt"
  177. "io/ioutil"
  178. "os"
  179. "path/filepath"
  180. "strings"
  181. "time"
  182. )
  183. `)
  184. return err
  185. }
  186. func header_release_common(w io.Writer) error {
  187. _, err := fmt.Fprintf(w, `type asset struct {
  188. bytes []byte
  189. info os.FileInfo
  190. }
  191. type bindataFileInfo struct {
  192. name string
  193. size int64
  194. mode os.FileMode
  195. modTime time.Time
  196. }
  197. func (fi bindataFileInfo) Name() string {
  198. return fi.name
  199. }
  200. func (fi bindataFileInfo) Size() int64 {
  201. return fi.size
  202. }
  203. func (fi bindataFileInfo) Mode() os.FileMode {
  204. return fi.mode
  205. }
  206. func (fi bindataFileInfo) ModTime() time.Time {
  207. return fi.modTime
  208. }
  209. func (fi bindataFileInfo) IsDir() bool {
  210. return false
  211. }
  212. func (fi bindataFileInfo) Sys() interface{} {
  213. return nil
  214. }
  215. `)
  216. return err
  217. }
  218. func compressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
  219. _, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
  220. if err != nil {
  221. return err
  222. }
  223. gz := gzip.NewWriter(&StringWriter{Writer: w})
  224. _, err = io.Copy(gz, r)
  225. gz.Close()
  226. if err != nil {
  227. return err
  228. }
  229. _, err = fmt.Fprintf(w, `"
  230. func %sBytes() ([]byte, error) {
  231. return bindataRead(
  232. _%s,
  233. %q,
  234. )
  235. }
  236. `, asset.Func, asset.Func, asset.Name)
  237. return err
  238. }
  239. func compressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
  240. _, err := fmt.Fprintf(w, `var _%s = []byte("`, asset.Func)
  241. if err != nil {
  242. return err
  243. }
  244. gz := gzip.NewWriter(&StringWriter{Writer: w})
  245. _, err = io.Copy(gz, r)
  246. gz.Close()
  247. if err != nil {
  248. return err
  249. }
  250. _, err = fmt.Fprintf(w, `")
  251. func %sBytes() ([]byte, error) {
  252. return bindataRead(
  253. _%s,
  254. %q,
  255. )
  256. }
  257. `, asset.Func, asset.Func, asset.Name)
  258. return err
  259. }
  260. func uncompressed_nomemcopy(w io.Writer, asset *Asset, r io.Reader) error {
  261. _, err := fmt.Fprintf(w, `var _%s = "`, asset.Func)
  262. if err != nil {
  263. return err
  264. }
  265. _, err = io.Copy(&StringWriter{Writer: w}, r)
  266. if err != nil {
  267. return err
  268. }
  269. _, err = fmt.Fprintf(w, `"
  270. func %sBytes() ([]byte, error) {
  271. return bindataRead(
  272. _%s,
  273. %q,
  274. )
  275. }
  276. `, asset.Func, asset.Func, asset.Name)
  277. return err
  278. }
  279. func uncompressed_memcopy(w io.Writer, asset *Asset, r io.Reader) error {
  280. _, err := fmt.Fprintf(w, `var _%s = []byte(`, asset.Func)
  281. if err != nil {
  282. return err
  283. }
  284. b, err := ioutil.ReadAll(r)
  285. if err != nil {
  286. return err
  287. }
  288. if utf8.Valid(b) && !bytes.Contains(b, []byte{0}) {
  289. fmt.Fprintf(w, "`%s`", sanitize(b))
  290. } else {
  291. fmt.Fprintf(w, "%+q", b)
  292. }
  293. _, err = fmt.Fprintf(w, `)
  294. func %sBytes() ([]byte, error) {
  295. return _%s, nil
  296. }
  297. `, asset.Func, asset.Func)
  298. return err
  299. }
  300. func asset_release_common(w io.Writer, c *Config, asset *Asset) error {
  301. fi, err := os.Stat(asset.Path)
  302. if err != nil {
  303. return err
  304. }
  305. mode := uint(fi.Mode())
  306. modTime := fi.ModTime().Unix()
  307. size := fi.Size()
  308. if c.NoMetadata {
  309. mode = 0
  310. modTime = 0
  311. size = 0
  312. }
  313. if c.Mode > 0 {
  314. mode = uint(os.ModePerm) & c.Mode
  315. }
  316. if c.ModTime > 0 {
  317. modTime = c.ModTime
  318. }
  319. _, err = fmt.Fprintf(w, `func %s() (*asset, error) {
  320. bytes, err := %sBytes()
  321. if err != nil {
  322. return nil, err
  323. }
  324. info := bindataFileInfo{name: %q, size: %d, mode: os.FileMode(%d), modTime: time.Unix(%d, 0)}
  325. a := &asset{bytes: bytes, info: info}
  326. return a, nil
  327. }
  328. `, asset.Func, asset.Func, asset.Name, size, mode, modTime)
  329. return err
  330. }