Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <[email protected]>
143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
// 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"
|
|
"strings"
|
|
|
|
"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:]))
|
|
}
|
|
|
|
// normalizeArgs reorders args into [flags and their values..., positionals...]
|
|
// because stdlib flag.Parse stops at the first non-flag token, which would
|
|
// misparse flags placed after the positional input.
|
|
func normalizeArgs(args []string, valueFlags map[string]bool) []string {
|
|
var flags, positionals []string
|
|
for i := 0; i < len(args); i++ {
|
|
tok := args[i]
|
|
if !strings.HasPrefix(tok, "-") || tok == "-" {
|
|
positionals = append(positionals, tok)
|
|
continue
|
|
}
|
|
flags = append(flags, tok)
|
|
if !strings.Contains(tok, "=") {
|
|
name := tok
|
|
if valueFlags[name] && i+1 < len(args) {
|
|
i++
|
|
flags = append(flags, args[i])
|
|
}
|
|
}
|
|
}
|
|
return append(flags, positionals...)
|
|
}
|
|
|
|
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: "."}
|
|
valueFlags := make(map[string]bool)
|
|
switch frontend.Name() {
|
|
case "arch-binary":
|
|
opts.Repo = defaultRepo
|
|
fs.StringVar(&opts.Repo, "repo", opts.Repo, "repository base URL")
|
|
valueFlags["--repo"] = true
|
|
case "arch-src":
|
|
opts.Arch = "x86_64"
|
|
fs.StringVar(&opts.Arch, "arch", opts.Arch, "target architecture")
|
|
valueFlags["--arch"] = true
|
|
}
|
|
fs.StringVar(&opts.Output, "output", opts.Output, "output directory")
|
|
valueFlags["--output"] = true
|
|
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(normalizeArgs(args[1:], valueFlags)); 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 frontend.Name() == "arch-binary" && !strings.HasSuffix(rest[0], ".pkg.tar.zst") {
|
|
fmt.Fprintln(os.Stderr, "error: arch-binary input must end with .pkg.tar.zst")
|
|
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
|
|
}
|