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  }