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  }