Server: - Add a --cache-path allowlist so a server can be limited to the caches it is meant to purge, defaulting to any path as before. - Set socket permissions explicitly (--socket-mode, default 0660) instead of inheriting the service manager's umask, which left the socket unreachable. - Refuse to remove a socket another instance is still serving. - Read keys both raw and decoded, so keys nginx stored with escapes and keys a caller escaped by hand both purge. - Add an exact= parameter for literal keys containing glob punctuation. - Report purge failures as 500 rather than 502, and send error bodies through http.Error so a failure is not reported as a successful purge. - Graceful shutdown with systemd readiness notification. Purge: - Group purge arguments into PurgeRequest and report the number of entries removed. - Compile exclude globs once, and fail the purge when one is invalid rather than purging the keys it was meant to keep. - Cap header scanning and tolerate entries nginx evicts mid-walk. - Switch to filepath.WalkDir to avoid an Lstat per cache file. New: - service command to install, start, stop, and remove the system service. - service install takes --cache-path, writing the allowlist into the unit it installs, so an installed service is restricted from its first start. - Makefile, VERSION, and build identifiers stamped via ldflags. - Tests for the server handler and the service command. Build: - Update to Go 1.25, kong v1, GoReleaser v2, and current GitHub Actions. - Add vet and test steps to CI. - Rename purgeCmd.go/serverCmd.go to Go's file naming convention. Bump version to 0.2.0.
81 lines
2.2 KiB
Go
81 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"runtime/debug"
|
|
"strings"
|
|
|
|
"github.com/alecthomas/kong"
|
|
)
|
|
|
|
// VersionFlag prints build information and exits.
|
|
type VersionFlag bool
|
|
|
|
// Decode satisfies kong.MapperValue. The flag is treated as a boolean toggle.
|
|
func (v VersionFlag) Decode(ctx *kong.DecodeContext) error { return nil }
|
|
|
|
// IsBool reports the flag as a boolean for kong's parser.
|
|
func (v VersionFlag) IsBool() bool { return true }
|
|
|
|
// BeforeApply emits version information then exits before the rest of the
|
|
// command is executed.
|
|
func (v VersionFlag) BeforeApply(app *kong.Kong, vars kong.Vars) error {
|
|
fmt.Printf("%s: %s (%s)\n", Name, Version, Mode)
|
|
if Commit != "" {
|
|
fmt.Printf(" commit: %s\n", Commit)
|
|
}
|
|
if Date != "" {
|
|
fmt.Printf(" built: %s\n", Date)
|
|
}
|
|
// Without build stamps, a module-aware build still records the revision
|
|
// it was built from, so fall back to what the toolchain embedded.
|
|
if Commit == "" {
|
|
if bi, ok := debug.ReadBuildInfo(); ok {
|
|
for _, s := range bi.Settings {
|
|
switch s.Key {
|
|
case "vcs.revision":
|
|
fmt.Printf(" commit: %s\n", s.Value)
|
|
case "vcs.time":
|
|
fmt.Printf(" built: %s\n", s.Value)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
app.Exit(0)
|
|
return nil
|
|
}
|
|
|
|
// Flags and or commands supplied to cli.
|
|
type Flags struct {
|
|
Version VersionFlag `name:"version" help:"Print version information and quit"`
|
|
|
|
Server ServerCmd `cmd:"" aliases:"s" default:"1" help:"Run the server"`
|
|
Purge PurgeCmd `cmd:"" aliases:"p" help:"Purge cache now"`
|
|
Service ServiceCmd `cmd:"" help:"Manage the purge server system service."`
|
|
}
|
|
|
|
// kongVars are the values the command tags interpolate. They live in one place
|
|
// so that a parser built anywhere describes the same command line.
|
|
func kongVars() kong.Vars {
|
|
return kong.Vars{
|
|
"serviceActions": strings.Join(ServiceAction, ","),
|
|
"defaultSocket": defaultSocketPath,
|
|
"defaultMode": defaultSocketMode,
|
|
}
|
|
}
|
|
|
|
// Parse the supplied flags and commands.
|
|
func (a *App) ParseFlags() *kong.Context {
|
|
a.flags = &Flags{}
|
|
|
|
ctx := kong.Parse(a.flags,
|
|
kong.Name(Name),
|
|
kong.Description(Description),
|
|
kong.UsageOnError(),
|
|
kong.ConfigureHelp(kong.HelpOptions{
|
|
Compact: true,
|
|
}),
|
|
kongVars(),
|
|
)
|
|
return ctx
|
|
}
|