main.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright 2018-present the CoreDHCP Authors. All rights reserved
  2. // This source code is licensed under the MIT license found in the
  3. // LICENSE file in the root directory of this source tree.
  4. package main
  5. import (
  6. "bufio"
  7. "fmt"
  8. "html/template"
  9. "io/ioutil"
  10. "log"
  11. "os"
  12. "path"
  13. "sort"
  14. "strings"
  15. flag "github.com/spf13/pflag"
  16. )
  17. const (
  18. defaultTemplateFile = "coredhcp.go.template"
  19. importBase = "github.com/coredhcp/coredhcp/"
  20. )
  21. var (
  22. flagTemplate = flag.StringP("template", "t", defaultTemplateFile, "Template file name")
  23. flagOutfile = flag.StringP("outfile", "o", "", "Output file path")
  24. flagFromFile = flag.StringP("from", "f", "", "Optional file name to get the plugin list from, one import path per line")
  25. )
  26. var funcMap = template.FuncMap{
  27. "importname": func(importPath string) (string, error) {
  28. parts := strings.Split(importPath, "/")
  29. if len(parts) < 1 {
  30. return "", fmt.Errorf("no components found in import path '%s'", importPath)
  31. }
  32. return "pl_" + parts[len(parts)-1], nil
  33. },
  34. }
  35. func usage() {
  36. fmt.Fprintf(flag.CommandLine.Output(),
  37. "%s [-template tpl] [-outfile out] [-from pluginlist] [plugin [plugin...]]\n",
  38. os.Args[0],
  39. )
  40. flag.PrintDefaults()
  41. fmt.Fprintln(flag.CommandLine.Output(), ` plugin
  42. Plugin name to include, as go import path.
  43. Short names can be used for builtin coredhcp plugins (eg "serverid")`)
  44. }
  45. func main() {
  46. flag.Usage = usage
  47. flag.Parse()
  48. data, err := ioutil.ReadFile(*flagTemplate)
  49. if err != nil {
  50. log.Fatalf("Failed to read template file '%s': %v", *flagTemplate, err)
  51. }
  52. t, err := template.New("coredhcp").Funcs(funcMap).Parse(string(data))
  53. if err != nil {
  54. log.Fatalf("Template parsing failed: %v", err)
  55. }
  56. plugins := make(map[string]bool)
  57. for _, pl := range flag.Args() {
  58. pl := strings.TrimSpace(pl)
  59. if pl == "" {
  60. continue
  61. }
  62. if !strings.ContainsRune(pl, '/') {
  63. // A bare name was specified, not a full import path.
  64. // Coredhcp plugins aren't in the standard library, and it's unlikely someone
  65. // would put them at the base of $GOPATH/src.
  66. // Assume this is one of the builtin plugins. If needed, use the -from option
  67. // which always requires (and uses) exact paths
  68. // XXX: we could also look into github.com/coredhcp/plugins
  69. pl = importBase + pl
  70. }
  71. plugins[pl] = true
  72. }
  73. if *flagFromFile != "" {
  74. // additional plugin names from a text file, one line per plugin import
  75. // path
  76. fd, err := os.Open(*flagFromFile)
  77. if err != nil {
  78. log.Fatalf("Failed to read file '%s': %v", *flagFromFile, err)
  79. }
  80. defer func() {
  81. if err := fd.Close(); err != nil {
  82. log.Printf("Error closing file '%s': %v", *flagFromFile, err)
  83. }
  84. }()
  85. sc := bufio.NewScanner(fd)
  86. for sc.Scan() {
  87. pl := strings.TrimSpace(sc.Text())
  88. if pl == "" {
  89. continue
  90. }
  91. plugins[pl] = true
  92. }
  93. if err := sc.Err(); err != nil {
  94. log.Fatalf("Error reading file '%s': %v", *flagFromFile, err)
  95. }
  96. }
  97. if len(plugins) == 0 {
  98. log.Fatalf("No plugin specified!")
  99. }
  100. outfile := *flagOutfile
  101. if outfile == "" {
  102. tmpdir, err := ioutil.TempDir("", "coredhcp")
  103. if err != nil {
  104. log.Fatalf("Cannot create temporary directory: %v", err)
  105. }
  106. outfile = path.Join(tmpdir, "coredhcp.go")
  107. }
  108. log.Printf("Generating output file '%s' with %d plugin(s):", outfile, len(plugins))
  109. idx := 1
  110. for pl := range plugins {
  111. log.Printf("% 3d) %s", idx, pl)
  112. idx++
  113. }
  114. outFD, err := os.OpenFile(outfile, os.O_CREATE|os.O_WRONLY, 0644)
  115. if err != nil {
  116. log.Fatalf("Failed to create output file '%s': %v", outfile, err)
  117. }
  118. defer func() {
  119. if err := outFD.Close(); err != nil {
  120. log.Printf("Error while closing file descriptor for '%s': %v", outfile, err)
  121. }
  122. }()
  123. // WARNING: no escaping of the provided strings is done
  124. pluginList := make([]string, 0, len(plugins))
  125. for pl := range plugins {
  126. pluginList = append(pluginList, pl)
  127. }
  128. sort.Strings(pluginList)
  129. if err := t.Execute(outFD, pluginList); err != nil {
  130. log.Fatalf("Template execution failed: %v", err)
  131. }
  132. log.Printf("Generated file '%s'. You can build it by running 'go build' in the output directory.", outfile)
  133. fmt.Println(path.Dir(outfile))
  134. }