| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- package runnable
-
- import "fmt"
- import "os/exec"
-
- import "github.com/codecrafters-io/shell-starter-go/app/builtin"
- import "github.com/codecrafters-io/shell-starter-go/app/core"
- import "github.com/codecrafters-io/shell-starter-go/app/tokenize"
-
- type Runnable interface {
- Run(ctx *core.Context) core.ActionResult
- }
-
- type ExternalCommand struct {
- Args []string
- ExecPath string
- Name string
- }
-
- func (self ExternalCommand) Run(ctx *core.Context) core.ActionResult {
- wrapEs := func(es int) core.ActionResult {
- return core.ActionResult{
- Code: core.ActionResultCodeExternalCommand,
- ExitStatus: core.ExitStatus(es),
- }
- }
- cmd := exec.Command(self.ExecPath, self.Args...)
- cmd.Args[0] = self.Name
- cmd.Stdout = ctx.Stdout
- cmd.Stderr = ctx.Stderr
- cmd.Stdin = ctx.Stdin
- err := cmd.Run()
- if err != nil {
- if exiterr, ok := err.(*exec.ExitError); ok {
- return wrapEs(exiterr.ExitCode())
- // fmt.Printf("Handle():exiterr=%#v\n", exiterr.ExitCode())
- } else {
- fmt.Printf("Handle():err=%#v\n", err)
- return wrapEs(65535)
- }
- }
- return wrapEs(0)
- }
-
- type ParseError struct {
- code ParseErrorCode
- value string
- }
- type ParseErrorCode int
-
- const (
- ParseErrorCodeNotFound ParseErrorCode = iota
- )
-
- func (e ParseError) Error() string {
- switch e.code {
- case ParseErrorCodeNotFound:
- return fmt.Sprintf("%s: not found", e.value)
- default:
- return fmt.Sprintf("unknown ParseErrorCode code: %d .value=%q", e.code, e.value)
- }
-
- }
-
- func Parse(ctx *core.Context, command_line string) (Runnable, error) {
- tokens, err := tokenize.Tokenize(command_line)
- if err != nil {
- return nil, err
- }
- //fmt.Printf("Parse():tokens=%#v\n", tokens)
- if len(tokens) == 0 { // ie. empty or whitespace-only input
- return Noop{}, nil
- }
- bltn, err := builtin.Parse(ctx, tokens[0], tokens[1:])
- if err == nil { // it was a builtin
- return bltn, nil
- }
- if e, ok := err.(builtin.ParseError); ok {
- switch e.Code {
- case builtin.ParseErrorCodeUsage:
- return nil, err
- case builtin.ParseErrorCodeUnknownBuiltin:
- exec_path, err := exec.LookPath(tokens[0])
- if err != nil { // command not found
- return nil, ParseError{
- code: ParseErrorCodeNotFound,
- value: tokens[0],
- }
- }
- return ExternalCommand{
- ExecPath: exec_path,
- Name: tokens[0],
- Args: tokens[1:],
- }, nil
- }
- }
- panic("unexpected builtin.Parse(); only builtin.ParseError is expected")
- }
-
- type Noop struct{}
-
- func (self Noop) Run(ctx *core.Context) core.ActionResult {
- return core.ActionResult{
- Code: core.ActionResultCodeNoop,
- ExitStatus: 0,
- }
- }
|