feat(cli): add Go module, subcommand dispatch, frontend registry

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <[email protected]>
This commit is contained in:
2026-08-19 16:27:51 -04:00
co-authored by Sisyphus
commit 57253f0523
6 changed files with 227 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
// Command zeta-reconstruct converts Arch Linux packages into Zeta package
// format. Subcommands are provided by frontends registered in the registry.
package main
import (
"flag"
"fmt"
"os"
"git.spectoria.dev/huntedbytheirs/zeta-reconstruct/internal/registry"
// Import frontend packages so their init() functions register them.
_ "git.spectoria.dev/huntedbytheirs/zeta-reconstruct/internal/arch/binary"
_ "git.spectoria.dev/huntedbytheirs/zeta-reconstruct/internal/arch/src"
)
const defaultRepo = "https://raw.githubusercontent.com/gretagen/zeta-packages/refs/heads/main"
const usageText = `usage: zeta-reconstruct <command> [flags] <input>
Commands:
arch-binary convert an Arch binary package (.pkg.tar.zst) to Zeta
arch-src convert a PKGBUILD/.SRCINFO source recipe to Zeta
Flags:
--list list registered frontends
-h, --help show this help
arch-binary flags:
--output <dir> output directory (default ".")
--repo <url> repository base URL (default "` + defaultRepo + `")
arch-src flags:
--output <dir> output directory (default ".")
--arch <arch> target architecture (default "x86_64")
`
func main() {
os.Exit(run(os.Args[1:]))
}
func run(args []string) int {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "error: no command specified")
fmt.Fprintln(os.Stderr, "Run 'zeta-reconstruct --help' for usage.")
return 2
}
switch args[0] {
case "--list":
for _, name := range registry.List() {
fmt.Println(name)
}
return 0
case "--help", "-h":
fmt.Print(usageText)
return 0
}
frontend, ok := registry.Get(args[0])
if !ok {
fmt.Fprintf(os.Stderr, "error: unknown command %q\n", args[0])
fmt.Fprintln(os.Stderr, "Run 'zeta-reconstruct --help' for usage.")
return 2
}
fs := flag.NewFlagSet(frontend.Name(), flag.ContinueOnError)
fs.SetOutput(os.Stderr)
opts := registry.Options{Output: "."}
switch frontend.Name() {
case "arch-binary":
opts.Repo = defaultRepo
fs.StringVar(&opts.Repo, "repo", opts.Repo, "repository base URL")
case "arch-src":
opts.Arch = "x86_64"
fs.StringVar(&opts.Arch, "arch", opts.Arch, "target architecture")
}
fs.StringVar(&opts.Output, "output", opts.Output, "output directory")
fs.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: zeta-reconstruct %s [flags] <input>\n", frontend.Name())
fmt.Fprintln(os.Stderr, "Run 'zeta-reconstruct --help' for usage.")
}
if err := fs.Parse(args[1:]); err != nil {
if err == flag.ErrHelp {
fs.Usage()
return 0
}
return 2
}
rest := fs.Args()
if len(rest) == 0 {
fmt.Fprintf(os.Stderr, "error: %s requires an input argument\n", frontend.Name())
fs.Usage()
return 1
}
if len(rest) > 1 {
fmt.Fprintf(os.Stderr, "error: unexpected argument %q\n", rest[1])
fs.Usage()
return 2
}
if err := frontend.Convert(rest[0], opts); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
return 1
}
return 0
}