feat: standalone core-php binary with build tags
Some checks failed
Security Scan / security (push) Successful in 7s
Test / test (push) Failing after 1m22s

- Remove init() registration, use cli.Main() pattern
- Build-tag FrankenPHP files (cgo/!cgo)
- Add Taskfile.yml
- Add CLAUDE.md

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-06 08:40:39 +00:00
parent 05d2480f5e
commit ce2ca60268
5 changed files with 175 additions and 6 deletions

150
CLAUDE.md Normal file
View file

@ -0,0 +1,150 @@
# CLAUDE.md — core/go-php
## What This Is
Standalone `core-php` binary for PHP/Laravel development. Merges the FrankenPHP handler (CGO) with PHP dev CLI commands (pure Go). Produces a single binary that `core` can invoke as a subprocess.
**Module path**: `forge.lthn.ai/core/go-php`
**Binary**: `cmd/core-php/main.go``./bin/core-php`
**Pattern**: `cli.Main()` + `cli.WithCommands("php", php.AddPHPCommands)`
## Build
```bash
# Dev tooling only (no FrankenPHP, no CGO needed)
CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php
CGO_ENABLED=0 go test ./...
# With FrankenPHP (needs PHP-ZTS + CGO)
go build -o ./bin/core-php ./cmd/core-php
```
## Current State
- All code merged from `core/php` + `core/go-php` into single module
- Entry point exists at `cmd/core-php/main.go`
- Tests pass (`CGO_ENABLED=0 go test ./...`)
- `init()` in `cmd.go` still calls `cli.RegisterCommands()` — needs removing (standalone binary pattern)
- No Taskfile yet
- No CLAUDE.md until now
- FrankenPHP handler files: `handler.go`, `bridge.go`, `extract.go`, `env.go`
- FrankenPHP serve command: `cmd_serve_frankenphp.go` (exists, needs build tags)
- Dev CLI commands: `cmd_dev.go`, `cmd_build.go`, `cmd_deploy.go`, `cmd_ci.go`, `cmd_quality.go`, `cmd_packages.go`, `cmd_qa_runner.go`
## Why This Matters
Completing go-php unblocks a chain:
1. `core/go-php` done → `core/php` namespace freed
2. `core/php-framework` relocates to `core/php` (matching `core/go` pattern)
3. `core/ts` created from Deno prototype (the original seed project)
## Plan — Tasks To Complete
### Task 1: Clean up `init()` registration
**File**: `cmd.go`
Remove `init()` that calls `cli.RegisterCommands()`. The standalone binary uses `cli.Main()` directly — `init()` registration is the old pattern for when this was a library imported by the main `core` binary.
Keep `AddPHPCommands` exported (the entry point calls it).
**Verify**: `CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php && ./bin/core-php php --help`
### Task 2: Build-tag the FrankenPHP files
FrankenPHP requires CGO + PHP-ZTS headers. Files that import `github.com/dunglas/frankenphp` need build tags so the binary compiles without them.
**Files needing `//go:build cgo`**:
- `handler.go`
- `bridge.go`
- `cmd_serve_frankenphp.go`
- Any file importing FrankenPHP
**Create stubs** (`//go:build !cgo`):
- `cmd_serve_frankenphp_nocgo.go` — prints "requires CGO + PHP-ZTS"
- `handler_nocgo.go` — nil/noop exports if other files reference Handler
**Verify**: `CGO_ENABLED=0 go build ./...` AND `CGO_ENABLED=0 go test ./...`
### Task 3: Add Taskfile.yml
Based on the BugSETI pattern (`/Users/snider/Code/host-uk/core/cmd/bugseti/Taskfile.yml`):
```yaml
version: '3'
tasks:
build:
desc: Build core-php binary
cmds:
- CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php
build-frankenphp:
desc: Build with FrankenPHP support (needs PHP-ZTS)
cmds:
- go build -o ./bin/core-php ./cmd/core-php
test:
desc: Run tests
cmds:
- CGO_ENABLED=0 go test ./...
run:
desc: Build and run
cmds:
- task: build
- ./bin/core-php {{.CLI_ARGS}}
```
### Task 4: Verify all commands register
Run `./bin/core-php php --help` and confirm all subcommands appear:
- `dev` — Laravel dev server (FrankenPHP + Vite + Horizon)
- `build` — Docker/production builds
- `deploy` — Deployment commands
- `ci` — CI pipeline
- `quality` / `qa` — Code quality (Pint, PHPStan)
- `packages` — Composer package management
- `serve` — FrankenPHP server (CGO only)
### Task 5: Push to forge
```bash
git add -A
git commit -m "feat: standalone core-php binary with build tags
- Remove init() registration, use cli.Main() pattern
- Build-tag FrankenPHP files (cgo/!cgo)
- Add Taskfile.yml
- Add CLAUDE.md
Co-Authored-By: Virgil <virgil@lethean.io>"
git push origin main
```
**Remote**: `ssh://git@forge.lthn.ai:2223/core/go-php.git`
## Coding Standards
- **UK English** in comments and docs
- **Strict error handling**: wrap with context, no silent swallows
- **Test naming**: `_Good`, `_Bad`, `_Ugly` suffix pattern
- **No init()**: standalone binary pattern uses `cli.Main()` + `cli.WithCommands()`
- **License**: EUPL-1.2
- **Co-author**: `Co-Authored-By: Virgil <virgil@lethean.io>`
## Key Dependencies
| Package | Role |
|---------|------|
| `forge.lthn.ai/core/cli` | CLI framework (cobra + bubbletea TUI) |
| `forge.lthn.ai/core/go` | Core framework (services, DI) |
| `forge.lthn.ai/core/go-i18n` | Internationalisation |
| `github.com/dunglas/frankenphp` | PHP-in-Go (CGO, optional) |
## Reference
- CLI pattern: `/Users/snider/Code/host-uk/cli/main.go`
- BugSETI Taskfile: `/Users/snider/Code/host-uk/core/cmd/bugseti/Taskfile.yml`
- FrankenPHP native app: see `frankenphp-native.md` in memory

23
Taskfile.yml Normal file
View file

@ -0,0 +1,23 @@
version: '3'
tasks:
build:
desc: Build core-php binary
cmds:
- CGO_ENABLED=0 go build -o ./bin/core-php ./cmd/core-php
build-frankenphp:
desc: Build with FrankenPHP support (needs PHP-ZTS)
cmds:
- go build -o ./bin/core-php ./cmd/core-php
test:
desc: Run tests
cmds:
- CGO_ENABLED=0 go test ./...
run:
desc: Build and run
cmds:
- task: build
- ./bin/core-php {{.CLI_ARGS}}

4
cmd.go
View file

@ -9,10 +9,6 @@ import (
"forge.lthn.ai/core/go/pkg/io"
)
func init() {
cli.RegisterCommands(AddPHPCommands)
}
// DefaultMedium is the default filesystem medium used by the php package.
// It defaults to io.Local (unsandboxed filesystem access).
// Use SetMedium to change this for testing or sandboxed operation.

1
go.mod
View file

@ -32,6 +32,7 @@ require (
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/gammazero/deque v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/klauspost/compress v1.18.4 // indirect
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-localereader v0.0.1 // indirect

3
go.sum
View file

@ -49,8 +49,7 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=