-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Added run() and exec() functions * Use new Suspend/Resume to run() commands including interactive ones (like vi etc) * Use the release version of terminal, tweak the help for run() * update help output
- Loading branch information
Showing
11 changed files
with
129 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package extensions | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"os" | ||
"os/exec" | ||
|
||
"fortio.org/log" | ||
"grol.io/grol/eval" | ||
"grol.io/grol/object" | ||
) | ||
|
||
func createCmd(s eval.State, args []object.Object) (*exec.Cmd, *object.Error) { | ||
cmdArgs := make([]string, 0, len(args)) | ||
for _, arg := range args { | ||
if arg.Type() != object.STRING { | ||
return nil, s.Errorfp("exec: argument %s not a string", arg.Inspect()) | ||
} | ||
cmdArgs = append(cmdArgs, arg.(object.String).Value) | ||
} | ||
//nolint:gosec // we do want to run the command given by the user. | ||
return exec.CommandContext(s.Context, cmdArgs[0], cmdArgs[1:]...), nil | ||
} | ||
|
||
var ( | ||
stdout = object.String{Value: "stdout"} | ||
stderr = object.String{Value: "stderr"} | ||
) | ||
|
||
func createShellFunctions() { | ||
shellFn := object.Extension{ | ||
Name: "exec", | ||
MinArgs: 1, | ||
MaxArgs: -1, | ||
Help: "executes a command and returns its stdout, stderr and any error", | ||
ArgTypes: []object.Type{object.STRING}, | ||
Callback: func(env any, _ string, args []object.Object) object.Object { | ||
s := env.(*eval.State) | ||
cmd, oerr := createCmd(*s, args) | ||
if oerr != nil { | ||
return *oerr | ||
} | ||
log.Infof("Running %#v", cmd) | ||
var sout, serr bytes.Buffer | ||
cmd.Stdout = &sout | ||
cmd.Stderr = &serr | ||
err := cmd.Run() | ||
res := object.MakeQuad(stdout, object.String{Value: sout.String()}, | ||
stderr, object.String{Value: serr.String()}) | ||
if err != nil { | ||
res = res.Set(eval.ErrorKey, object.String{Value: err.Error()}) | ||
} else { | ||
res = res.Set(eval.ErrorKey, object.NULL) | ||
} | ||
return res | ||
}, | ||
DontCache: true, | ||
} | ||
MustCreate(shellFn) | ||
shellFn.Name = "run" | ||
shellFn.Help = "runs a command interactively" | ||
shellFn.Callback = func(env any, _ string, args []object.Object) object.Object { | ||
s := env.(*eval.State) | ||
if s.Term != nil { | ||
s.Term.Suspend() | ||
} | ||
s.Context, s.Cancel = context.WithCancel(context.Background()) // no timeout. | ||
cmd, oerr := createCmd(*s, args) | ||
if oerr != nil { | ||
return *oerr | ||
} | ||
log.Infof("Running %#v", cmd) | ||
cmd.Stdin = os.Stdin | ||
cmd.Stdout = os.Stdout | ||
cmd.Stderr = os.Stderr | ||
err := cmd.Run() | ||
if s.Term != nil { | ||
s.Context, s.Cancel = s.Term.Resume(context.Background()) | ||
} | ||
if err != nil { | ||
return s.Error(err) | ||
} | ||
return object.NULL | ||
} | ||
MustCreate(shellFn) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
|
||
run("true") | ||
run("echo", "echoing", "foo") | ||
|
||
IsErr("non zero exit", run("false"), "exit status 1") | ||
|
||
NoErr("exec captures", exec("false").err, `^exit status 1$`) | ||
NoErr("exec captures", exec("echo", "-n", "foo").stdout, "^foo$") | ||
NoErr("exec captures", exec("ls", "/no/such/file").stderr, "No such file or directory") |