@@ -4,54 +4,49 @@ import (
4
4
"bytes"
5
5
"context"
6
6
"fmt"
7
- "math/rand"
8
7
"os"
9
8
"os/exec"
10
9
"path/filepath"
11
- "regexp"
12
10
"strings"
13
11
"time"
14
12
15
13
"github.com/hashicorp/go-version"
16
14
"github.com/roadrunner-server/velox/v2025"
17
15
"github.com/roadrunner-server/velox/v2025/builder/templates"
16
+ "github.com/roadrunner-server/velox/v2025/plugin"
18
17
"go.uber.org/zap"
19
18
)
20
19
21
20
const (
22
21
// path to the file which should be generated from the template
23
- pluginsPath string = "/container/plugins.go"
24
- letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
25
- goModStr string = "go.mod"
26
- pluginStructureStr string = "Plugin{}"
27
- rrMainGo string = "cmd/rr/main.go"
28
- executableName string = "rr"
22
+ pluginsPath string = "/container/plugins.go"
23
+ goModStr string = "go.mod"
24
+ rrMainGo string = "cmd/rr/main.go"
25
+ executableName string = "rr"
26
+ executableNameWindows string = "rr.exe"
29
27
// cleanup pattern
30
28
cleanupPattern string = "roadrunner-server*"
31
29
ldflags string = "-X github.com/roadrunner-server/roadrunner/v2025/internal/meta.version=%s -X github.com/roadrunner-server/roadrunner/v2025/internal/meta.buildTime=%s"
32
30
)
33
31
34
- var replaceRegexp = regexp .MustCompile ("(\t | )(.+) => (.+)" )
35
-
36
32
type Builder struct {
37
33
// rrTempPath - path, where RR was saved
38
34
rrTempPath string
39
35
// outputDir - output directory
40
36
outputDir string
41
- modules []* velox.ModulesInfo
42
37
log * zap.Logger
43
38
sb * strings.Builder
39
+ plugins []* plugin.Plugin
44
40
debug bool
45
41
rrVersion string
46
42
goos string
47
43
goarch string
48
44
}
49
45
50
46
// NewBuilder creates a new Builder with the given required parameters and optional configuration
51
- func NewBuilder (rrTmpPath string , modules [] * velox. ModulesInfo , opts ... Option ) * Builder {
47
+ func NewBuilder (rrTmpPath string , opts ... Option ) * Builder {
52
48
b := & Builder {
53
49
rrTempPath : rrTmpPath ,
54
- modules : modules ,
55
50
}
56
51
57
52
// Apply all options
@@ -63,64 +58,47 @@ func NewBuilder(rrTmpPath string, modules []*velox.ModulesInfo, opts ...Option)
63
58
}
64
59
65
60
// Build builds a RR based on the provided modules info
66
- func (b * Builder ) Build (rrModule string ) error { //nolint:gocyclo
67
- t := new (templates.Template )
68
-
69
- module , err := validateModule (rrModule )
70
- if err != nil {
71
- return err
61
+ func (b * Builder ) Build (rrRef string ) (string , error ) { //nolint:gocyclo
62
+ if len (b .plugins ) == 0 {
63
+ return "" , fmt .Errorf ("please, use WithPlugins to add plugins to the RR build" )
72
64
}
73
65
74
- t .ModuleVersion = module
75
- t .Entries = make ([]* templates.Entry , len (b .modules ))
76
- for i := range b .modules {
77
- t .Entries [i ] = & templates.Entry {
78
- Module : b .modules [i ].ModuleName ,
79
- // we need to set prefix to avoid collisions
80
- Prefix : randStringBytes (5 ),
81
- StructureName : pluginStructureStr ,
82
- PseudoVersion : b .modules [i ].PseudoVersion ,
83
- Replace : b .modules [i ].Replace ,
84
- }
66
+ t := templates .NewTemplate (b .plugins )
67
+
68
+ module , err := validateModule (rrRef )
69
+ if err != nil {
70
+ return "" , err
85
71
}
86
72
73
+ t .RRModuleVersion = module
87
74
buf := new (bytes.Buffer )
88
75
89
76
// compatibility with version 2
90
- switch t .ModuleVersion {
77
+ switch t .RRModuleVersion {
91
78
case velox .V2025 :
92
79
err = templates .CompileTemplateV2025 (buf , t )
93
80
if err != nil {
94
- return err
81
+ return "" , err
95
82
}
96
83
case velox .V2024 :
97
84
err = templates .CompileTemplateV2024 (buf , t )
98
85
if err != nil {
99
- return err
100
- }
101
- case velox .V2023 :
102
- err = templates .CompileTemplateV2023 (buf , t )
103
- if err != nil {
104
- return err
105
- }
106
- case velox .V2 :
107
- err = templates .CompileTemplateV2 (buf , t )
108
- if err != nil {
109
- return err
86
+ return "" , err
110
87
}
111
88
default :
112
- return fmt .Errorf ("unknown module version: %s" , t .ModuleVersion )
89
+ return "" , fmt .Errorf ("unknown module version: %s" , t .RRModuleVersion )
113
90
}
114
91
115
92
b .log .Debug ("template" , zap .String ("template" , buf .String ()))
116
93
117
94
f , err := os .Open (b .rrTempPath )
118
95
if err != nil {
119
- return err
96
+ return "" , err
120
97
}
121
98
defer func () {
122
99
_ = f .Close ()
123
- files , errGl := filepath .Glob (filepath .Join (os .TempDir (), cleanupPattern ))
100
+ // clean output directory, remove everything except RR binary
101
+ files , errGl := filepath .Glob (filepath .Join (b .outputDir , cleanupPattern ))
124
102
if errGl != nil {
125
103
return
126
104
}
@@ -134,77 +112,67 @@ func (b *Builder) Build(rrModule string) error { //nolint:gocyclo
134
112
// remove old plugins.go
135
113
err = os .Remove (filepath .Join (b .rrTempPath , pluginsPath ))
136
114
if err != nil {
137
- return err
115
+ return "" , err
138
116
}
139
117
140
118
err = os .WriteFile (filepath .Join (b .rrTempPath , pluginsPath ), buf .Bytes (), 0600 )
141
119
if err != nil {
142
- return err
120
+ return "" , err
143
121
}
144
122
145
123
err = os .Remove (filepath .Join (b .rrTempPath , goModStr ))
146
124
if err != nil {
147
- return err
125
+ return "" , err
148
126
}
149
127
150
128
goModFile , err := os .Create (filepath .Join (b .rrTempPath , goModStr ))
151
129
if err != nil {
152
- return err
130
+ return "" , err
153
131
}
154
132
155
133
// reuse buffer
156
134
buf .Reset ()
157
135
158
136
// compatibility with version 2
159
- switch t .ModuleVersion {
137
+ switch t .RRModuleVersion {
160
138
case velox .V2025 :
161
139
err = templates .CompileGoModTemplate2025 (buf , t )
162
140
if err != nil {
163
- return err
141
+ return "" , err
164
142
}
165
143
case velox .V2024 :
166
144
err = templates .CompileGoModTemplate2024 (buf , t )
167
145
if err != nil {
168
- return err
169
- }
170
- case velox .V2023 :
171
- err = templates .CompileGoModTemplate2023 (buf , t )
172
- if err != nil {
173
- return err
174
- }
175
- case velox .V2 :
176
- err = templates .CompileGoModTemplateV2 (buf , t )
177
- if err != nil {
178
- return err
146
+ return "" , err
179
147
}
180
148
default :
181
- return fmt .Errorf ("unknown module version: %s" , t .ModuleVersion )
149
+ return "" , fmt .Errorf ("unknown module version: %s" , t .RRModuleVersion )
182
150
}
183
151
184
152
b .log .Debug ("template" , zap .String ("template" , buf .String ()))
185
153
186
154
_ , err = goModFile .Write (buf .Bytes ())
187
155
if err != nil {
188
- return err
156
+ return "" , err
189
157
}
190
158
191
159
// reuse buffer
192
160
buf .Reset ()
193
161
194
162
err = b .exec ([]string {"go" , "mod" , "download" })
195
163
if err != nil {
196
- return err
164
+ return "" , err
197
165
}
198
166
199
167
err = b .exec ([]string {"go" , "mod" , "tidy" })
200
168
if err != nil {
201
- return err
169
+ return "" , err
202
170
}
203
171
204
172
b .log .Info ("creating output directory" , zap .String ("dir" , b .outputDir ))
205
173
_ , err = os .Stat (b .outputDir )
206
174
if err != nil && ! os .IsNotExist (err ) {
207
- return fmt .Errorf ("stat failed for output directory %s: %w" , b .outputDir , err )
175
+ return "" , fmt .Errorf ("stat failed for output directory %s: %w" , b .outputDir , err )
208
176
}
209
177
210
178
if os .IsExist (err ) {
@@ -214,22 +182,24 @@ func (b *Builder) Build(rrModule string) error { //nolint:gocyclo
214
182
215
183
err = os .MkdirAll (b .outputDir , os .ModeDir | os .ModePerm )
216
184
if err != nil {
217
- return err
185
+ return "" , err
218
186
}
219
187
220
188
// INFO: we can get go envs via go env GOOS for example, but instead we will set them manually
221
- err = b .goBuildCmd (filepath .Join (b .rrTempPath , executableName ))
189
+ err = b .goBuildCmd (filepath .Join (b .rrTempPath , generateExecutableName ( b . goos ) ))
222
190
if err != nil {
223
- return err
191
+ return "" , err
224
192
}
225
193
226
- b .log .Info ("moving binary" , zap .String ("file" , filepath .Join (b .rrTempPath , executableName )), zap .String ("to" , filepath .Join (b .outputDir , executableName )))
227
- err = moveFile (filepath .Join (b .rrTempPath , executableName ), filepath .Join (b .outputDir , executableName ))
194
+ // move the binary to the output directory
195
+ binaryPath := filepath .Join (b .outputDir , generateExecutableName (b .goos ))
196
+ b .log .Info ("moving binary" , zap .String ("file" , filepath .Join (b .rrTempPath , generateExecutableName (b .goos ))), zap .String ("to" , binaryPath ))
197
+ err = moveFile (filepath .Join (b .rrTempPath , generateExecutableName (b .goos )), binaryPath )
228
198
if err != nil {
229
- return err
199
+ return "" , err
230
200
}
231
201
232
- return nil
202
+ return binaryPath , nil
233
203
}
234
204
235
205
func (b * Builder ) Write (d []byte ) (int , error ) {
@@ -256,14 +226,6 @@ func validateModule(module string) (string, error) {
256
226
return fmt .Sprintf ("v%d" , v .Segments ()[0 ]), nil
257
227
}
258
228
259
- func randStringBytes (n int ) string {
260
- b := make ([]byte , n )
261
- for i := range b {
262
- b [i ] = letterBytes [rand .Intn (len (letterBytes ))] //nolint:gosec
263
- }
264
- return string (b )
265
- }
266
-
267
229
func (b * Builder ) goBuildCmd (outputPath string ) error {
268
230
var cmd * exec.Cmd
269
231
@@ -346,38 +308,6 @@ func (b *Builder) exec(cmd []string) error {
346
308
return nil
347
309
}
348
310
349
- func (b * Builder ) getDepsReplace (repl string ) []* templates.Entry {
350
- b .log .Info ("found replace, processing" , zap .String ("dependency" , repl ))
351
- modFile , err := os .ReadFile (filepath .Join (repl , goModStr ))
352
- if err != nil {
353
- return nil
354
- }
355
-
356
- var result []* templates.Entry //nolint:prealloc
357
- replaces := replaceRegexp .FindAllStringSubmatch (string (modFile ), - 1 )
358
- for i := range replaces {
359
- split := strings .Split (strings .TrimSpace (replaces [i ][0 ]), " => " )
360
- if len (split ) != 2 {
361
- b .log .Error ("not enough split args" , zap .String ("replace" , replaces [i ][0 ]))
362
- continue
363
- }
364
-
365
- moduleName := split [0 ]
366
- moduleReplace := split [1 ]
367
-
368
- if strings .HasPrefix (moduleReplace , "." ) {
369
- moduleReplace = filepath .Join (repl , moduleReplace )
370
- }
371
-
372
- result = append (result , & templates.Entry {
373
- Module : moduleName ,
374
- Replace : moduleReplace ,
375
- })
376
- }
377
-
378
- return result
379
- }
380
-
381
311
func moveFile (from , to string ) error {
382
312
ffInfo , err := os .Stat (from )
383
313
if err != nil {
@@ -406,3 +336,11 @@ func moveFile(from, to string) error {
406
336
407
337
return toFile .Close ()
408
338
}
339
+
340
+ // for Windows we should use .exe pattern
341
+ func generateExecutableName (goos string ) string {
342
+ if strings .ToLower (goos ) == "windows" {
343
+ return executableNameWindows
344
+ }
345
+ return executableName
346
+ }
0 commit comments