main.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package main
  2. import (
  3. "bytes"
  4. "flag"
  5. "fmt"
  6. "io/ioutil"
  7. "os"
  8. "os/exec"
  9. "path"
  10. "runtime"
  11. "strings"
  12. "text/template"
  13. "github.com/fatih/camelcase"
  14. "gopkg.in/src-d/hercules.v3"
  15. )
  16. //go:generate go run embed.go
  17. var SHLIB_EXT = map[string]string{
  18. "window": "dll",
  19. "linux": "so",
  20. "darwin": "dylib",
  21. "freebsd": "dylib",
  22. }
  23. func main() {
  24. var outputDir, name, varname, _flag, pkg string
  25. var printVersion, disableMakefile bool
  26. flag.StringVar(&name, "n", "", "Name of the plugin, CamelCase. Required.")
  27. flag.StringVar(&outputDir, "o", ".", "Output directory for the generated plugin files.")
  28. flag.StringVar(&varname, "varname", "", "Name of the plugin instance variable, If not "+
  29. "specified, inferred from -n.")
  30. flag.StringVar(&_flag, "flag", "", "Name of the plugin activation cmdline flag, If not "+
  31. "specified, inferred from -varname.")
  32. flag.BoolVar(&printVersion, "version", false, "Print version information and exit.")
  33. flag.BoolVar(&disableMakefile, "no-makefile", false, "Do not generate the Makefile.")
  34. flag.StringVar(&pkg, "package", "main", "Name of the package.")
  35. flag.Parse()
  36. if printVersion {
  37. fmt.Printf("Version: 3\nGit: %s\n", hercules.GIT_HASH)
  38. return
  39. }
  40. if name == "" {
  41. fmt.Fprintln(os.Stderr, "-n must be specified")
  42. flag.PrintDefaults()
  43. os.Exit(1)
  44. }
  45. splitted := camelcase.Split(name)
  46. err := os.MkdirAll(outputDir, os.ModePerm)
  47. if err != nil {
  48. panic(err)
  49. }
  50. outputPath := path.Join(outputDir, strings.ToLower(strings.Join(splitted, "_"))+".go")
  51. gen := template.Must(template.New("plugin").Parse(PLUGIN_TEMPLATE_SOURCE))
  52. outFile, err := os.Create(outputPath)
  53. if err != nil {
  54. panic(err)
  55. }
  56. defer outFile.Close()
  57. if varname == "" {
  58. varname = strings.ToLower(splitted[0])
  59. }
  60. if _flag == "" {
  61. _flag = strings.ToLower(strings.Join(splitted, "-"))
  62. }
  63. outputBase := path.Base(outputPath)
  64. shlib := outputBase[:len(outputBase)-2] + SHLIB_EXT[runtime.GOOS]
  65. protoBuf := outputPath[:len(outputPath)-3] + ".proto"
  66. pbGo := outputPath[:len(outputPath)-3] + ".pb.go"
  67. dict := map[string]string{
  68. "name": name, "varname": varname, "flag": _flag, "package": pkg,
  69. "output": outputPath, "shlib": shlib, "proto": protoBuf, "protogo": pbGo,
  70. "outdir": outputDir}
  71. err = gen.Execute(outFile, dict)
  72. if err != nil {
  73. panic(err)
  74. }
  75. // write pb file
  76. ioutil.WriteFile(protoBuf, []byte(fmt.Sprintf(`syntax = "proto3";
  77. option go_package = "%s";
  78. message %sResultMessage {
  79. // add fields here
  80. // reference: https://developers.google.com/protocol-buffers/docs/proto3
  81. // example: pb/pb.proto https://github.com/src-d/hercules/blob/master/pb/pb.proto
  82. }
  83. `, pkg, name)), 0666)
  84. // generate the pb Go file
  85. protoc, err := exec.LookPath("protoc")
  86. args := [...]string{
  87. protoc,
  88. "--gogo_out=" + outputDir,
  89. "--proto_path=" + outputDir,
  90. protoBuf,
  91. }
  92. env := os.Environ()
  93. env = append(env, fmt.Sprintf(
  94. "PATH=%s:%s", os.Getenv("PATH"), path.Join(os.Getenv("GOPATH"), "bin")))
  95. if err != nil {
  96. panic("protoc was not found at " + env[len(env)-1])
  97. }
  98. cmd := exec.Cmd{Path: protoc, Args: args[:], Env: env, Stdout: os.Stdout, Stderr: os.Stderr}
  99. err = cmd.Run()
  100. if err != nil {
  101. panic(err)
  102. }
  103. if !disableMakefile {
  104. makefile := path.Join(outputDir, "Makefile")
  105. gen = template.Must(template.New("plugin").Parse(`all: {{.shlib}}
  106. {{.shlib}}: {{.output}} {{.protogo}}
  107. ` + "\t" + `go build -buildmode=plugin {{.output}} {{.protogo}}
  108. {{.protogo}}: {{.proto}}
  109. ` + "\t" + `PATH=$$PATH:$$GOPATH/bin protoc --gogo_out=. --proto_path=. {{.proto}}
  110. `))
  111. buffer := new(bytes.Buffer)
  112. mkrelative := func(name string) {
  113. dict[name] = path.Base(dict[name])
  114. }
  115. mkrelative("output")
  116. mkrelative("protogo")
  117. mkrelative("proto")
  118. gen.Execute(buffer, dict)
  119. ioutil.WriteFile(makefile, buffer.Bytes(), 0666)
  120. }
  121. }