Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements. Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate. Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable. Refs: Versioned dependencies U1/U3; feature/dependency-workspace
177 lines
4.3 KiB
Go
177 lines
4.3 KiB
Go
// Package cli 实现 errcode 命令:list / show / search / validate / export / serve。
|
||
package cli
|
||
|
||
import (
|
||
"encoding/json"
|
||
"flag"
|
||
"fmt"
|
||
"io"
|
||
"os"
|
||
"strings"
|
||
|
||
"git-ssh.u1680832.nyat.app/weichen/Error-Code-System.git/errcode"
|
||
"git-ssh.u1680832.nyat.app/weichen/Error-Code-System.git/server"
|
||
)
|
||
|
||
// Main 执行命令行并返回进程退出码。
|
||
func Main(args []string) int {
|
||
return Run(args, os.Stdout, os.Stderr)
|
||
}
|
||
|
||
// Run 执行命令。stdout 写结果,stderr 写用法与错误。
|
||
func Run(args []string, stdout, stderr io.Writer) int {
|
||
if len(args) == 0 {
|
||
fmt.Fprintln(stderr, usage)
|
||
return 2
|
||
}
|
||
switch args[0] {
|
||
case "list":
|
||
return cmdList(args[1:], stdout, stderr)
|
||
case "show":
|
||
return cmdShow(args[1:], stdout, stderr)
|
||
case "search":
|
||
return cmdSearch(args[1:], stdout, stderr)
|
||
case "validate":
|
||
return cmdValidate(args[1:], stdout, stderr)
|
||
case "export":
|
||
return cmdExport(args[1:], stdout, stderr)
|
||
case "serve":
|
||
return cmdServe(args[1:], stderr)
|
||
case "-h", "--help", "help":
|
||
fmt.Fprintln(stdout, usage)
|
||
return 0
|
||
default:
|
||
fmt.Fprintf(stderr, "未知命令 %q\n%s\n", args[0], usage)
|
||
return 2
|
||
}
|
||
}
|
||
|
||
const usage = `用法:
|
||
errcode list [--domain 域] [--json]
|
||
errcode show <码或别名>
|
||
errcode search <关键词>
|
||
errcode validate <码或别名>
|
||
errcode export [--domain 域]
|
||
errcode serve [--addr :8091]`
|
||
|
||
func registry() *errcode.Registry { return errcode.Default }
|
||
|
||
func cmdList(args []string, stdout, stderr io.Writer) int {
|
||
fs := flag.NewFlagSet("list", flag.ContinueOnError)
|
||
fs.SetOutput(stderr)
|
||
domain := fs.String("domain", "", "只列出该域")
|
||
asJSON := fs.Bool("json", false, "以 JSON 输出")
|
||
if err := fs.Parse(args); err != nil {
|
||
return 2
|
||
}
|
||
defs := registry().List(*domain)
|
||
if *asJSON {
|
||
enc := json.NewEncoder(stdout)
|
||
enc.SetEscapeHTML(false)
|
||
enc.SetIndent("", " ")
|
||
if err := enc.Encode(defs); err != nil {
|
||
fmt.Fprintln(stderr, err)
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|
||
for _, def := range defs {
|
||
fmt.Fprintf(stdout, "%s\t%d\t%s\t%s\n", def.Code, def.HTTP, def.Retry, def.Summary)
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func cmdShow(args []string, stdout, stderr io.Writer) int {
|
||
if len(args) != 1 {
|
||
fmt.Fprintln(stderr, "用法: errcode show <码或别名>")
|
||
return 2
|
||
}
|
||
def, ok := registry().Lookup(args[0])
|
||
if !ok {
|
||
fmt.Fprintf(stderr, "未登记: %s(回落 %s)\n", args[0], errcode.SysUnknownCode)
|
||
return 1
|
||
}
|
||
enc := json.NewEncoder(stdout)
|
||
enc.SetEscapeHTML(false)
|
||
enc.SetIndent("", " ")
|
||
if err := enc.Encode(def); err != nil {
|
||
fmt.Fprintln(stderr, err)
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func cmdSearch(args []string, stdout, stderr io.Writer) int {
|
||
if len(args) < 1 {
|
||
fmt.Fprintln(stderr, "用法: errcode search <关键词>")
|
||
return 2
|
||
}
|
||
q := strings.Join(args, " ")
|
||
for _, def := range registry().Search(q) {
|
||
fmt.Fprintf(stdout, "%s\t%s\n", def.Code, def.Summary)
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func cmdValidate(args []string, stdout, stderr io.Writer) int {
|
||
if len(args) != 1 {
|
||
fmt.Fprintln(stderr, "用法: errcode validate <码或别名>")
|
||
return 2
|
||
}
|
||
def, ok := registry().Lookup(args[0])
|
||
resolved := def
|
||
if !ok {
|
||
resolved = registry().Resolve(args[0])
|
||
}
|
||
fmt.Fprintf(stdout, "input=%s known=%t resolved=%s\n", args[0], ok, resolved.Code)
|
||
if !ok {
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func cmdExport(args []string, stdout, stderr io.Writer) int {
|
||
fs := flag.NewFlagSet("export", flag.ContinueOnError)
|
||
fs.SetOutput(stderr)
|
||
domain := fs.String("domain", "", "只导出该域")
|
||
if err := fs.Parse(args); err != nil {
|
||
return 2
|
||
}
|
||
var data []byte
|
||
var err error
|
||
if *domain == "" {
|
||
data, err = registry().ExportJSON()
|
||
} else {
|
||
encBuf := &strings.Builder{}
|
||
enc := json.NewEncoder(encBuf)
|
||
enc.SetEscapeHTML(false)
|
||
enc.SetIndent("", " ")
|
||
err = enc.Encode(registry().List(*domain))
|
||
data = []byte(encBuf.String())
|
||
}
|
||
if err != nil {
|
||
fmt.Fprintln(stderr, err)
|
||
return 1
|
||
}
|
||
if _, err := stdout.Write(data); err != nil {
|
||
fmt.Fprintln(stderr, err)
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func cmdServe(args []string, stderr io.Writer) int {
|
||
fs := flag.NewFlagSet("serve", flag.ContinueOnError)
|
||
fs.SetOutput(stderr)
|
||
addr := fs.String("addr", server.DefaultAddr, "监听地址")
|
||
if err := fs.Parse(args); err != nil {
|
||
return 2
|
||
}
|
||
fmt.Fprintf(stderr, "errcode serve %s\n", *addr)
|
||
if err := server.New(registry()).ListenAndServe(*addr); err != nil {
|
||
fmt.Fprintln(stderr, err)
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|