From ced286540d12f84a48095050174f2a37b376bdcc Mon Sep 17 00:00:00 2001 From: xhd2015 Date: Thu, 23 May 2024 09:19:26 +0800 Subject: [PATCH] enhance help message --- cmd/xgo/help.go | 10 +++- cmd/xgo/main.go | 8 +-- cmd/xgo/runtime_gen/core/version.go | 4 +- cmd/xgo/tool.go | 48 +++++++++++++++++- cmd/xgo/trace/main.go | 31 ++++++++++-- cmd/xgo/version.go | 4 +- runtime/core/version.go | 4 +- support/filecopy/copy_test.go | 77 +++++++++++++++-------------- support/netutil/netutil.go | 7 ++- 9 files changed, 135 insertions(+), 58 deletions(-) diff --git a/cmd/xgo/help.go b/cmd/xgo/help.go index c363241b..dd5018ab 100644 --- a/cmd/xgo/help.go +++ b/cmd/xgo/help.go @@ -17,16 +17,22 @@ The commands are: version print xgo version revision print xgo revision upgrade upgrade to latest version of xgo - tool invoke xgo tools + tool invoke xgo tools Examples: xgo build -o main ./ build current module xgo build -o main -gcflags="all=-N -l" ./ build current module with debug flags xgo run ./ run current module xgo test ./... test all test cases of current module + xgo exec go version print instrumented go version + xgo tool help print help for xgo tools + +Examples of Trace: xgo test -run TestSomething --strace ./ test and collect stack trace xgo tool trace TestSomething.json view collected stack trace - xgo exec go version print instrumented go version + +Example of Test Explorer: + xgo tool test-explorer open test explorer See https://github.com/xhd2015/xgo for documentation. diff --git a/cmd/xgo/main.go b/cmd/xgo/main.go index 3cefeacb..034b5590 100644 --- a/cmd/xgo/main.go +++ b/cmd/xgo/main.go @@ -44,7 +44,7 @@ func main() { fmt.Fprintf(os.Stderr, "xgo: requires command\nRun 'xgo help' for usage.\n") os.Exit(1) } - if cmd == "help" { + if cmd == "help" || cmd == "-h" || cmd == "--help" { fmt.Print(strings.TrimPrefix(help, "\n")) return } @@ -69,11 +69,7 @@ func main() { return } if cmd == "tool" { - if len(args) == 0 { - fmt.Fprintf(os.Stderr, "xgo tool: requires tool to run\n") - os.Exit(1) - } - err := handleTool(args[0], args[1:]) + err := handleTool(args) if err != nil { if err, ok := err.(*exec.ExitError); ok { os.Exit(err.ExitCode()) diff --git a/cmd/xgo/runtime_gen/core/version.go b/cmd/xgo/runtime_gen/core/version.go index 669d461e..c5e9b757 100755 --- a/cmd/xgo/runtime_gen/core/version.go +++ b/cmd/xgo/runtime_gen/core/version.go @@ -7,8 +7,8 @@ import ( ) const VERSION = "1.0.36" -const REVISION = "1e1b9419279db2f75b8619256fced2e8a84e9ee7+1" -const NUMBER = 229 +const REVISION = "48d5fefe9c2c051c940e088429f9253b80a65305+1" +const NUMBER = 230 // these fields will be filled by compiler const XGO_VERSION = "" diff --git a/cmd/xgo/tool.go b/cmd/xgo/tool.go index d008a738..5822e860 100644 --- a/cmd/xgo/tool.go +++ b/cmd/xgo/tool.go @@ -14,7 +14,53 @@ import ( "github.com/xhd2015/xgo/support/cmd" ) -func handleTool(tool string, args []string) error { +const toolHelp = ` +Xgo ships with a toolset that improves testing experience. + +Usage: + xgo tool [arguments] + +The commands are: + trace stack trace visualization + test-explorer test explorer + coverage incremental coverage tool + list list all tools + help show help + +Examples: + xgo tool trace TestSomething.json visualize a generated trace + xgo tool test-explorer open test explorer UI + xgo tool coverage serve cover.out visualize incrementa coverage of cover.out + +See https://github.com/xhd2015/xgo for documentation. + +` + +const toolList = ` +Available tools: + trace visualize a generated trace + test-explorer open test explorer UI + coverage visualize incrementa coverage +` + +func handleTool(args []string) error { + // tool string, + + // if len(args) == 0 { + // fmt.Fprintf(os.Stderr, "xgo tool: requires tool to run\n") + // os.Exit(1) + // } + + if len(args) == 0 || args[0] == "help" || args[0] == "-h" || args[0] == "--help" { + fmt.Print(strings.TrimPrefix(toolHelp, "\n")) + return nil + } + tool := args[0] + args = args[1:] + if tool == "list" { + fmt.Print(strings.TrimPrefix(toolList, "\n")) + return nil + } if tool == "trace" { trace.Main(args) return nil diff --git a/cmd/xgo/trace/main.go b/cmd/xgo/trace/main.go index 1e9d9fb3..67a10a33 100644 --- a/cmd/xgo/trace/main.go +++ b/cmd/xgo/trace/main.go @@ -19,22 +19,43 @@ import ( "github.com/xhd2015/xgo/support/netutil" ) +const help = ` +Xgo tool trace visualize a generated trace file. + +Usage: + xgo tool trace + +Examples: + xgo test -run TestSomething --strace ./ generate trace file + xgo tool trace TestSomething.json visualize a generated trace + +See https://github.com/xhd2015/xgo for documentation. + +` + func Main(args []string) { var files []string var port string n := len(args) + + var showHelp bool for i := 0; i < n; i++ { arg := args[i] if arg == "--" { files = append(files, args[i+1:]...) break } + if arg == "-h" || arg == "--help" { + showHelp = true + break + } if arg == "--port" { if i+1 >= n { fmt.Fprintf(os.Stderr, "--port requires arg\n") os.Exit(1) } - port = arg + port = args[i+1] + i++ continue } else if strings.HasPrefix(arg, "--port=") { port = strings.TrimPrefix(arg, "--port=") @@ -47,6 +68,10 @@ func Main(args []string) { fmt.Fprintf(os.Stderr, "unrecognized flag: %s\n", arg) os.Exit(1) } + if showHelp { + fmt.Print(strings.TrimPrefix(help, "\n")) + return + } if len(files) == 0 { fmt.Fprintf(os.Stderr, "requires file\n") os.Exit(1) @@ -136,13 +161,11 @@ func serveFile(portStr string, file string) error { } port = int(parsePort) } - err = netutil.ServePort(port, autoIncrPort, 500*time.Millisecond, func(port int) { + err = netutil.ServePortHTTP(server, port, autoIncrPort, 500*time.Millisecond, func(port int) { url := fmt.Sprintf("http://localhost:%d", port) fmt.Printf("Server listen at %s\n", url) openURL(url) - }, func(port int) error { - return http.ListenAndServe(fmt.Sprintf(":%d", port), server) }) if err != nil { return err diff --git a/cmd/xgo/version.go b/cmd/xgo/version.go index 7744059f..0bd2de07 100644 --- a/cmd/xgo/version.go +++ b/cmd/xgo/version.go @@ -3,8 +3,8 @@ package main import "fmt" const VERSION = "1.0.36" -const REVISION = "1e1b9419279db2f75b8619256fced2e8a84e9ee7+1" -const NUMBER = 229 +const REVISION = "48d5fefe9c2c051c940e088429f9253b80a65305+1" +const NUMBER = 230 func getRevision() string { revSuffix := "" diff --git a/runtime/core/version.go b/runtime/core/version.go index 669d461e..c5e9b757 100644 --- a/runtime/core/version.go +++ b/runtime/core/version.go @@ -7,8 +7,8 @@ import ( ) const VERSION = "1.0.36" -const REVISION = "1e1b9419279db2f75b8619256fced2e8a84e9ee7+1" -const NUMBER = 229 +const REVISION = "48d5fefe9c2c051c940e088429f9253b80a65305+1" +const NUMBER = 230 // these fields will be filled by compiler const XGO_VERSION = "" diff --git a/support/filecopy/copy_test.go b/support/filecopy/copy_test.go index b463bbf3..be9ddb09 100644 --- a/support/filecopy/copy_test.go +++ b/support/filecopy/copy_test.go @@ -9,34 +9,6 @@ import ( "testing" ) -func testCopyReplace(prepare func(rootDir string, srcDir string, dstDir string) error, check func(rootDir string, srcDir string, dstDir string) error) error { - tmpDir, err := os.MkdirTemp("", "copy-with-link") - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - - srcDir := filepath.Join(tmpDir, "src") - err = os.MkdirAll(srcDir, 0755) - if err != nil { - return err - } - dstDir := filepath.Join(tmpDir, "dst") - - err = prepare(tmpDir, srcDir, dstDir) - if err != nil { - return err - } - err = CopyReplaceDir(srcDir, dstDir, false) - if err != nil { - return err - } - if check == nil { - return nil - } - return check(tmpDir, srcDir, dstDir) -} - func TestCopyWithSymLinkFiles(t *testing.T) { // doc.txt // src/ @@ -73,16 +45,6 @@ func TestCopyWithSymLinkFiles(t *testing.T) { } } -func checkIsSymLink(file string) (bool, error) { - finfo, err := os.Lstat(file) - if err != nil { - return false, err - } - if finfo.Mode()&fs.ModeSymlink != 0 { - return true, nil - } - return false, nil -} func TestCopyWithSymLinkDirs(t *testing.T) { // doc.txt // src/ @@ -117,3 +79,42 @@ func TestCopyWithSymLinkDirs(t *testing.T) { t.Fatal(err) } } + +func checkIsSymLink(file string) (bool, error) { + finfo, err := os.Lstat(file) + if err != nil { + return false, err + } + if finfo.Mode()&fs.ModeSymlink != 0 { + return true, nil + } + return false, nil +} + +func testCopyReplace(prepare func(rootDir string, srcDir string, dstDir string) error, check func(rootDir string, srcDir string, dstDir string) error) error { + tmpDir, err := os.MkdirTemp("", "copy-with-link") + if err != nil { + return err + } + defer os.RemoveAll(tmpDir) + + srcDir := filepath.Join(tmpDir, "src") + err = os.MkdirAll(srcDir, 0755) + if err != nil { + return err + } + dstDir := filepath.Join(tmpDir, "dst") + + err = prepare(tmpDir, srcDir, dstDir) + if err != nil { + return err + } + err = CopyReplaceDir(srcDir, dstDir, false) + if err != nil { + return err + } + if check == nil { + return nil + } + return check(tmpDir, srcDir, dstDir) +} diff --git a/support/netutil/netutil.go b/support/netutil/netutil.go index 3731a54c..5f78a840 100644 --- a/support/netutil/netutil.go +++ b/support/netutil/netutil.go @@ -28,11 +28,16 @@ func ServePortHTTP(server *http.ServeMux, port int, autoIncrPort bool, watchTime // suggested watch timeout: 500ms func ServePort(port int, autoIncrPort bool, watchTimeout time.Duration, watch func(port int), doWithPort func(port int) error) error { for { - serving, err := IsTCPAddrServing(net.JoinHostPort("localhost", strconv.Itoa(port)), 20*time.Millisecond) + addr := net.JoinHostPort("localhost", strconv.Itoa(port)) + serving, err := IsTCPAddrServing(addr, 20*time.Millisecond) if err != nil { return err } if serving { + if !autoIncrPort { + return fmt.Errorf("bind %s failed: address in use", addr) + } + port++ continue }