215 lines
7.2 KiB
Go
215 lines
7.2 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"git.yuntuo.hk/k2safe/go-omni/cmd/go-omni/apigen"
|
|
"git.yuntuo.hk/k2safe/go-omni/cmd/go-omni/scaffold"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
usage()
|
|
os.Exit(2)
|
|
}
|
|
|
|
switch os.Args[1] {
|
|
case "api":
|
|
if err := runAPI(os.Args[2:]); err != nil {
|
|
fmt.Fprintln(os.Stderr, "go-omni api:", err)
|
|
os.Exit(1)
|
|
}
|
|
case "migrate":
|
|
if err := runMigrate(os.Args[2:]); err != nil {
|
|
fmt.Fprintln(os.Stderr, "go-omni migrate:", err)
|
|
os.Exit(1)
|
|
}
|
|
case "add":
|
|
if err := runAdd(os.Args[2:]); err != nil {
|
|
fmt.Fprintln(os.Stderr, "go-omni add:", err)
|
|
os.Exit(1)
|
|
}
|
|
case "new":
|
|
if err := runNew(os.Args[2:]); err != nil {
|
|
fmt.Fprintln(os.Stderr, "go-omni new:", err)
|
|
os.Exit(1)
|
|
}
|
|
case "help", "-h", "--help":
|
|
usage()
|
|
default:
|
|
fmt.Fprintf(os.Stderr, "unknown command %q\n", os.Args[1])
|
|
usage()
|
|
os.Exit(2)
|
|
}
|
|
}
|
|
|
|
func runNew(args []string) error {
|
|
options := scaffold.Options{}
|
|
var target string
|
|
var apiFile string
|
|
for index := 0; index < len(args); index++ {
|
|
arg := args[index]
|
|
switch {
|
|
case arg == "--api" || strings.HasPrefix(arg, "--api="):
|
|
_, value, inline := strings.Cut(arg, "=")
|
|
if !inline {
|
|
if index+1 >= len(args) || strings.HasPrefix(args[index+1], "-") {
|
|
return errors.New("--api requires a file")
|
|
}
|
|
index++
|
|
value = args[index]
|
|
}
|
|
if value == "" {
|
|
return errors.New("--api requires a file")
|
|
}
|
|
apiFile = value
|
|
case arg == "--log-output" || arg == "--log-format" || arg == "--storage" || strings.HasPrefix(arg, "--log-output=") || strings.HasPrefix(arg, "--log-format=") || strings.HasPrefix(arg, "--storage="):
|
|
name, value, hasValue := strings.Cut(arg, "=")
|
|
if !hasValue {
|
|
if index+1 >= len(args) || strings.HasPrefix(args[index+1], "--") {
|
|
return fmt.Errorf("%s requires a value", name)
|
|
}
|
|
index++
|
|
value = args[index]
|
|
}
|
|
if strings.TrimSpace(value) == "" {
|
|
return fmt.Errorf("%s requires a value", name)
|
|
}
|
|
switch name {
|
|
case "--log-output":
|
|
options.LogOutput = value
|
|
case "--log-format":
|
|
options.LogFormat = value
|
|
case "--storage":
|
|
options.Storage = value
|
|
}
|
|
case arg == "--force":
|
|
options.Force = true
|
|
case arg == "--database":
|
|
if index+1 >= len(args) || strings.TrimSpace(args[index+1]) == "" {
|
|
return errors.New("--database requires memory or mysql")
|
|
}
|
|
index++
|
|
options.Database = args[index]
|
|
case strings.HasPrefix(arg, "--database="):
|
|
options.Database = strings.TrimPrefix(arg, "--database=")
|
|
if strings.TrimSpace(options.Database) == "" {
|
|
return errors.New("--database requires memory or mysql")
|
|
}
|
|
case arg == "--module":
|
|
if index+1 >= len(args) {
|
|
return errors.New("--module requires a value")
|
|
}
|
|
index++
|
|
options.Module = args[index]
|
|
case strings.HasPrefix(arg, "--module="):
|
|
options.Module = strings.TrimPrefix(arg, "--module=")
|
|
case arg == "--framework-dir":
|
|
if index+1 >= len(args) {
|
|
return errors.New("--framework-dir requires a value")
|
|
}
|
|
index++
|
|
options.FrameworkDir = args[index]
|
|
case strings.HasPrefix(arg, "--framework-dir="):
|
|
options.FrameworkDir = strings.TrimPrefix(arg, "--framework-dir=")
|
|
case arg == "--framework-version":
|
|
if index+1 >= len(args) || strings.TrimSpace(args[index+1]) == "" {
|
|
return errors.New("--framework-version requires a value")
|
|
}
|
|
index++
|
|
options.FrameworkVersion = args[index]
|
|
case strings.HasPrefix(arg, "--framework-version="):
|
|
options.FrameworkVersion = strings.TrimPrefix(arg, "--framework-version=")
|
|
if strings.TrimSpace(options.FrameworkVersion) == "" {
|
|
return errors.New("--framework-version requires a value")
|
|
}
|
|
case strings.HasPrefix(arg, "-"):
|
|
return fmt.Errorf("unknown option %q", arg)
|
|
case target == "":
|
|
target = arg
|
|
default:
|
|
return fmt.Errorf("unexpected argument %q", arg)
|
|
}
|
|
}
|
|
if target == "" {
|
|
return errors.New("project directory is required")
|
|
}
|
|
if options.Module == "" && apiFile == "" {
|
|
options.Module = filepath.Base(filepath.Clean(target))
|
|
}
|
|
options.Dir = target
|
|
if options.Force {
|
|
return errors.New("managed projects do not accept --force; use api generate to update owned files")
|
|
}
|
|
o := apigen.Options{API: apiFile, Dir: target, Module: options.Module, FrameworkDir: options.FrameworkDir, FrameworkVersion: options.FrameworkVersion, LogOutput: options.LogOutput, LogFormat: options.LogFormat, Database: options.Database, Storage: options.Storage}
|
|
var err error
|
|
var out apigen.Output
|
|
if apiFile != "" {
|
|
out, err = apigen.Generate(o)
|
|
} else {
|
|
out, err = apigen.New(o)
|
|
}
|
|
printAPIDiagnostics(out.Diagnostics)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("created API project %s; implement internal/logic operations; run with go run .\n", filepath.Clean(target))
|
|
return nil
|
|
}
|
|
|
|
func usage() {
|
|
fmt.Fprintln(os.Stderr, "GoOmni project tool")
|
|
fmt.Fprintln(os.Stderr, "")
|
|
fmt.Fprintln(os.Stderr, "Usage:")
|
|
fmt.Fprintln(os.Stderr, " go-omni migrate [--dir migrations] [--apply] [--dsn-env GO_OMNI_DB_DSN]")
|
|
fmt.Fprintln(os.Stderr, " go-omni new [--module <module>] <directory>")
|
|
fmt.Fprintln(os.Stderr, " go-omni new --api <file.api> [--module <module>] <directory>")
|
|
fmt.Fprintln(os.Stderr, " go-omni api new [--module <module>] <directory> Create a runnable API project")
|
|
fmt.Fprintln(os.Stderr, " go-omni api generate [--api <file.api>] [--dir <project>] [--check|--dry-run]")
|
|
fmt.Fprintln(os.Stderr, " go-omni api inspect [--api <file.api>] Show routes, auth and business errors")
|
|
fmt.Fprintln(os.Stderr, " go-omni api export [--api <file.api>] Write OpenAPI JSON to stdout")
|
|
fmt.Fprintln(os.Stderr, " go-omni api validate --api <file.api> Validate definitions and OpenAPI")
|
|
fmt.Fprintln(os.Stderr, " go-omni add <name> [--dir <project>] Generate an isolated business module")
|
|
fmt.Fprintln(os.Stderr, " --framework-version <version> Pin a remote framework version (defaults to CLI version)")
|
|
fmt.Fprintln(os.Stderr, " --framework-dir <directory> Use a local framework checkout")
|
|
fmt.Fprintln(os.Stderr, " --database <none|memory|mysql> Defaults to none")
|
|
fmt.Fprintln(os.Stderr, " --log-output <stdout|stderr|file> Generate configured logging (default stderr)")
|
|
fmt.Fprintln(os.Stderr, " --log-format <json|text> Select structured log format (default json)")
|
|
fmt.Fprintln(os.Stderr, " --storage <none|local|s3|r2|oss> Select optional storage adapter (default none)")
|
|
}
|
|
|
|
func runAdd(args []string) error {
|
|
directory, name := ".", ""
|
|
for index := 0; index < len(args); index++ {
|
|
arg := args[index]
|
|
switch {
|
|
case arg == "--dir":
|
|
if index+1 >= len(args) {
|
|
return errors.New("--dir requires a project directory")
|
|
}
|
|
index++
|
|
directory = args[index]
|
|
case strings.HasPrefix(arg, "--dir="):
|
|
directory = strings.TrimPrefix(arg, "--dir=")
|
|
case strings.HasPrefix(arg, "-"):
|
|
return fmt.Errorf("unknown option %q", arg)
|
|
case name == "":
|
|
name = arg
|
|
default:
|
|
return fmt.Errorf("unexpected argument %q", arg)
|
|
}
|
|
}
|
|
if _, err := os.Stat(filepath.Join(directory, ".goOmni", "apiManifest.json")); err == nil {
|
|
return errors.New("managed API projects add modules through .api imports and api generate")
|
|
}
|
|
if err := scaffold.AddModule(directory, name); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("created internal/%s; see its README.md for route registration\n", name)
|
|
return nil
|
|
}
|