genassets.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. //go:build ignore
  7. // +build ignore
  8. package main
  9. import (
  10. "bytes"
  11. "compress/gzip"
  12. "flag"
  13. "fmt"
  14. "go/format"
  15. "io"
  16. "io/ioutil"
  17. "os"
  18. "path/filepath"
  19. "strconv"
  20. "strings"
  21. "text/template"
  22. "time"
  23. )
  24. var tpl = template.Must(template.New("assets").Parse(`// Code generated by genassets.go - DO NOT EDIT.
  25. package auto
  26. import (
  27. "time"
  28. "github.com/syncthing/syncthing/lib/assets"
  29. )
  30. func Assets() map[string]assets.Asset {
  31. var ret = make(map[string]assets.Asset, {{.Assets | len}})
  32. t := time.Unix({{.Generated}}, 0)
  33. {{range $asset := .Assets}}
  34. ret["{{$asset.Name}}"] = assets.Asset{
  35. Content: {{$asset.Data}},
  36. Gzipped: {{$asset.Gzipped}},
  37. Length: {{$asset.Length}},
  38. Filename: {{$asset.Name | printf "%q"}},
  39. Modified: t,
  40. }
  41. {{end}}
  42. return ret
  43. }
  44. `))
  45. type asset struct {
  46. Name string
  47. Data string
  48. Length int
  49. Gzipped bool
  50. }
  51. var assets []asset
  52. func walkerFor(basePath string) filepath.WalkFunc {
  53. return func(name string, info os.FileInfo, err error) error {
  54. if err != nil {
  55. return err
  56. }
  57. if strings.HasPrefix(filepath.Base(name), ".") {
  58. // Skip dotfiles
  59. return nil
  60. }
  61. if info.Mode().IsRegular() {
  62. data, err := ioutil.ReadFile(name)
  63. if err != nil {
  64. return err
  65. }
  66. length := len(data)
  67. var buf bytes.Buffer
  68. gw, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
  69. gw.Write(data)
  70. gw.Close()
  71. // Only replace asset by gzipped version if it is smaller.
  72. // In practice, this means HTML, CSS, SVG etc. get compressed,
  73. // while PNG and WOFF files are left uncompressed.
  74. // lib/assets detects gzip and sets headers/decompresses.
  75. gzipped := buf.Len() < len(data)
  76. if gzipped {
  77. data = buf.Bytes()
  78. }
  79. name, _ = filepath.Rel(basePath, name)
  80. assets = append(assets, asset{
  81. Name: filepath.ToSlash(name),
  82. Data: fmt.Sprintf("%q", string(data)),
  83. Length: length,
  84. Gzipped: gzipped,
  85. })
  86. }
  87. return nil
  88. }
  89. }
  90. type templateVars struct {
  91. Assets []asset
  92. Generated int64
  93. }
  94. func main() {
  95. outfile := flag.String("o", "", "Name of output file (default stdout)")
  96. flag.Parse()
  97. filepath.Walk(flag.Arg(0), walkerFor(flag.Arg(0)))
  98. var buf bytes.Buffer
  99. // Generated time is now, except if the SOURCE_DATE_EPOCH environment
  100. // variable is set (for reproducible builds).
  101. generated := time.Now().Unix()
  102. if s, _ := strconv.ParseInt(os.Getenv("SOURCE_DATE_EPOCH"), 10, 64); s > 0 {
  103. generated = s
  104. }
  105. tpl.Execute(&buf, templateVars{
  106. Assets: assets,
  107. Generated: generated,
  108. })
  109. bs, err := format.Source(buf.Bytes())
  110. if err != nil {
  111. fmt.Fprintln(os.Stderr, err)
  112. os.Exit(1)
  113. }
  114. out := io.Writer(os.Stdout)
  115. if *outfile != "" {
  116. out, err = os.Create(*outfile)
  117. if err != nil {
  118. fmt.Fprintln(os.Stderr, err)
  119. os.Exit(1)
  120. }
  121. }
  122. out.Write(bs)
  123. }