Skip to content

Commit 84dae7b

Browse files
committed
add overwrite-readme flag to extension-init command
1 parent bd8f0c2 commit 84dae7b

4 files changed

Lines changed: 98 additions & 21 deletions

File tree

caddy/extinit.go

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,49 @@ package caddy
33
import (
44
"errors"
55
"log"
6-
"os"
76
"path/filepath"
87
"strings"
98

10-
"github.com/dunglas/frankenphp/internal/extgen"
11-
129
caddycmd "github.com/caddyserver/caddy/v2/cmd"
10+
"github.com/dunglas/frankenphp/internal/extgen"
1311
"github.com/spf13/cobra"
1412
)
1513

1614
func init() {
1715
caddycmd.RegisterCommand(caddycmd.Command{
1816
Name: "extension-init",
19-
Usage: "go_extension.go [--verbose]",
17+
Usage: "go_extension.go [--overwrite-readme]",
2018
Short: "Initializes a PHP extension from a Go file (EXPERIMENTAL)",
2119
Long: `
2220
Initializes a PHP extension from a Go file. This command generates the necessary C files for the extension, including the header and source files, as well as the arginfo file.`,
2321
CobraFunc: func(cmd *cobra.Command) {
24-
cmd.Flags().BoolP("debug", "v", false, "Enable verbose debug logs")
22+
cmd.Flags().BoolP("overwrite-readme", "r", false, "Overwrite README.md if it exists")
2523

26-
cmd.RunE = caddycmd.WrapCommandFuncForCobra(cmdInitExtension)
24+
cmd.RunE = cmdInitExtension
2725
},
2826
})
2927
}
3028

31-
func cmdInitExtension(_ caddycmd.Flags) (int, error) {
32-
if len(os.Args) < 3 {
33-
return 1, errors.New("the path to the Go source is required")
29+
func cmdInitExtension(cmd *cobra.Command, args []string) error {
30+
if len(args) == 0 {
31+
return errors.New("the path to the Go source is required")
32+
}
33+
34+
overwriteReadme, err := cmd.Flags().GetBool("overwrite-readme")
35+
if err != nil {
36+
return err
3437
}
3538

36-
sourceFile := os.Args[2]
39+
sourceFile := args[0]
3740
baseName := extgen.SanitizePackageName(strings.TrimSuffix(filepath.Base(sourceFile), ".go"))
3841

39-
generator := extgen.Generator{BaseName: baseName, SourceFile: sourceFile, BuildDir: filepath.Dir(sourceFile)}
42+
generator := extgen.Generator{BaseName: baseName, SourceFile: sourceFile, BuildDir: filepath.Dir(sourceFile), OverwriteReadme: overwriteReadme}
4043

4144
if err := generator.Generate(); err != nil {
42-
return 1, err
45+
return err
4346
}
4447

4548
log.Printf("PHP extension %q initialized successfully in directory %q", baseName, generator.BuildDir)
4649

47-
return 0, nil
50+
return nil
4851
}

internal/extgen/docs.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package extgen
33
import (
44
"bytes"
55
_ "embed"
6+
"os"
67
"path/filepath"
78
"text/template"
89
)
@@ -12,6 +13,7 @@ var docFileContent string
1213

1314
type DocumentationGenerator struct {
1415
generator *Generator
16+
overwrite bool
1517
}
1618

1719
type DocTemplateData struct {
@@ -22,6 +24,11 @@ type DocTemplateData struct {
2224

2325
func (dg *DocumentationGenerator) generate() error {
2426
filename := filepath.Join(dg.generator.BuildDir, "README.md")
27+
28+
if _, err := os.Stat(filename); err == nil && !dg.overwrite {
29+
return nil
30+
}
31+
2532
content, err := dg.generateMarkdown()
2633
if err != nil {
2734
return err

internal/extgen/docs_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,3 +383,66 @@ func BenchmarkDocumentationGenerator_GenerateMarkdown(b *testing.B) {
383383
assert.NoError(b, err)
384384
}
385385
}
386+
387+
func TestDocumentationGenerator_OverwriteReadme(t *testing.T) {
388+
tempDir := t.TempDir()
389+
readmePath := filepath.Join(tempDir, "README.md")
390+
391+
err := os.WriteFile(readmePath, []byte("hello"), 0644)
392+
require.NoError(t, err)
393+
394+
generator := &Generator{
395+
BaseName: "testextension",
396+
BuildDir: tempDir,
397+
Functions: []phpFunction{
398+
{
399+
Name: "greet",
400+
ReturnType: phpString,
401+
Params: []phpParameter{
402+
{Name: "name", PhpType: phpString},
403+
},
404+
Signature: "greet(string $name): string",
405+
},
406+
},
407+
Classes: []phpClass{},
408+
}
409+
410+
docGen := &DocumentationGenerator{
411+
generator: generator,
412+
}
413+
414+
err = docGen.generate()
415+
assert.NoError(t, err, "generate() unexpected error")
416+
417+
content, err := os.ReadFile(readmePath)
418+
require.NoError(t, err, "Failed to read generated README.md")
419+
420+
assert.Equal(t, string(content), "hello")
421+
422+
// regenerate
423+
docGen = &DocumentationGenerator{
424+
generator: generator,
425+
overwrite: true,
426+
}
427+
428+
err = docGen.generate()
429+
assert.NoError(t, err, "generate() unexpected error")
430+
431+
content, err = os.ReadFile(readmePath)
432+
require.NoError(t, err, "Failed to read generated README.md")
433+
434+
contentStr := string(content)
435+
436+
assert.Contains(t, contentStr, "# testextension Extension", "README should contain extension title")
437+
assert.Contains(t, contentStr, "Auto-generated PHP extension from Go code.", "README should contain description")
438+
439+
if len(generator.Functions) > 0 {
440+
assert.Contains(t, contentStr, "## Functions", "README should contain functions section when functions exist")
441+
442+
for _, fn := range generator.Functions {
443+
assert.Contains(t, contentStr, "### "+fn.Name, "README should contain function %s", fn.Name)
444+
assert.Contains(t, contentStr, fn.Signature, "README should contain function signature for %s", fn.Name)
445+
}
446+
}
447+
448+
}

internal/extgen/generator.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import (
66
)
77

88
type Generator struct {
9-
BaseName string
10-
SourceFile string
11-
BuildDir string
12-
Functions []phpFunction
13-
Classes []phpClass
14-
Constants []phpConstant
15-
Namespace string
9+
BaseName string
10+
SourceFile string
11+
BuildDir string
12+
Functions []phpFunction
13+
Classes []phpClass
14+
Constants []phpConstant
15+
Namespace string
16+
OverwriteReadme bool
1617
}
1718

1819
// EXPERIMENTAL
@@ -129,7 +130,10 @@ func (g *Generator) generateGoFile() error {
129130
}
130131

131132
func (g *Generator) generateDocumentation() error {
132-
docGen := DocumentationGenerator{g}
133+
docGen := DocumentationGenerator{
134+
generator: g,
135+
overwrite: g.OverwriteReadme,
136+
}
133137
if err := docGen.generate(); err != nil {
134138
return &GeneratorError{"documentation generation", "failed to generate documentation", err}
135139
}

0 commit comments

Comments
 (0)