فهرست منبع

Add hercules-plugin-generate command

Vadim Markovtsev 7 سال پیش
والد
کامیت
5bee53ccd8
7فایلهای تغییر یافته به همراه157 افزوده شده و 7 حذف شده
  1. 2 0
      .gitignore
  2. 2 0
      .travis.yml
  3. 9 3
      Makefile
  4. 1 4
      README.md
  5. 25 0
      cmd/hercules-generate-plugin/embed.go
  6. 59 0
      cmd/hercules-generate-plugin/main.go
  7. 59 0
      cmd/hercules-generate-plugin/plugin.template

+ 2 - 0
.gitignore

@@ -1,3 +1,5 @@
+cmd/hercules-generate-plugin/plugin_template_source.go
+
 **/.DS_Store
 .idea
 

+ 2 - 0
.travis.yml

@@ -37,6 +37,8 @@ script:
   - $GOPATH/bin/hercules -version
   - $GOPATH/bin/hercules -burndown -burndown-files -burndown-people -couples -quiet https://github.com/src-d/hercules | python3 labours.py -m all -o out --backend Agg --disable-projector
   - $GOPATH/bin/hercules -burndown -burndown-files -burndown-people -couples -quiet -pb https://github.com/src-d/hercules | python3 labours.py -f pb -m all -o out --backend Agg --disable-projector
