github.com/mem/u-root@v2.0.1-0.20181004165302-9b18b4636a33+incompatible/cmds/elvish/program/program.go (about) 1 // Package program provides the entry point to Elvish. Its subpackages 2 // correspond to subprograms of Elvish. 3 package program 4 5 // This package sets up the basic environment and calls the appropriate 6 // "subprogram", one of the daemon, the terminal interface, or the web 7 // interface. 8 9 import ( 10 "flag" 11 "fmt" 12 "io" 13 "log" 14 "os" 15 "runtime/pprof" 16 "strconv" 17 18 "github.com/u-root/u-root/cmds/elvish/program/shell" 19 "github.com/u-root/u-root/cmds/elvish/util" 20 ) 21 22 var logger = util.GetLogger("[main] ") 23 24 type flagSet struct { 25 flag.FlagSet 26 27 Log, LogPrefix, CPUProfile string 28 29 Help, Version, BuildInfo, JSON bool 30 31 CodeInArg, CompileOnly bool 32 33 Web bool 34 Port int 35 36 Forked int 37 38 Bin, DB, Sock string 39 } 40 41 func newFlagSet() *flagSet { 42 f := flagSet{} 43 f.Init("elvish", flag.ContinueOnError) 44 f.Usage = func() { 45 usage(os.Stderr, &f) 46 } 47 48 f.StringVar(&f.Log, "log", "", "a file to write debug log to") 49 f.StringVar(&f.CPUProfile, "cpuprofile", "", "write cpu profile to file") 50 51 f.BoolVar(&f.Help, "help", false, "show usage help and quit") 52 f.BoolVar(&f.Version, "version", false, "show version and quit") 53 f.BoolVar(&f.BuildInfo, "buildinfo", false, "show build info and quit") 54 f.BoolVar(&f.JSON, "json", false, "show output in JSON. Useful with -buildinfo.") 55 56 f.BoolVar(&f.CodeInArg, "c", false, "take first argument as code to execute") 57 f.BoolVar(&f.CompileOnly, "compileonly", false, "Parse/Compile but do not execute") 58 59 f.StringVar(&f.Bin, "bin", "", "path to the elvish binary") 60 f.StringVar(&f.DB, "db", "", "path to the database") 61 62 return &f 63 } 64 65 // usage prints usage to the specified output. It modifies the flagSet; there is 66 // no API for getting the current output of a flag.FlagSet, so we can neither 67 // use the current output of f to output our own usage string, nor restore the 68 // previous value of f's output. 69 func usage(out io.Writer, f *flagSet) { 70 f.SetOutput(out) 71 fmt.Fprintln(out, "Usage: elvish [flags] [script]") 72 fmt.Fprintln(out, "Supported flags:") 73 f.PrintDefaults() 74 } 75 76 func Main(allArgs []string) int { 77 flag := newFlagSet() 78 err := flag.Parse(allArgs[1:]) 79 if err != nil { 80 // Error and usage messages are already shown. 81 return 2 82 } 83 84 // Handle flags common to all subprograms. 85 86 if flag.CPUProfile != "" { 87 f, err := os.Create(flag.CPUProfile) 88 if err != nil { 89 log.Fatal(err) 90 } 91 pprof.StartCPUProfile(f) 92 defer pprof.StopCPUProfile() 93 } 94 95 if flag.Log != "" { 96 err = util.SetOutputFile(flag.Log) 97 } else if flag.LogPrefix != "" { 98 err = util.SetOutputFile(flag.LogPrefix + strconv.Itoa(os.Getpid())) 99 } 100 if err != nil { 101 fmt.Fprintln(os.Stderr, err) 102 } 103 104 return FindProgram(flag).Main(flag.Args()) 105 } 106 107 // Program represents a subprogram. 108 type Program interface { 109 // Main calls the subprogram with arguments. The return value will be used 110 // as the exit status of the entire program. 111 Main(args []string) int 112 } 113 114 // FindProgram finds a suitable Program according to flags. It does not have any 115 // side effects. 116 func FindProgram(flag *flagSet) Program { 117 switch { 118 case flag.Help: 119 return ShowHelp{flag} 120 case flag.Version: 121 return ShowVersion{} 122 case flag.BuildInfo: 123 return ShowBuildInfo{flag.JSON} 124 default: 125 return shell.New(flag.Bin, flag.Sock, flag.DB, flag.CodeInArg, flag.CompileOnly) 126 } 127 }