-
Notifications
You must be signed in to change notification settings - Fork 221
/
scanner.go
185 lines (161 loc) · 4.55 KB
/
scanner.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package scanner
import (
"embed"
"io/fs"
"path/filepath"
"strings"
"text/template"
"github.com/pkg/errors"
)
//go:embed templates templates/*/.dockerignore templates/**/.fly
var content embed.FS
type InitCommand struct {
Command string
Args []string
Description string
Condition bool
}
type Secret struct {
Key string
Help string
Value string
Generate func() (string, error)
}
type MergeConfigStruct struct {
Name string
Temporary bool
}
type SourceInfo struct {
Family string
Version string
DockerfilePath string
BuildArgs map[string]string
Builder string
ReleaseCmd string
DockerCommand string
DockerEntrypoint string
KillSignal string
Buildpacks []string
Secrets []Secret
Files []SourceFile
Port int
Env map[string]string
Statics []Static
Processes map[string]string
DeployDocs string
Notice string
SkipDeploy bool
SkipDatabase bool
Volumes []Volume
DockerfileAppendix []string
InitCommands []InitCommand
PostgresInitCommands []InitCommand
PostgresInitCommandCondition bool
Concurrency map[string]int
Callback func(appName string, srcInfo *SourceInfo, options map[string]bool) error
HttpCheckPath string
HttpCheckHeaders map[string]string
ConsoleCommand string
MergeConfig *MergeConfigStruct
}
type SourceFile struct {
Path string
Contents []byte
}
type Static struct {
GuestPath string `toml:"guest_path" json:"guest_path"`
UrlPrefix string `toml:"url_prefix" json:"url_prefix"`
}
type Volume struct {
Source string `toml:"source" json:"source,omitempty"`
Destination string `toml:"destination" json:"destination,omitempty"`
Processes []string `json:"processes,omitempty" toml:"processes,omitempty"`
}
type ScannerConfig struct {
Mode string
ExistingPort int
}
func Scan(sourceDir string, config *ScannerConfig) (*SourceInfo, error) {
scanners := []sourceScanner{
configureDjango,
configureLaravel,
configurePhoenix,
configureRails,
configureRedwood,
configureJsFramework,
/* frameworks scanners are placed before generic scanners,
since they might mix languages or have a Dockerfile that
doesn't work with Fly */
configureDockerfile,
configureLucky,
configureRuby,
configureGo,
configureElixir,
configurePython,
configureDeno,
configureNuxt,
configureNextJs,
configureNode,
configureStatic,
configureDotnet,
}
for _, scanner := range scanners {
si, err := scanner(sourceDir, config)
if err != nil {
return nil, err
}
if si != nil {
return si, nil
}
}
return nil, nil
}
type sourceScanner func(sourceDir string, config *ScannerConfig) (*SourceInfo, error)
// templates recursively returns files from the templates directory within the named directory
// will panic on errors since these files are embedded and should work
func templates(name string) (files []SourceFile) {
filter := func(input []byte) []byte { return input }
return templatesFilter(name, filter)
}
// same thing as templates (above) but with template execution given a map of variables
func templatesExecute(name string, vars map[string]interface{}) (files []SourceFile) {
filter := func(input []byte) []byte {
template := template.Must(template.New("name").Parse(string(input)))
result := strings.Builder{}
err := template.Execute(&result, vars)
if err != nil {
panic(err)
}
return []byte(result.String())
}
return templatesFilter(name, filter)
}
// templates with a filter function applied to the content of each template
func templatesFilter(name string, filter func(input []byte) []byte) (files []SourceFile) {
err := fs.WalkDir(content, name, func(path string, d fs.DirEntry, e error) error {
if d.IsDir() {
return nil
}
relPath, err := filepath.Rel(name, path)
if err != nil {
return errors.Wrap(err, "error removing template prefix")
}
data, err := fs.ReadFile(content, path)
if err != nil {
return err
}
if err != nil {
return err
}
f := SourceFile{
Path: relPath,
Contents: filter(data),
}
files = append(files, f)
return nil
})
if err != nil {
panic(err)
}
return
}