aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cli/internal/cmd
diff options
context:
space:
mode:
author简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
committer简律纯 <hsiangnianian@outlook.com>2023-04-28 01:36:44 +0800
commitdd84b9d64fb98746a230cd24233ff50a562c39c9 (patch)
treeb583261ef00b3afe72ec4d6dacb31e57779a6faf /cli/internal/cmd
parent0b46fcd72ac34382387b2bcf9095233efbcc52f4 (diff)
downloadHydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.tar.gz
HydroRoll-dd84b9d64fb98746a230cd24233ff50a562c39c9.zip
Diffstat (limited to 'cli/internal/cmd')
-rw-r--r--cli/internal/cmd/root.go157
1 files changed, 157 insertions, 0 deletions
diff --git a/cli/internal/cmd/root.go b/cli/internal/cmd/root.go
new file mode 100644
index 0000000..d8d0e33
--- /dev/null
+++ b/cli/internal/cmd/root.go
@@ -0,0 +1,157 @@
+// Package cmd holds the root cobra command for turbo
+package cmd
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "runtime/pprof"
+ "runtime/trace"
+
+ "github.com/pkg/errors"
+ "github.com/vercel/turbo/cli/internal/cmdutil"
+ "github.com/vercel/turbo/cli/internal/daemon"
+ "github.com/vercel/turbo/cli/internal/process"
+ "github.com/vercel/turbo/cli/internal/prune"
+ "github.com/vercel/turbo/cli/internal/run"
+ "github.com/vercel/turbo/cli/internal/signals"
+ "github.com/vercel/turbo/cli/internal/turbostate"
+ "github.com/vercel/turbo/cli/internal/util"
+)
+
+func initializeOutputFiles(helper *cmdutil.Helper, parsedArgs *turbostate.ParsedArgsFromRust) error {
+ if parsedArgs.Trace != "" {
+ cleanup, err := createTraceFile(parsedArgs.Trace)
+ if err != nil {
+ return fmt.Errorf("failed to create trace file: %v", err)
+ }
+ helper.RegisterCleanup(cleanup)
+ }
+ if parsedArgs.Heap != "" {
+ cleanup, err := createHeapFile(parsedArgs.Heap)
+ if err != nil {
+ return fmt.Errorf("failed to create heap file: %v", err)
+ }
+ helper.RegisterCleanup(cleanup)
+ }
+ if parsedArgs.CPUProfile != "" {
+ cleanup, err := createCpuprofileFile(parsedArgs.CPUProfile)
+ if err != nil {
+ return fmt.Errorf("failed to create CPU profile file: %v", err)
+ }
+ helper.RegisterCleanup(cleanup)
+ }
+
+ return nil
+}
+
+// RunWithArgs runs turbo with the ParsedArgsFromRust that is passed from the Rust side.
+func RunWithArgs(args *turbostate.ParsedArgsFromRust, turboVersion string) int {
+ util.InitPrintf()
+ // TODO: replace this with a context
+ signalWatcher := signals.NewWatcher()
+ helper := cmdutil.NewHelper(turboVersion, args)
+ ctx := context.Background()
+
+ err := initializeOutputFiles(helper, args)
+ if err != nil {
+ fmt.Printf("%v", err)
+ return 1
+ }
+ defer helper.Cleanup(args)
+
+ doneCh := make(chan struct{})
+ var execErr error
+ go func() {
+ command := args.Command
+ if command.Daemon != nil {
+ execErr = daemon.ExecuteDaemon(ctx, helper, signalWatcher, args)
+ } else if command.Prune != nil {
+ execErr = prune.ExecutePrune(helper, args)
+ } else if command.Run != nil {
+ execErr = run.ExecuteRun(ctx, helper, signalWatcher, args)
+ } else {
+ execErr = fmt.Errorf("unknown command: %v", command)
+ }
+
+ close(doneCh)
+ }()
+
+ // Wait for either our command to finish, in which case we need to clean up,
+ // or to receive a signal, in which case the signal handler above does the cleanup
+ select {
+ case <-doneCh:
+ // We finished whatever task we were running
+ signalWatcher.Close()
+ exitErr := &process.ChildExit{}
+ if errors.As(execErr, &exitErr) {
+ return exitErr.ExitCode
+ } else if execErr != nil {
+ fmt.Printf("Turbo error: %v\n", execErr)
+ return 1
+ }
+ return 0
+ case <-signalWatcher.Done():
+ // We caught a signal, which already called the close handlers
+ return 1
+ }
+}
+
+type profileCleanup func() error
+
+// Close implements io.Close for profileCleanup
+func (pc profileCleanup) Close() error {
+ return pc()
+}
+
+// To view a CPU trace, use "go tool trace [file]". Note that the trace
+// viewer doesn't work under Windows Subsystem for Linux for some reason.
+func createTraceFile(traceFile string) (profileCleanup, error) {
+ f, err := os.Create(traceFile)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to create trace file: %v", traceFile)
+ }
+ if err := trace.Start(f); err != nil {
+ return nil, errors.Wrap(err, "failed to start tracing")
+ }
+ return func() error {
+ trace.Stop()
+ return f.Close()
+ }, nil
+}
+
+// To view a heap trace, use "go tool pprof [file]" and type "top". You can
+// also drop it into https://speedscope.app and use the "left heavy" or
+// "sandwich" view modes.
+func createHeapFile(heapFile string) (profileCleanup, error) {
+ f, err := os.Create(heapFile)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to create heap file: %v", heapFile)
+ }
+ return func() error {
+ if err := pprof.WriteHeapProfile(f); err != nil {
+ // we don't care if we fail to close the file we just failed to write to
+ _ = f.Close()
+ return errors.Wrapf(err, "failed to write heap file: %v", heapFile)
+ }
+ return f.Close()
+ }, nil
+}
+
+// To view a CPU profile, drop the file into https://speedscope.app.
+// Note: Running the CPU profiler doesn't work under Windows subsystem for
+// Linux. The profiler has to be built for native Windows and run using the
+// command prompt instead.
+func createCpuprofileFile(cpuprofileFile string) (profileCleanup, error) {
+ f, err := os.Create(cpuprofileFile)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to create cpuprofile file: %v", cpuprofileFile)
+ }
+ if err := pprof.StartCPUProfile(f); err != nil {
+ return nil, errors.Wrap(err, "failed to start CPU profiling")
+ }
+ return func() error {
+ pprof.StopCPUProfile()
+ return f.Close()
+ }, nil
+}