This repository has been archived by the owner on May 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathgo.go
153 lines (136 loc) · 3.7 KB
/
go.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package generators
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"sort"
"strings"
"github.com/pkg/errors"
"github.com/yext/edward/services"
"github.com/yext/edward/services/backends/commandline"
)
// GoGenerator generates go services from main packages
type GoGenerator struct {
generatorBase
foundServices []*services.ServiceConfig
}
// Name returns 'go' to identify this generator
func (v *GoGenerator) Name() string {
return "go"
}
// StartWalk lets a generator know that a directory walk has been started, with the
// given starting path
func (v *GoGenerator) StartWalk(path string) {
v.generatorBase.StartWalk(path)
}
// VisitDir searches a directory for .go files, and will store a service if a main
// package is detected. Returns true in the first return value if a service was found.
func (v *GoGenerator) VisitDir(path string) (bool, error) {
files, _ := ioutil.ReadDir(path)
for _, f := range files {
fPath := filepath.Join(path, f.Name())
if filepath.Ext(fPath) != ".go" {
continue
}
input, err := ioutil.ReadFile(fPath)
if err != nil {
return false, errors.WithStack(err)
}
packageExpr := regexp.MustCompile(`package main\n`)
if packageExpr.Match(input) {
packageName := filepath.Base(path)
packagePath, err := filepath.Rel(v.basePath, path)
if err != nil {
return false, errors.WithStack(err)
}
service, err := v.goService(packageName, packagePath)
if err != nil {
return false, errors.WithStack(err)
}
v.foundServices = append(v.foundServices, service)
return true, nil
}
}
return false, nil
}
// Services returns the services generated during the last walk
func (v *GoGenerator) Services() []*services.ServiceConfig {
return v.foundServices
}
func (v *GoGenerator) goService(name, packagePath string) (*services.ServiceConfig, error) {
service := &services.ServiceConfig{
Name: name,
Path: &packagePath,
Env: []string{},
Backends: []*services.BackendConfig{
{
Type: "commandline",
Config: &commandline.Backend{
Commands: commandline.ServiceConfigCommands{
Build: "go install",
Launch: name,
},
},
},
},
}
return service, nil
}
func (v *GoGenerator) createWatch(service *services.ServiceConfig) (services.ServiceWatch, error) {
return services.ServiceWatch{
Service: service,
IncludedPaths: v.getImportList(service),
}, nil
}
func (v *GoGenerator) getImportList(service *services.ServiceConfig) []string {
if service.Path == nil {
return nil
}
// Get a list of imports using 'go list'
var imports = []string{}
cmd := exec.Command("go", "list", "-f", "{{ join .Imports \":\" }}")
cmd.Dir = *service.Path
var out bytes.Buffer
var errBuf bytes.Buffer
cmd.Stderr = &errBuf
cmd.Stdout = &out
err := cmd.Run()
if err != nil {
fmt.Println("Error getting import list:", errBuf.String())
return []string{*service.Path}
}
imports = append(imports, strings.Split(out.String(), ":")...)
// Verify the import paths exist
var checkedImports = []string{*service.Path}
for _, i := range imports {
path := os.ExpandEnv(fmt.Sprintf("$GOPATH/src/%v", i))
if _, err := os.Stat(path); err == nil {
rel, err := filepath.Rel(v.basePath, path)
if err != nil {
// TODO: Handle this error more effectively
fmt.Println("Could not get relative path:", err)
continue
}
checkedImports = append(checkedImports, rel)
}
}
// Remove subpaths
sort.Strings(checkedImports)
var outImports []string
for i, path := range checkedImports {
include := true
for j, earlier := range checkedImports {
if i > j && strings.HasPrefix(path, earlier) {
include = false
}
}
if include {
outImports = append(outImports, path)
}
}
return outImports
}