+  - $GOPATH/bin/hercules-generate-plugin -version
+  - $GOPATH/bin/hercules-generate-plugin -n MyTest && test -e my_test.go
 
 after_success:
   - bash <(curl -s https://codecov.io/bash)

+ 9 - 3
Makefile

@@ -2,12 +2,16 @@ ifneq (oneshell, $(findstring oneshell, $(.FEATURES)))
   $(error GNU make 3.82 or later is required)
 endif
 
-all: dependencies ${GOPATH}/bin/hercules
+all: dependencies ${GOPATH}/bin/hercules ${GOPATH}/bin/hercules-generate-plugin
 
 test: all
 	go test gopkg.in/src-d/hercules.v3
 
-dependencies: ${GOPATH}/src/gopkg.in/bblfsh/client-go.v2
+dependencies: ${GOPATH}/src/gopkg.in/bblfsh/client-go.v2 ${GOPATH}/src/gopkg.in/src-d/hercules.v3
+	cd ${GOPATH}/src/gopkg.in/src-d/hercules.v3/cmd/hercules-generate-plugin && go generate
+
+${GOPATH}/src/gopkg.in/src-d/hercules.v3:
+	go get -d gopkg.in/src-d/hercules.v3/...
 
 .ONESHELL:
 ${GOPATH}/src/gopkg.in/bblfsh/client-go.v2:
@@ -19,4 +23,6 @@ ${GOPATH}/src/gopkg.in/bblfsh/client-go.v2:
 ${GOPATH}/bin/hercules: *.go cmd/hercules/*.go rbtree/*.go stdout/*.go toposort/*.go pb/*.go
 	cd ${GOPATH}/src/gopkg.in/src-d/hercules.v3
 	go get -ldflags "-X gopkg.in/src-d/hercules.v3.GIT_HASH=$$(git rev-parse HEAD)" gopkg.in/src-d/hercules.v3/cmd/hercules
-	${GOPATH}/bin/hercules -version
+
+${GOPATH}/bin/hercules-generate-plugin: cmd/hercules-generate-plugin/*.go ${GOPATH}/bin/hercules
+	go get -ldflags "-X gopkg.in/src-d/hercules.v3.GIT_HASH=$$(git rev-parse HEAD)" gopkg.in/src-d/hercules.v3/cmd/hercules-generate-plugin

+ 1 - 4
README.md

@@ -25,14 +25,11 @@ There is a [presentation](http://vmarkovtsev.github.io/techtalks-2017-moscow-lig
 ### Installation
 You are going to need Go (>= v1.8) and Python 2 or 3.
 ```
-go get gopkg.in/src-d/hercules.v3/cmd/hercules
+go get -d gopkg.in/src-d/hercules.v3/cmd/hercules
 cd $GOPATH/src/gopkg.in/hercules.v3/cmd/hercules
 make
 ```
 
-The first command fails with `libuast.h` not found - this is expected. Pretend that nothing has
-happened and carry on.
-
 #### Windows
 Numpy and SciPy are requirements. Install the correct version by downloading the wheel from http://www.lfd.uci.edu/~gohlke/pythonlibs/#scipy.
 Couples analysis also needs Tensorflow.

+ 25 - 0
cmd/hercules-generate-plugin/embed.go

@@ -0,0 +1,25 @@
+// +build ignore
+
+package main
+
+import (
+	"io/ioutil"
+	"os"
+	"text/template"
+)
+
+func main() {
+  contents, err := ioutil.ReadFile("plugin.template")
+	if err != nil {
+		panic(err)
+	}
+	template.Must(template.New("plugin").Parse(string(contents)))
+	file, err := os.Create("plugin_template_source.go")
+	if err != nil {
+		panic(err)
+	}
+	defer file.Close()
+	file.WriteString("package main\n\nconst PLUGIN_TEMPLATE_SOURCE = `")
+	file.Write(contents)
+	file.WriteString("`\n")
+}

+ 59 - 0
cmd/hercules-generate-plugin/main.go

@@ -0,0 +1,59 @@
+package main
+
+import (
+  "flag"
+  "fmt"
+  "os"
+  "strings"
+  "text/template"
+
+  "gopkg.in/src-d/hercules.v3"
+  "github.com/fatih/camelcase"
+)
+
+//go:generate go run embed.go
+
+func main() {
+  var outputPath, name, varname, _flag, pkg string
+  var printVersion bool
+  flag.StringVar(&name, "n", "", "Name of the plugin, CamelCase. Required.")
+  flag.StringVar(&outputPath, "o", "", "Output path of the generated plugin code. If not " +
+      "specified, inferred from -n.")
+  flag.StringVar(&varname, "varname", "", "Name of the plugin instance variable, If not " +
+      "specified, inferred from -n.")
+  flag.StringVar(&_flag, "flag", "", "Name of the plugin activation cmdline flag, If not " +
+      "specified, inferred from -varname.")
+  flag.BoolVar(&printVersion, "version", false, "Print version information and exit.")
+  flag.StringVar(&pkg, "package", "contrib", "Name of the package.")
+  flag.Parse()
+  if printVersion {
+		fmt.Printf("Version: 3\nGit:     %s\n", hercules.GIT_HASH)
+		return
+	}
+  if name == "" {
+    fmt.Fprintln(os.Stderr, "-n must be specified")
+    flag.PrintDefaults()
+    os.Exit(1)
+  }
+  splitted := camelcase.Split(name)
+  if outputPath == "" {
+    outputPath = strings.ToLower(strings.Join(splitted, "_")) + ".go"
+  }
+  gen := template.Must(template.New("plugin").Parse(PLUGIN_TEMPLATE_SOURCE))
+  outFile, err := os.Create(outputPath)
+  if err != nil {
+    panic(err)
+  }
+  defer outFile.Close()
+  if varname == "" {
+    varname = strings.ToLower(splitted[0])
+  }
+  if _flag == "" {
+    _flag = varname
+  }
+  dict := map[string]string{"name": name, "varname": varname, "flag": _flag, "package": pkg}
+  err = gen.Execute(outFile, dict)
+  if err != nil {
+    panic(err)
+  }
+}

+ 59 - 0
cmd/hercules-generate-plugin/plugin.template

@@ -0,0 +1,59 @@
+package {{.package}}
+
+import (
+  "gopkg.in/src-d/go-git.v4"
+  "gopkg.in/src-d/hercules.v3"
+)
+
+// {{.name}} contains the intermediate state which is mutated by Consume(). It should implement
+// hercules.LeafPipelineItem.
+type {{.name}} struct {
+}
+
+// {{.name}}Result is returned by Finalize() and represents the analysis result.
+type {{.name}}Result struct {
+}
+
+// Analysis' name in the graph is usually the same as the type's name, however, does not have to.
+func ({{.varname}} *{{.name}}) Name() string {
+	return "{{.name}}"
+}
+
+// LeafPipelineItem-s normally do not act as intermediate nodes and thus we return an empty slice.
+func ({{.varname}} *{{.name}}) Provides() []string {
+	return []string{}
+}
+
+// Requires returns the list of dependencies which must be supplied in Consume().
+func ({{.varname}} *{{.name}}) Requires() []string {
+	arr := [...]string{/* insert dependencies here */}
+	return arr[:]
+}
+
+func ({{.varname}} *{{.name}}) ListConfigurationOptions() []hercules.ConfigurationOption {
+	return []hercules.ConfigurationOption{}
+}
+
+func ({{.varname}} *{{.name}}) Flag() string {
+	return "{{.flag}}"
+}
+
+func ({{.varname}} *{{.name}}) Configure(facts map[string]interface{}) {
+}
+
+func ({{.varname}} *{{.name}}) Initialize(repository *git.Repository) {
+}
+
+func ({{.varname}} *{{.name}}) Consume(deps map[string]interface{}) (map[string]interface{}, error) {
+	return nil, nil
+}
+
+func ({{.varname}} *{{.name}}) Finalize() interface{} {
+  result := {{.name}}Result{}
+  // insert code here
+  return result
+}
+
+func init() {
+	hercules.Registry.Register(&{{.name}}{})
+}