a simple url shortener in Go (check it out at qurl.org)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
6.0 KiB

  1. // The bindata command embeds binary files as byte arrays into a Go source file.
  2. //
  3. // It is designed with go generate in mind, but can be used on its own as well.
  4. //
  5. // The data is stored as a map of byte slices or strings indexed by the
  6. // file paths as specified on the command line. The default name of the
  7. // map is "bindata" but a custom name can be specified on the command line (-m).
  8. //
  9. // Multiple files and directories can be provided on the command line.
  10. // Directories are treated recursively. The keys of the map are the paths
  11. // of the files relative to the current directory. A different root for
  12. // the paths can be specified on the command line (-r).
  13. //
  14. // By default, the data are saved as byte slices.
  15. // It is also possible to save them a strings (-s).
  16. //
  17. // By default, the package name of the file containing the generate directive
  18. // is used as the package name of the generated file, or "main" otherwise.
  19. // A custom package name can also be specified on the command line (-p).
  20. //
  21. // The output file can be specified on the command line (-o).
  22. // If a file already exists at this location, it will be overwritten.
  23. // The file produced is properly formatted and commented.
  24. // If no output file is specified, the contents are printed on the standard output.
  25. //
  26. // To see the full list of flags, run:
  27. // bindata -h
  28. //
  29. // Example
  30. //
  31. // Given a file hello.go containing:
  32. //
  33. // package main
  34. //
  35. // import "fmt"
  36. //
  37. // func main() {
  38. // fmt.Println("Hello, 世界")
  39. // }
  40. //
  41. // Running `bindata hello.go` will produce:
  42. //
  43. // package main
  44. //
  45. // // This file is generated. Do not edit directly.
  46. //
  47. // // bindata stores binary files as byte slices indexed by filepaths.
  48. // var bindata = map[string][]byte{
  49. // "hello.go": []byte{
  50. // 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e,
  51. // 0x0a, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x22, 0x66, 0x6d,
  52. // 0x74, 0x22, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x20, 0x6d, 0x61, 0x69,
  53. // 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x66, 0x6d, 0x74, 0x2e, 0x50,
  54. // 0x72, 0x69, 0x6e, 0x74, 0x6c, 0x6e, 0x28, 0x22, 0x48, 0x65, 0x6c, 0x6c,
  55. // 0x6f, 0x2c, 0x20, 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c, 0x22, 0x29, 0x0a,
  56. // 0x7d, 0x0a,
  57. // },
  58. // }
  59. //
  60. // Example using go generate
  61. //
  62. // Add a command like this one anywhere in a source file:
  63. // //go:generate bindata -o jpegs.go pic1.jpg pic2.jpg pic3.jpg
  64. // Then simply run
  65. // go generate
  66. // and the file jpegs.go will be created.
  67. package main
  68. import (
  69. "bufio"
  70. "flag"
  71. "fmt"
  72. "io"
  73. "os"
  74. "path/filepath"
  75. "text/template"
  76. )
  77. // tmpl is the template of the generated Go source file.
  78. var tmpl = template.Must(template.New("bindata").Parse(`package {{.Pkg}}
  79. // This file is generated. Do not edit directly.
  80. // {{.Map}} stores binary files as {{if .AsString}}strings{{else}}byte slices{{end}} indexed by file paths.
  81. var {{.Map}} = map[string]{{if .AsString}}string{{else}}[]byte{{end}}{{"{"}}{{range $name, $data := .Files}}
  82. {{printf "%#v" $name}}: {{printf "%#v" $data}},{{end}}
  83. }
  84. `))
  85. // vars contains the variables required by the template.
  86. var vars struct {
  87. Pkg string
  88. Map string
  89. AsString bool
  90. Files map[string]fmt.Formatter
  91. }
  92. func main() {
  93. if err := run(); err != nil {
  94. fmt.Println("bindata:", err)
  95. os.Exit(1)
  96. }
  97. }
  98. // run executes the program.
  99. func run() error {
  100. // use GOPACKAGE (set by go generate) as default package name if available
  101. pkg := os.Getenv("GOPACKAGE")
  102. if pkg == "" {
  103. pkg = "main"
  104. }
  105. var out, prefix string
  106. fs := flag.NewFlagSet("bindata", flag.ExitOnError)
  107. fs.StringVar(&out, "o", "", "output file (default: stdout)")
  108. fs.StringVar(&vars.Pkg, "p", pkg, "name of the package")
  109. fs.StringVar(&vars.Map, "m", "bindata", "name of the map variable")
  110. fs.StringVar(&prefix, "r", "", "root path for map keys")
  111. fs.BoolVar(&vars.AsString, "s", false, "save data as strings")
  112. if err := fs.Parse(os.Args[1:]); err != nil {
  113. return err
  114. }
  115. vars.Files = make(map[string]fmt.Formatter)
  116. for _, path := range fs.Args() {
  117. if err := AddPath(path, prefix); err != nil {
  118. return err
  119. }
  120. }
  121. var file *os.File
  122. if out != "" {
  123. var err error
  124. if file, err = os.Create(out); err != nil {
  125. return err
  126. }
  127. } else {
  128. file = os.Stdout
  129. }
  130. return tmpl.Execute(file, vars)
  131. }
  132. // AddPath add files to the slice in vars recursively.
  133. func AddPath(path, prefix string) error {
  134. fi, err := os.Stat(path)
  135. if err != nil {
  136. return err
  137. }
  138. if fi.IsDir() {
  139. dir, err := os.Open(path)
  140. if err != nil {
  141. return err
  142. }
  143. files, err := dir.Readdirnames(0)
  144. if err != nil {
  145. return err
  146. }
  147. for _, file := range files {
  148. if err := AddPath(filepath.Join(path, file), prefix); err != nil {
  149. return err
  150. }
  151. }
  152. } else {
  153. file, err := os.Open(path)
  154. if err != nil {
  155. return err
  156. }
  157. path, err := filepath.Rel(prefix, path)
  158. if err != nil {
  159. return err
  160. }
  161. if vars.AsString {
  162. vars.Files[path] = StringFormatter{file}
  163. } else {
  164. vars.Files[path] = ByteSliceFormatter{file}
  165. }
  166. }
  167. return nil
  168. }
  169. // A ByteSliceFormatter is a byte slice pretty printing io.Reader.
  170. type ByteSliceFormatter struct {
  171. io.Reader
  172. }
  173. // Format pretty prints the bytes read from the ByteSliceFormatter.
  174. func (f ByteSliceFormatter) Format(s fmt.State, c rune) {
  175. buf := bufio.NewReader(f)
  176. const cols = 12 // number of columns in the formatted byte slice.
  177. fmt.Fprintf(s, "[]byte{")
  178. b, err := buf.ReadByte()
  179. for i := 0; err == nil; i++ {
  180. if i%cols == 0 {
  181. fmt.Fprintf(s, "\n\t\t")
  182. } else {
  183. fmt.Fprintf(s, " ")
  184. }
  185. fmt.Fprintf(s, "%#02x,", b)
  186. b, err = buf.ReadByte()
  187. }
  188. fmt.Fprintf(s, "\n\t}")
  189. }
  190. // A StringFormatter is a string pretty printing io.Reader.
  191. type StringFormatter struct {
  192. io.Reader
  193. }
  194. // Format pretty prints the bytes read from the StringFormatter.
  195. func (f StringFormatter) Format(s fmt.State, c rune) {
  196. buf := bufio.NewReader(f)
  197. const cols = 16 // number of bytes per line in the formatted string.
  198. fmt.Fprintf(s, `"`)
  199. b, err := buf.ReadByte()
  200. for i := 0; err == nil; i++ {
  201. if i%cols == 0 {
  202. fmt.Fprintf(s, "\" +\n\t\t\"")
  203. }
  204. fmt.Fprintf(s, "\\x%02x", b)
  205. b, err = buf.ReadByte()
  206. }
  207. fmt.Fprintf(s, `"`)
  208. }