github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/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/core/elvish/program/shell" 19 "github.com/u-root/u-root/cmds/core/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 55 f.BoolVar(&f.CodeInArg, "c", false, "take first argument as code to execute") 56 f.BoolVar(&f.CompileOnly, "compileonly", false, "Parse/Compile but do not execute") 57 58 f.StringVar(&f.Bin, "bin", "", "path to the elvish binary") 59 f.StringVar(&f.DB, "db", "", "path to the database") 60 61 return &f 62 } 63 64 // usage prints usage to the specified output. It modifies the flagSet; there is 65 // no API for getting the current output of a flag.FlagSet, so we can neither 66 // use the current output of f to output our own usage string, nor restore the 67 // previous value of f's output. 68 func usage(out io.Writer, f *flagSet) { 69 f.SetOutput(out) 70 fmt.Fprintln(out, "Usage: elvish [flags] [script]") 71 fmt.Fprintln(out, "Supported flags:") 72 f.PrintDefaults() 73 } 74 75 func Main(allArgs []string) int { 76 flag := newFlagSet() 77 err := flag.Parse(allArgs[1:]) 78 if err != nil { 79 // Error and usage messages are already shown. 80 return 2 81 } 82 83 // Handle flags common to all subprograms. 84 85 if flag.CPUProfile != "" { 86 f, err := os.Create(flag.CPUProfile) 87 if err != nil { 88 log.Fatal(err) 89 } 90 pprof.StartCPUProfile(f) 91 defer pprof.StopCPUProfile() 92 } 93 94 if flag.Log != "" { 95 err = util.SetOutputFile(flag.Log) 96 } else if flag.LogPrefix != "" { 97 err = util.SetOutputFile(flag.LogPrefix + strconv.Itoa(os.Getpid())) 98 } 99 if err != nil { 100 fmt.Fprintln(os.Stderr, err) 101 } 102 103 return FindProgram(flag).Main(flag.Args()) 104 } 105 106 // Program represents a subprogram. 107 type Program interface { 108 // Main calls the subprogram with arguments. The return value will be used 109 // as the exit status of the entire program. 110 Main(args []string) int 111 } 112 113 // FindProgram finds a suitable Program according to flags. It does not have any 114 // side effects. 115 func FindProgram(flag *flagSet) Program { 116 switch { 117 case flag.Help: 118 return ShowHelp{flag} 119 case flag.Version: 120 return ShowVersion{} 121 case flag.BuildInfo: 122 return ShowBuildInfo{} 123 default: 124 return shell.New(flag.Bin, flag.Sock, flag.DB, flag.CodeInArg, flag.CompileOnly) 125 } 126 }