Skip to content

Commit 5a43e9f

Browse files
authored
feat: make frankenphp directive optional in Caddyfile (#1601)
* make frankenphp directive optional, thanks @francislavoie * get rid of global variable * update workers when adding to app * suggestions * goto instead of continue outer? * remove empty frankenphp directives * update config to reflect the optional frankenphp directive * AI translations * restore eol newlines * don't double check for duplicate worker name * add short form for php_server worker too * translations * AI hates EOL newlines now? * suggestion to check for nil * suggestion to use else if block
1 parent 5542044 commit 5a43e9f

9 files changed

Lines changed: 170 additions & 221 deletions

File tree

caddy/admin_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,6 @@ func TestAddModuleWorkerViaAdminApi(t *testing.T) {
225225
skip_install_trust
226226
admin localhost:2999
227227
http_port `+testPort+`
228-
229-
frankenphp
230228
}
231229
232230
localhost:`+testPort+` {
@@ -252,8 +250,6 @@ func TestAddModuleWorkerViaAdminApi(t *testing.T) {
252250
skip_install_trust
253251
admin localhost:2999
254252
http_port ` + testPort + `
255-
256-
frankenphp
257253
}
258254
259255
localhost:` + testPort + ` {

caddy/caddy.go

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ const (
3333

3434
var iniError = errors.New("'php_ini' must be in the format: php_ini \"<key>\" \"<value>\"")
3535

36-
// FrankenPHPModule instances register their workers, and FrankenPHPApp reads them at Start() time.
37-
// FrankenPHPApp.Workers may be set by JSON config, so keep them separate.
38-
var moduleWorkerConfigs []workerConfig
39-
4036
func init() {
4137
caddy.RegisterModule(FrankenPHPApp{})
4238
caddy.RegisterModule(FrankenPHPModule{})
@@ -104,6 +100,40 @@ func (f *FrankenPHPApp) Provision(ctx caddy.Context) error {
104100
return nil
105101
}
106102

103+
func (f *FrankenPHPApp) generateUniqueModuleWorkerName(filepath string) string {
104+
var i uint
105+
filepath, _ = fastabs.FastAbs(filepath)
106+
name := "m#" + filepath
107+
108+
retry:
109+
for _, wc := range f.Workers {
110+
if wc.Name == name {
111+
name = fmt.Sprintf("m#%s_%d", filepath, i)
112+
i++
113+
114+
goto retry
115+
}
116+
}
117+
118+
return name
119+
}
120+
121+
func (f *FrankenPHPApp) addModuleWorkers(workers ...workerConfig) ([]workerConfig, error) {
122+
for i := range workers {
123+
w := &workers[i]
124+
if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(w.FileName) {
125+
w.FileName = filepath.Join(frankenphp.EmbeddedAppPath, w.FileName)
126+
}
127+
if w.Name == "" {
128+
w.Name = f.generateUniqueModuleWorkerName(w.FileName)
129+
} else if !strings.HasPrefix(w.Name, "m#") {
130+
w.Name = "m#" + w.Name
131+
}
132+
f.Workers = append(f.Workers, *w)
133+
}
134+
return workers, nil
135+
}
136+
107137
func (f *FrankenPHPApp) Start() error {
108138
repl := caddy.NewReplacer()
109139

@@ -115,9 +145,7 @@ func (f *FrankenPHPApp) Start() error {
115145
frankenphp.WithPhpIni(f.PhpIni),
116146
frankenphp.WithMaxWaitTime(f.MaxWaitTime),
117147
}
118-
// Add workers from FrankenPHPApp and FrankenPHPModule configurations
119-
// f.Workers may have been set by JSON config, so keep them separate
120-
for _, w := range append(f.Workers, moduleWorkerConfigs...) {
148+
for _, w := range append(f.Workers) {
121149
opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch))
122150
}
123151

@@ -143,7 +171,6 @@ func (f *FrankenPHPApp) Stop() error {
143171
f.Workers = nil
144172
f.NumThreads = 0
145173
f.MaxWaitTime = 0
146-
moduleWorkerConfigs = nil
147174

148175
return nil
149176
}
@@ -383,6 +410,23 @@ func (FrankenPHPModule) CaddyModule() caddy.ModuleInfo {
383410
// Provision sets up the module.
384411
func (f *FrankenPHPModule) Provision(ctx caddy.Context) error {
385412
f.logger = ctx.Slogger()
413+
app, err := ctx.App("frankenphp")
414+
if err != nil {
415+
return err
416+
}
417+
fapp, ok := app.(*FrankenPHPApp)
418+
if !ok {
419+
return fmt.Errorf(`expected ctx.App("frankenphp") to return *FrankenPHPApp, got %T`, app)
420+
}
421+
if fapp == nil {
422+
return fmt.Errorf(`expected ctx.App("frankenphp") to return *FrankenPHPApp, got nil`)
423+
}
424+
425+
workers, err := fapp.addModuleWorkers(f.Workers...)
426+
if err != nil {
427+
return err
428+
}
429+
f.Workers = workers
386430

387431
if f.Root == "" {
388432
if frankenphp.EmbeddedAppPath == "" {
@@ -496,25 +540,6 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c
496540
return nil
497541
}
498542

499-
func generateUniqueModuleWorkerName(filepath string) string {
500-
var i uint
501-
name := "m#" + filepath
502-
503-
outer:
504-
for {
505-
for _, wc := range moduleWorkerConfigs {
506-
if wc.Name == name {
507-
name = fmt.Sprintf("m#%s_%d", filepath, i)
508-
i++
509-
510-
continue outer
511-
}
512-
}
513-
514-
return name
515-
}
516-
}
517-
518543
// UnmarshalCaddyfile implements caddyfile.Unmarshaler.
519544
func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
520545
// First pass: Parse all directives except "worker"
@@ -600,28 +625,14 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
600625
}
601626
}
602627

603-
if wc.Name == "" {
604-
wc.Name = generateUniqueModuleWorkerName(wc.FileName)
605-
}
606-
if !strings.HasPrefix(wc.Name, "m#") {
607-
wc.Name = "m#" + wc.Name
608-
}
609-
610628
// Check if a worker with this filename already exists in this module
611629
for _, existingWorker := range f.Workers {
612630
if existingWorker.FileName == wc.FileName {
613631
return fmt.Errorf(`workers in a single "php_server" block must not have duplicate filenames: %q`, wc.FileName)
614632
}
615633
}
616-
// Check if a worker with this name and a different environment or filename already exists
617-
for _, existingWorker := range moduleWorkerConfigs {
618-
if existingWorker.Name == wc.Name {
619-
return fmt.Errorf("workers must not have duplicate names: %q", wc.Name)
620-
}
621-
}
622634

623635
f.Workers = append(f.Workers, wc)
624-
moduleWorkerConfigs = append(moduleWorkerConfigs, wc)
625636
}
626637
}
627638
}

caddy/caddy_test.go

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@ func TestPHP(t *testing.T) {
3131
admin localhost:2999
3232
http_port `+testPort+`
3333
https_port 9443
34-
35-
frankenphp
3634
}
3735
3836
localhost:`+testPort+` {
@@ -63,8 +61,6 @@ func TestLargeRequest(t *testing.T) {
6361
admin localhost:2999
6462
http_port `+testPort+`
6563
https_port 9443
66-
67-
frankenphp
6864
}
6965
7066
localhost:`+testPort+` {
@@ -182,8 +178,6 @@ func TestNamedModuleWorkers(t *testing.T) {
182178
{
183179
skip_install_trust
184180
admin localhost:2999
185-
186-
frankenphp
187181
}
188182
189183
http://localhost:`+testPort+` {
@@ -383,8 +377,6 @@ func TestPHPServerDirective(t *testing.T) {
383377
admin localhost:2999
384378
http_port `+testPort+`
385379
https_port 9443
386-
387-
frankenphp
388380
}
389381
390382
localhost:`+testPort+` {
@@ -406,8 +398,6 @@ func TestPHPServerDirectiveDisableFileServer(t *testing.T) {
406398
admin localhost:2999
407399
http_port `+testPort+`
408400
https_port 9443
409-
410-
frankenphp
411401
order php_server before respond
412402
}
413403
@@ -434,8 +424,6 @@ func TestMetrics(t *testing.T) {
434424
http_port `+testPort+`
435425
https_port 9443
436426
metrics
437-
438-
frankenphp
439427
}
440428
441429
localhost:`+testPort+` {
@@ -800,7 +788,6 @@ func TestAllDefinedServerVars(t *testing.T) {
800788
skip_install_trust
801789
admin localhost:2999
802790
http_port `+testPort+`
803-
frankenphp
804791
}
805792
localhost:`+testPort+` {
806793
route {

caddy/config_test.go

Lines changed: 15 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ import (
77
"github.com/stretchr/testify/require"
88
)
99

10-
// resetModuleWorkers resets the moduleWorkerConfigs slice for testing
11-
func resetModuleWorkers() {
12-
moduleWorkerConfigs = make([]workerConfig, 0)
13-
}
14-
1510
func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) {
1611
// Create a test configuration with duplicate worker filenames
1712
configWithDuplicateFilenames := `
@@ -38,53 +33,6 @@ func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) {
3833
// Verify that an error was returned
3934
require.Error(t, err, "Expected an error when two workers in the same module have the same filename")
4035
require.Contains(t, err.Error(), "must not have duplicate filenames", "Error message should mention duplicate filenames")
41-
resetModuleWorkers()
42-
}
43-
44-
func TestModuleWorkersDuplicateNameFail(t *testing.T) {
45-
// Create a test configuration with a worker name
46-
configWithWorkerName1 := `
47-
{
48-
php_server {
49-
worker {
50-
name test-worker
51-
file ../testdata/worker-with-env.php
52-
num 1
53-
}
54-
}
55-
}`
56-
57-
// Parse the first configuration
58-
d1 := caddyfile.NewTestDispenser(configWithWorkerName1)
59-
module1 := &FrankenPHPModule{}
60-
61-
// Unmarshal the first configuration
62-
err := module1.UnmarshalCaddyfile(d1)
63-
require.NoError(t, err, "First module should be configured without errors")
64-
65-
// Create a second test configuration with the same worker name
66-
configWithWorkerName2 := `
67-
{
68-
php_server {
69-
worker {
70-
name test-worker
71-
file ../testdata/worker-with-env.php
72-
num 1
73-
}
74-
}
75-
}`
76-
77-
// Parse the second configuration
78-
d2 := caddyfile.NewTestDispenser(configWithWorkerName2)
79-
module2 := &FrankenPHPModule{}
80-
81-
// Unmarshal the second configuration
82-
err = module2.UnmarshalCaddyfile(d2)
83-
84-
// Verify that an error was returned
85-
require.Error(t, err, "Expected an error when two workers have the same name, but different environments")
86-
require.Contains(t, err.Error(), "must not have duplicate names", "Error message should mention duplicate names")
87-
resetModuleWorkers()
8836
}
8937

9038
func TestModuleWorkersWithDifferentFilenames(t *testing.T) {
@@ -111,8 +59,6 @@ func TestModuleWorkersWithDifferentFilenames(t *testing.T) {
11159
require.Len(t, module.Workers, 2, "Expected two workers to be added to the module")
11260
require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "First worker should have the correct filename")
11361
require.Equal(t, "../testdata/worker-with-counter.php", module.Workers[1].FileName, "Second worker should have the correct filename")
114-
115-
resetModuleWorkers()
11662
}
11763

11864
func TestModuleWorkersDifferentNamesSucceed(t *testing.T) {
@@ -130,6 +76,7 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) {
13076

13177
// Parse the first configuration
13278
d1 := caddyfile.NewTestDispenser(configWithWorkerName1)
79+
app := &FrankenPHPApp{}
13380
module1 := &FrankenPHPModule{}
13481

13582
// Unmarshal the first configuration
@@ -158,12 +105,15 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) {
158105
// Verify that no error was returned
159106
require.NoError(t, err, "Expected no error when two workers have different names")
160107

161-
// Verify that both workers were added to moduleWorkerConfigs
162-
require.Len(t, moduleWorkerConfigs, 2, "Expected two workers to be added to moduleWorkerConfigs")
163-
require.Equal(t, "m#test-worker-1", moduleWorkerConfigs[0].Name, "First worker should have the correct name")
164-
require.Equal(t, "m#test-worker-2", moduleWorkerConfigs[1].Name, "Second worker should have the correct name")
108+
_, err = app.addModuleWorkers(module1.Workers...)
109+
require.NoError(t, err, "Expected no error when adding the first module workers")
110+
_, err = app.addModuleWorkers(module2.Workers...)
111+
require.NoError(t, err, "Expected no error when adding the second module workers")
165112

166-
resetModuleWorkers()
113+
// Verify that both workers were added
114+
require.Len(t, app.Workers, 2, "Expected two workers in the app")
115+
require.Equal(t, "m#test-worker-1", app.Workers[0].Name, "First worker should have the correct name")
116+
require.Equal(t, "m#test-worker-2", app.Workers[1].Name, "Second worker should have the correct name")
167117
}
168118

169119
func TestModuleWorkerWithEnvironmentVariables(t *testing.T) {
@@ -198,8 +148,6 @@ func TestModuleWorkerWithEnvironmentVariables(t *testing.T) {
198148
require.Len(t, module.Workers[0].Env, 2, "Expected two environment variables")
199149
require.Equal(t, "production", module.Workers[0].Env["APP_ENV"], "APP_ENV should be set to production")
200150
require.Equal(t, "true", module.Workers[0].Env["DEBUG"], "DEBUG should be set to true")
201-
202-
resetModuleWorkers()
203151
}
204152

205153
func TestModuleWorkerWithWatchConfiguration(t *testing.T) {
@@ -236,8 +184,6 @@ func TestModuleWorkerWithWatchConfiguration(t *testing.T) {
236184
require.Equal(t, "./**/*.{php,yaml,yml,twig,env}", module.Workers[0].Watch[0], "First watch pattern should be the default")
237185
require.Equal(t, "./src/**/*.php", module.Workers[0].Watch[1], "Second watch pattern should match the configuration")
238186
require.Equal(t, "./config/**/*.yaml", module.Workers[0].Watch[2], "Third watch pattern should match the configuration")
239-
240-
resetModuleWorkers()
241187
}
242188

243189
func TestModuleWorkerWithCustomName(t *testing.T) {
@@ -256,6 +202,7 @@ func TestModuleWorkerWithCustomName(t *testing.T) {
256202
// Parse the configuration
257203
d := caddyfile.NewTestDispenser(configWithCustomName)
258204
module := &FrankenPHPModule{}
205+
app := &FrankenPHPApp{}
259206

260207
// Unmarshal the configuration
261208
err := module.UnmarshalCaddyfile(d)
@@ -267,8 +214,9 @@ func TestModuleWorkerWithCustomName(t *testing.T) {
267214
require.Len(t, module.Workers, 1, "Expected one worker to be added to the module")
268215
require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename")
269216

270-
// Verify that the worker was added to moduleWorkerConfigs with the m# prefix
271-
require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name")
272-
273-
resetModuleWorkers()
217+
// Verify that the worker was added to app.Workers with the m# prefix
218+
module.Workers, err = app.addModuleWorkers(module.Workers...)
219+
require.NoError(t, err, "Expected no error when adding the worker to the app")
220+
require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name, prefixed with m#")
221+
require.Equal(t, "m#custom-worker-name", app.Workers[0].Name, "Worker should have the custom name, prefixed with m#")
274222
}

0 commit comments

Comments
 (0)