github.com/sercand/please@v13.4.0+incompatible/test/go_provider/main.go (about) 1 // Package main implements a build provider for Please that understands Go files. 2 // This could be considered a base for such a thing; it is not complete in regard to 3 // all the subtleties of how Go would process them, and misses a lot of features 4 // (like useful cross-package dependencies, for example). 5 package main 6 7 import ( 8 "encoding/json" 9 "go/ast" 10 "go/parser" 11 "go/token" 12 "os" 13 "path" 14 "strings" 15 "text/template" 16 17 "gopkg.in/op/go-logging.v1" 18 ) 19 20 var log = logging.MustGetLogger("go_provider") 21 22 type Request struct { 23 Rule string `json:"rule"` 24 } 25 26 type Response struct { 27 Rule string `json:"rule"` 28 Success bool `json:"success"` 29 Messages []string `json:"messages"` 30 BuildFile string `json:"build_file"` 31 } 32 33 var tmpl = template.Must(template.New("build").Funcs(template.FuncMap{ 34 "filter": func(in map[string]*ast.File, test bool) []string { 35 ret := []string{} 36 for name := range in { 37 if strings.HasSuffix(name, "test.go") == test { 38 ret = append(ret, path.Base(name)) 39 } 40 } 41 return ret 42 }, 43 }).Parse(` 44 {{ range $pkgName, $pkg := . }} 45 go_library( 46 name = "{{ $pkgName }}", 47 srcs = [ 48 {{ range filter $pkg.Files false }} 49 "{{ . }}", 50 {{ end }} 51 ], 52 ) 53 54 {{ if filter $pkg.Files true }} 55 go_test( 56 name = "{{ $pkgName }}_test", 57 srcs = [ 58 {{ range filter $pkg.Files true }} 59 "{{ . }}", 60 {{ end }} 61 ], 62 deps = [":{{ $pkgName }}"], 63 ) 64 {{ end }} 65 {{ end }} 66 `)) 67 68 func provide(ch chan<- *Response, dir string) { 69 contents, err := parse(dir) 70 resp := &Response{ 71 Rule: dir, 72 BuildFile: contents, 73 } 74 if err != nil { 75 resp.Messages = []string{err.Error()} 76 } 77 ch <- resp 78 } 79 80 func parse(dir string) (string, error) { 81 var b strings.Builder 82 fs := token.NewFileSet() 83 pkgs, err := parser.ParseDir(fs, dir, nil, parser.ImportsOnly) 84 if err != nil { 85 return "", err 86 } else if err := tmpl.Execute(&b, pkgs); err != nil { 87 return "", err 88 } 89 return b.String(), nil 90 } 91 92 func main() { 93 decoder := json.NewDecoder(os.Stdin) 94 encoder := json.NewEncoder(os.Stdout) 95 ch := make(chan *Response, 10) 96 go func() { 97 for resp := range ch { 98 if err := encoder.Encode(resp); err != nil { 99 log.Error("Failed to encode message: %s", err) 100 } 101 } 102 }() 103 for { 104 req := &Request{} 105 if err := decoder.Decode(req); err != nil { 106 log.Error("Failed to decode incoming message: %s", err) 107 continue 108 } 109 go provide(ch, req.Rule) 110 } 111 }