diff --git a/.gitignore b/.gitignore index e0d15d7..434973d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # SPDX-License-Identifier: 0BSD -# The current preview runtime is connected through a local workspace only. +# Local workspaces must not override the published tutorial dependencies. go.work go.work.sum diff --git a/GENERATED_CODE.md b/GENERATED_CODE.md index ab66b5a..a4f3443 100644 --- a/GENERATED_CODE.md +++ b/GENERATED_CODE.md @@ -3,8 +3,8 @@ # Generated code Every `*.sando.go` file is an owned output of the neighboring `*.sando` source. -Commit both files so production builds need only ordinary Go and the small -`sando` runtime. +The exact generator is `himesan v1.0.0-beta.1`. Commit both files so production +builds need only ordinary Go and the small `sando` runtime. Never hand-edit a generated neighbor. Run `himesan generate internal/views`, review the deterministic diff, and use `himesan check internal/views` in local diff --git a/README.md b/README.md index ec2509e..cacc873 100644 --- a/README.md +++ b/README.md @@ -25,34 +25,43 @@ The starter demonstrates the boundary plainly: time through `Server-Timing`. - Production imports the Apache-2.0 `sando` runtime, not the compiler. -## Run the current source preview +## Walk the path with Beta 1 -Sandwich Hime does not have immutable public release tags yet. Do not invent a -version-shaped install command: clone the compiler and this starter side by -side, then use a local Go workspace as an explicit preview bridge. +Install Go 1.25 or newer, then resolve the tiny runtime before installing the +immutable classroom compiler: ```sh -mkdir sandwich-hime-walk -cd sandwich-hime-walk - -git clone https://gitea.speelman.ca/gamertan/sandwich-hime.git git clone https://gitea.speelman.ca/gamertan/sandwich-hime-tutorial.git - -cd sandwich-hime -go install ./cmd/himesan - -cd ../sandwich-hime-tutorial -go work init . -go work edit -replace=gamertan.com/sandwich-hime/sando=../sandwich-hime/sando - +cd sandwich-hime-tutorial +GOWORK=off go mod download gamertan.com/sandwich-hime/sando@v1.0.0-beta.1 +go install gamertan.com/sandwich-hime/cmd/himesan@v1.0.0-beta.1 ./scripts/verify.sh +GOWORK=off go run ./cmd/site +``` + +On Windows PowerShell, use the native verifier: + +```powershell +git clone https://gitea.speelman.ca/gamertan/sandwich-hime-tutorial.git +Set-Location sandwich-hime-tutorial +$env:GOWORK = "off" +go mod download gamertan.com/sandwich-hime/sando@v1.0.0-beta.1 +go install gamertan.com/sandwich-hime/cmd/himesan@v1.0.0-beta.1 +.\scripts\verify.ps1 go run ./cmd/site ``` -Make sure `$(go env GOPATH)/bin` is on `PATH`, or set `HIMESAN_BIN` to the -compiler executable when running the verification script. `go.work` and -`go.work.sum` are intentionally ignored: they are local preview wiring, not a -claim that `v0.0.0` was published. +Make sure Go's install directory—normally `$(go env GOPATH)/bin`—is on +`PATH`, or set `HIMESAN_BIN` to the full compiler path before running either +verifier. The starter deliberately runs with `GOWORK=off`: it proves the +application resolves the published Apache-2.0 runtime rather than a neighboring +development checkout. The verification scripts also reject any compiler or +runtime version other than `v1.0.0-beta.1`. + +Beta 1 is intended for classrooms, learning, prototypes, and evaluation. Its +interfaces may still change before final v1. Linux and Windows have been +maintainer-tested; macOS is provisional while native maintainer testing is +pending. Useful Mac compatibility reports are welcome on canonical Gitea. Open [http://127.0.0.1:8080/?name=Hime-san](http://127.0.0.1:8080/?name=Hime-san), refresh it, and watch the request number and UTC time change. Then try: @@ -74,6 +83,7 @@ internal/views/views.go typed template contracts internal/views/*.sando templates people edit internal/views/*.sando.go committed generated Go scripts/verify.sh generation, tests, build, and dependency gate +scripts/verify.ps1 the same gate for native Windows PowerShell ``` The application owns the server, routing, headers, data, and deployment. @@ -83,9 +93,9 @@ before accepting real user content. ## What the verification gate proves -`./scripts/verify.sh` checks committed output, generates twice and compares -digests, runs all tests and `go vet`, builds the server into a temporary -directory, and inspects its Go dependency graph. The only production +`./scripts/verify.sh` and `scripts/verify.ps1` check committed output, generate +twice and compare digests, run all tests and `go vet`, build the server into a +temporary directory, and inspect its Go dependency graph. The only production Sandwich Hime package allowed by that graph is `gamertan.com/sandwich-hime/sando`. diff --git a/go.mod b/go.mod index 21f615a..cfb19bc 100644 --- a/go.mod +++ b/go.mod @@ -4,4 +4,4 @@ module gitea.speelman.ca/gamertan/sandwich-hime-tutorial go 1.25 -require gamertan.com/sandwich-hime/sando v0.0.0 +require gamertan.com/sandwich-hime/sando v1.0.0-beta.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..633c126 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +gamertan.com/sandwich-hime/sando v1.0.0-beta.1 h1:WHe6LnVKvOz7CQr9OIWI78pCzIFIAGgoXlGfjYVAVoU= +gamertan.com/sandwich-hime/sando v1.0.0-beta.1/go.mod h1:awOXo4t2zNxxgH60qkTpMOdhYnultm9AfpjlN9gOEis= diff --git a/internal/views/badge.sando.go b/internal/views/badge.sando.go index 0c7303c..1da49b1 100644 --- a/internal/views/badge.sando.go +++ b/internal/views/badge.sando.go @@ -1,5 +1,5 @@ // Code generated by himesan; DO NOT EDIT. -// himesan:compiler 0.1.0-dev +// himesan:compiler v1.0.0-beta.1 // himesan:runtime-abi sando.v1 // himesan:source-sha256 241093d3b845d20c38e5a0fe5cf2213d6bb9114138818dbe98d8b3a99ff19d24 @@ -11,7 +11,7 @@ import ( __himesan_io "io" ) -var _ = __himesan_sando.ABI +var _ = __himesan_sando.ABISandoV1 func Badge(label string) __himesan_sando.Component { return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error { diff --git a/internal/views/home.sando.go b/internal/views/home.sando.go index 3ea42a1..9ba53d8 100644 --- a/internal/views/home.sando.go +++ b/internal/views/home.sando.go @@ -1,5 +1,5 @@ // Code generated by himesan; DO NOT EDIT. -// himesan:compiler 0.1.0-dev +// himesan:compiler v1.0.0-beta.1 // himesan:runtime-abi sando.v1 // himesan:source-sha256 2f04e0f2e6caae73ea3d419a88c53afcaf25d300e76dc522ae2f418a03a68def @@ -11,7 +11,7 @@ import ( __himesan_io "io" ) -var _ = __himesan_sando.ABI +var _ = __himesan_sando.ABISandoV1 func Home(view HomeView) __himesan_sando.Component { return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error { diff --git a/internal/views/layout.sando.go b/internal/views/layout.sando.go index 53c15f0..8bf01ef 100644 --- a/internal/views/layout.sando.go +++ b/internal/views/layout.sando.go @@ -1,5 +1,5 @@ // Code generated by himesan; DO NOT EDIT. -// himesan:compiler 0.1.0-dev +// himesan:compiler v1.0.0-beta.1 // himesan:runtime-abi sando.v1 // himesan:source-sha256 e56b373194349ae32dcbad4a26c1d1a3d133e335ff916cef064e12ca2901adf3 @@ -11,7 +11,7 @@ import ( __himesan_io "io" ) -var _ = __himesan_sando.ABI +var _ = __himesan_sando.ABISandoV1 func Layout(view LayoutView) __himesan_sando.Component { return __himesan_sando.ComponentFunc(func(__himesan_render_context __himesan_context.Context, __himesan_writer __himesan_io.Writer) error { diff --git a/scripts/verify.ps1 b/scripts/verify.ps1 new file mode 100644 index 0000000..84f4f0f --- /dev/null +++ b/scripts/verify.ps1 @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: 0BSD + +[CmdletBinding()] +param() + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version Latest + +$repoRoot = Split-Path -Parent $PSScriptRoot +Set-Location $repoRoot +$env:GOWORK = "off" + +$himesan = if ($env:HIMESAN_BIN) { $env:HIMESAN_BIN } else { "himesan" } +$expectedVersion = "v1.0.0-beta.1" +if (-not (Get-Command $himesan -ErrorAction SilentlyContinue)) { + throw "himesan was not found; install v1.0.0-beta.1 or set HIMESAN_BIN" +} + +function Assert-LastExitCode([string]$Step) { + if ($LASTEXITCODE -ne 0) { + throw "$Step failed with exit code $LASTEXITCODE" + } +} + +function Get-GeneratedDigest { + $lines = Get-ChildItem internal/views -Recurse -File -Filter *.sando.go | + Sort-Object FullName | + ForEach-Object { + $hash = (Get-FileHash -Algorithm SHA256 -LiteralPath $_.FullName).Hash.ToLowerInvariant() + "$($_.FullName):$hash" + } + return ($lines -join "`n") +} + +$versionLine = (& $himesan version | Select-Object -First 1) +Assert-LastExitCode "himesan version" +if ($versionLine -notmatch '^himesan ([^ ]+) ') { + throw "could not parse himesan version output: $versionLine" +} +if ($Matches[1] -ne $expectedVersion) { + throw "himesan version is $($Matches[1]); expected $expectedVersion" +} + +$runtimeVersion = (go list -m -f '{{.Version}}' gamertan.com/sandwich-hime/sando | Select-Object -First 1) +Assert-LastExitCode "sando runtime version" +if ($runtimeVersion -ne $expectedVersion) { + throw "sando runtime version is $runtimeVersion; expected $expectedVersion" +} + +& $himesan check internal/views +Assert-LastExitCode "himesan check" +$before = Get-GeneratedDigest +& $himesan generate internal/views +Assert-LastExitCode "first himesan generate" +$afterFirst = Get-GeneratedDigest +& $himesan generate internal/views +Assert-LastExitCode "second himesan generate" +$afterSecond = Get-GeneratedDigest +& $himesan check internal/views +Assert-LastExitCode "final himesan check" + +if ($before -ne $afterFirst -or $afterFirst -ne $afterSecond) { + throw "generated output was stale or nondeterministic" +} + +go test ./... +Assert-LastExitCode "go test" +go vet ./... +Assert-LastExitCode "go vet" + +$buildDir = Join-Path ([System.IO.Path]::GetTempPath()) ("sandwich-hime-tutorial-" + [guid]::NewGuid().ToString("N")) +New-Item -ItemType Directory -Path $buildDir | Out-Null +try { + go build -trimpath -o (Join-Path $buildDir "site.exe") ./cmd/site + Assert-LastExitCode "go build" +} finally { + Remove-Item -LiteralPath $buildDir -Recurse -Force -ErrorAction SilentlyContinue +} + +$dependencies = @(go list -deps ./cmd/site) +Assert-LastExitCode "go list -deps" +if ($dependencies -notcontains "gamertan.com/sandwich-hime/sando") { + throw "production dependency graph does not contain the sando runtime" +} +if ($dependencies | Where-Object { $_ -match '^gamertan\.com/sandwich-hime$|^gamertan\.com/sandwich-hime/(cmd|internal)(/|$)' }) { + throw "production dependency graph contains the Sandwich Hime compiler" +} + +Write-Output "verified Beta 1 identity, deterministic generation, tests, vet, build, and runtime-only production dependencies" diff --git a/scripts/verify.sh b/scripts/verify.sh index 487425f..bf5d9fb 100755 --- a/scripts/verify.sh +++ b/scripts/verify.sh @@ -7,12 +7,23 @@ repo_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) cd "$repo_root" himesan_bin=${HIMESAN_BIN:-himesan} +expected_version=v1.0.0-beta.1 if ! command -v "$himesan_bin" >/dev/null 2>&1; then - echo "himesan was not found; install it from the neighboring Sandwich Hime checkout or set HIMESAN_BIN" >&2 + echo "himesan was not found; install v1.0.0-beta.1 or set HIMESAN_BIN" >&2 exit 1 fi -if [[ ! -f go.work ]]; then - echo "go.work is missing; follow the README preview bridge commands first" >&2 + +export GOWORK=off + +actual_version=$("$himesan_bin" version | awk 'NR == 1 { print $2 }') +if [[ "$actual_version" != "$expected_version" ]]; then + echo "himesan version is $actual_version; expected $expected_version" >&2 + exit 1 +fi + +runtime_version=$(go list -m -f '{{.Version}}' gamertan.com/sandwich-hime/sando) +if [[ "$runtime_version" != "$expected_version" ]]; then + echo "sando runtime version is $runtime_version; expected $expected_version" >&2 exit 1 fi @@ -53,4 +64,4 @@ if grep -Eq '^gamertan\.com/sandwich-hime$|^gamertan\.com/sandwich-hime/(cmd|int exit 1 fi -echo "verified deterministic generation, tests, vet, build, and runtime-only production dependencies" +echo "verified Beta 1 identity, deterministic generation, tests, vet, build, and runtime-only production dependencies"