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  }