github.com/cilki/sh@v2.6.4+incompatible/cmd/gosh/main.go (about)

     1  // Copyright (c) 2017, Daniel Martí <mvdan@mvdan.cc>
     2  // See LICENSE for licensing information
     3  
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"flag"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"strings"
    13  
    14  	"golang.org/x/crypto/ssh/terminal"
    15  
    16  	"mvdan.cc/sh/interp"
    17  	"mvdan.cc/sh/syntax"
    18  )
    19  
    20  var (
    21  	command = flag.String("c", "", "command to be executed")
    22  
    23  	parser = syntax.NewParser()
    24  
    25  	mainRunner, _ = interp.New(interp.StdIO(os.Stdin, os.Stdout, os.Stderr))
    26  )
    27  
    28  func main() {
    29  	flag.Parse()
    30  	if err := runAll(); err != nil {
    31  		fmt.Fprintln(os.Stderr, err)
    32  		os.Exit(1)
    33  	}
    34  }
    35  
    36  func runAll() error {
    37  	if *command != "" {
    38  		return run(strings.NewReader(*command), "")
    39  	}
    40  	if flag.NArg() == 0 {
    41  		if terminal.IsTerminal(int(os.Stdin.Fd())) {
    42  			return interactive(mainRunner)
    43  		}
    44  		return run(os.Stdin, "")
    45  	}
    46  	for _, path := range flag.Args() {
    47  		if err := runPath(path); err != nil {
    48  			return err
    49  		}
    50  	}
    51  	return nil
    52  }
    53  
    54  func runPath(path string) error {
    55  	f, err := os.Open(path)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	defer f.Close()
    60  	return run(f, path)
    61  }
    62  
    63  func run(reader io.Reader, name string) error {
    64  	prog, err := parser.Parse(reader, name)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	mainRunner.Reset()
    69  	ctx := context.Background()
    70  	return mainRunner.Run(ctx, prog)
    71  }
    72  
    73  func interactive(runner *interp.Runner) error {
    74  	fmt.Fprintf(runner.Stdout, "$ ")
    75  	fn := func(stmts []*syntax.Stmt) bool {
    76  		if parser.Incomplete() {
    77  			fmt.Fprintf(runner.Stdout, "> ")
    78  			return true
    79  		}
    80  		ctx := context.Background()
    81  		for _, stmt := range stmts {
    82  			if err := runner.Run(ctx, stmt); err != nil {
    83  				switch x := err.(type) {
    84  				case interp.ShellExitStatus:
    85  					os.Exit(int(x))
    86  				case interp.ExitStatus:
    87  				default:
    88  					fmt.Fprintln(runner.Stderr, err)
    89  					os.Exit(1)
    90  				}
    91  			}
    92  		}
    93  		fmt.Fprintf(runner.Stdout, "$ ")
    94  		return true
    95  	}
    96  	return parser.Interactive(runner.Stdin, fn)
    97  }