forked from gobuffalo/buffalo
/
helpers.go
132 lines (106 loc) · 3.02 KB
/
helpers.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
package generators
import (
"errors"
"fmt"
"go/ast"
"go/parser"
"go/token"
"io/ioutil"
"strings"
)
// AddRoute adds a new route inside the `action/app.go` file.
func AddRoute(method, path, handlerName string) error {
routeDefinition := fmt.Sprintf(`app.%v("%v", %v)`, method, path, handlerName)
return AddInsideAppBlock(routeDefinition)
}
// AddInsideAppBlock will add anything inside of the app declaration block inside of `actions/app.go`
func AddInsideAppBlock(expressions ...string) error {
src, err := ioutil.ReadFile("actions/app.go")
if err != nil {
return err
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, "actions/app.go", string(src), 0)
if err != nil {
return err
}
srcContent := string(src)
fileLines := strings.Split(srcContent, "\n")
end := findClosingRouteBlockEnd(f, fset, fileLines)
if end < 0 {
return errors.New("could not find desired block on the app.go file")
}
el := fileLines[end:]
sl := []string{}
sf := []string{}
for _, l := range fileLines[:end] {
// if there's a app.ServeFiles("/", foo) line it needs to be the last added to the router
if strings.Contains(l, "ServeFiles(\"/\"") {
sf = append(sf, l)
continue
}
sl = append(sl, l)
}
for i := 0; i < len(expressions); i++ {
expressions[i] = fmt.Sprintf("\t\t%s", expressions[i])
}
el = append(sf, el...)
fileLines = append(sl, append(expressions, el...)...)
fileContent := strings.Join(fileLines, "\n")
err = ioutil.WriteFile("actions/app.go", []byte(fileContent), 0755)
return err
}
func findClosingRouteBlockEnd(f *ast.File, fset *token.FileSet, fileLines []string) int {
var end = -1
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.BlockStmt:
start := fset.Position(x.Lbrace).Line
blockDeclaration := fmt.Sprintf("%s\n", fileLines[start-1])
if strings.Contains(blockDeclaration, "if app == nil {") {
end = fset.Position(x.Rbrace).Line - 1
}
}
return true
})
return end
}
// AddImport adds n number of import statements into the path provided
func AddImport(path string, imports ...string) error {
src, err := ioutil.ReadFile(path)
if err != nil {
return err
}
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, string(src), 0)
if err != nil {
return err
}
srcContent := string(src)
fileLines := strings.Split(srcContent, "\n")
end := findLastImport(f, fset, fileLines)
x := make([]string, len(imports), len(imports)+2)
for _, i := range imports {
x = append(x, fmt.Sprintf("\t\"%s\"", i))
}
if end < 0 {
x = append([]string{"import ("}, x...)
x = append(x, ")")
}
fileLines = append(fileLines[:end], append(x, fileLines[end:]...)...)
fileContent := strings.Join(fileLines, "\n")
err = ioutil.WriteFile(path, []byte(fileContent), 0755)
return err
}
func findLastImport(f *ast.File, fset *token.FileSet, fileLines []string) int {
var end = -1
ast.Inspect(f, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.ImportSpec:
end = fset.Position(x.End()).Line
return true
}
return true
})
return end
}