github.com/yunabe/lgo@v0.0.0-20190709125917-42c42d410fdf/cmd/lgo/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "log" 7 "os" 8 "os/exec" 9 "os/signal" 10 "path/filepath" 11 "regexp" 12 "runtime" 13 "syscall" 14 15 "github.com/yunabe/lgo/cmd/lgo/install" 16 "github.com/yunabe/lgo/cmd/runner" 17 ) 18 19 const usage = `lgo is a tool to build and execute Go code interactively.append 20 21 Usage: 22 23 lgo commands [arguments] 24 25 The commands are; 26 27 install install lgo into $LGOPATH. You need to run this command before using lgo 28 installpkg install packages into $LGOPATH. This operation is optional. 29 kernel run a jupyter notebook kernel 30 run run Go code defined in files 31 repl ... 32 clean clean temporary files created by lgo 33 ` 34 35 var commandStrRe = regexp.MustCompile("[a-z]+") 36 37 func printUsageAndExit() { 38 fmt.Fprint(os.Stderr, usage) 39 os.Exit(1) 40 } 41 42 func runLgoInternal(subcommand string, extraArgs []string) { 43 // TODO: Consolidate this logic to check env variables. 44 if runtime.GOOS != "linux" { 45 log.Fatal("lgo only supports Linux") 46 } 47 lgopath := os.Getenv("LGOPATH") 48 if lgopath == "" { 49 log.Fatal("LGOPATH is empty") 50 } 51 lgopath, err := filepath.Abs(lgopath) 52 if err != nil { 53 log.Fatalf("Failed to get the absolute path of LGOPATH: %v", err) 54 } 55 56 lgoInternal := filepath.Join(lgopath, "bin", "lgo-internal") 57 if _, err = os.Stat(lgoInternal); os.IsNotExist(err) { 58 log.Fatal("lgo is not installed in LGOPATH. Please run `lgo install` first") 59 } 60 61 // These signals are ignored because no goroutine reads sigch. 62 // We do not use signal.Ignore because we do not change the signal handling behavior of child processes. 63 sigch := make(chan os.Signal) 64 signal.Notify(sigch, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGHUP, syscall.SIGINT) 65 66 sessID := runner.NewSessionID() 67 var args []string 68 args = append(args, "--subcommand="+subcommand) 69 args = append(args, "--sess_id="+sessID.Marshal()) 70 args = append(args, extraArgs...) 71 cmd := exec.Command(lgoInternal, args...) 72 cmd.Stdin = os.Stdin 73 cmd.Stdout = os.Stdout 74 cmd.Stderr = os.Stderr 75 if err := cmd.Run(); err != nil { 76 log.Printf("lgo-internal failed: %v", err) 77 } 78 // In case lgo-internal exists before cleaning files (e.g. os.Exit is called) 79 runner.CleanSession(lgopath, sessID) 80 } 81 82 func runMain() { 83 fs := flag.NewFlagSet("lgo run", flag.ExitOnError) 84 fs.Parse(os.Args[2:]) 85 runLgoInternal("run", fs.Args()) 86 } 87 88 func kernelMain() { 89 fs := flag.NewFlagSet("lgo kernel", flag.ExitOnError) 90 connectionFile := fs.String("connection_file", "", "jupyter kernel connection file path.") 91 fs.Parse(os.Args[2:]) 92 runLgoInternal("kernel", []string{"--connection_file=" + *connectionFile}) 93 } 94 95 func main() { 96 if len(os.Args) <= 1 { 97 printUsageAndExit() 98 } 99 cmd := os.Args[1] 100 if !commandStrRe.MatchString(cmd) { 101 printUsageAndExit() 102 } 103 switch cmd { 104 case "install": 105 install.InstallMain() 106 case "installpkg": 107 install.InstallPkgMain() 108 case "kernel": 109 kernelMain() 110 case "run": 111 runMain() 112 case "clean": 113 fmt.Fprint(os.Stderr, "not implemented") 114 case "help": 115 printUsageAndExit() 116 default: 117 fmt.Fprintf(os.Stderr, "unknown subcommand %q\n", cmd) 118 os.Exit(1) 119 } 120 }