github.com/NeowayLabs/nash@v0.2.2-0.20200127205349-a227041ffd50/nash.go (about) 1 // Package nash provides a library to embed the `nash` scripting language 2 // within your program or create your own nash cli. 3 package nash 4 5 import ( 6 "bytes" 7 "fmt" 8 "io" 9 10 "github.com/madlambda/nash/ast" 11 shell "github.com/madlambda/nash/internal/sh" 12 "github.com/madlambda/nash/sh" 13 ) 14 15 type ( 16 // Shell is the execution engine of the scripting language. 17 Shell struct { 18 interp *shell.Shell 19 } 20 ) 21 22 func newShell(nashpath string, nashroot string, abort bool) (*Shell, error) { 23 var ( 24 nash Shell 25 err error 26 ) 27 28 if abort { 29 nash.interp, err = shell.NewAbortShell(nashpath, nashroot) 30 } else { 31 nash.interp, err = shell.NewShell(nashpath, nashroot) 32 } 33 if err != nil { 34 return nil, err 35 } 36 37 return &nash, nil 38 } 39 40 // New creates a new `nash.Shell` instance. 41 func New(nashpath string, nashroot string) (*Shell, error) { 42 return newShell(nashpath, nashroot, false) 43 } 44 45 // NewAbort creates a new shell that aborts in case of error on initialization. 46 // Useful for tests, to avoid trashing the output log. 47 func NewAbort(nashpath string, nashroot string) (*Shell, error) { 48 return newShell(nashpath, nashroot, true) 49 } 50 51 // SetDebug enable some logging for debug purposes. 52 func (nash *Shell) SetDebug(b bool) { 53 nash.interp.SetDebug(b) 54 } 55 56 // SetInteractive enables interactive (shell) mode. 57 func (nash *Shell) SetInteractive(b bool) { 58 nash.interp.SetInteractive(b) 59 } 60 61 func (nash *Shell) NashPath() string { 62 return nash.interp.NashPath() 63 } 64 65 // Environ returns the set of environment variables in the shell 66 func (nash *Shell) Environ() shell.Env { 67 return nash.interp.Environ() 68 } 69 70 // GetFn gets the function object. 71 func (nash *Shell) GetFn(name string) (sh.FnDef, error) { 72 fnObj, err := nash.interp.GetFn(name) 73 if err != nil { 74 return nil, err 75 } 76 return fnObj.Fn(), nil 77 } 78 79 // Prompt returns the environment prompt or the default one 80 func (nash *Shell) Prompt() string { 81 value, ok := nash.interp.Getenv("PROMPT") 82 83 if ok { 84 return value.String() 85 } 86 87 return "<no prompt> " 88 } 89 90 // SetNashdPath sets an alternativa path to nashd 91 func (nash *Shell) SetNashdPath(path string) { 92 nash.interp.SetNashdPath(path) 93 } 94 95 // Exec executes the code specified by string content. 96 // By default, nash uses os.Stdin, os.Stdout and os.Stderr as input, output 97 // and error file descriptors. You can change it with SetStdin, SetStdout and Stderr, 98 // respectively. 99 // The path is only used for error line reporting. If content represents a file, then 100 // setting path to this filename should improve debugging (or no). 101 func (nash *Shell) Exec(path, content string) error { 102 return nash.interp.Exec(path, content) 103 } 104 105 // ExecOutput executes the code specified by string content. 106 // 107 // It behaves like **Exec** with the exception that it will ignore any 108 // stdout parameter (and the default os.Stdout) and will return the 109 // whole stdout output in memory. 110 // 111 // This method has no side effects, it will preserve any previously 112 // setted stdout, it will only ignore the configured stdout to run 113 // the provided script content; 114 func (nash *Shell) ExecOutput(path, content string) ([]byte, error) { 115 oldstdout := nash.Stdout() 116 defer nash.SetStdout(oldstdout) 117 118 var output bytes.Buffer 119 nash.SetStdout(&output) 120 121 err := nash.interp.Exec(path, content) 122 return output.Bytes(), err 123 } 124 125 // ExecuteString executes the script content. 126 // Deprecated: Use Exec instead. 127 func (nash *Shell) ExecuteString(path, content string) error { 128 return nash.interp.Exec(path, content) 129 } 130 131 // ExecFile executes the script content of the file specified by path 132 // and passes as arguments to the script the given args slice. 133 func (nash *Shell) ExecFile(path string, args ...string) error { 134 if len(args) > 0 { 135 err := nash.ExecuteString("setting args", `var ARGS = `+args2Nash(args)) 136 if err != nil { 137 return fmt.Errorf("Failed to set nash arguments: %s", err.Error()) 138 } 139 } 140 return nash.interp.ExecFile(path) 141 } 142 143 // ExecuteFile executes the given file. 144 // Deprecated: Use ExecFile instead. 145 func (nash *Shell) ExecuteFile(path string) error { 146 return nash.interp.ExecFile(path) 147 } 148 149 // ExecuteTree executes the given tree. 150 // Deprecated: Use ExecTree instead. 151 func (nash *Shell) ExecuteTree(tr *ast.Tree) ([]sh.Obj, error) { 152 return nash.interp.ExecuteTree(tr) 153 } 154 155 // ExecTree evaluates the given abstract syntax tree. 156 // it returns the object result of eval or nil when not applied and error. 157 func (nash *Shell) ExecTree(tree *ast.Tree) ([]sh.Obj, error) { 158 return nash.interp.ExecuteTree(tree) 159 } 160 161 // SetStdout set the stdout of the nash engine. 162 func (nash *Shell) SetStdout(out io.Writer) { 163 nash.interp.SetStdout(out) 164 } 165 166 // SetStderr set the stderr of nash engine 167 func (nash *Shell) SetStderr(err io.Writer) { 168 nash.interp.SetStderr(err) 169 } 170 171 // SetStdin set the stdin of the nash engine 172 func (nash *Shell) SetStdin(in io.Reader) { 173 nash.interp.SetStdin(in) 174 } 175 176 // Stdin is the interpreter standard input 177 func (nash *Shell) Stdin() io.Reader { return nash.interp.Stdin() } 178 179 // Stdout is the interpreter standard output 180 func (nash *Shell) Stdout() io.Writer { return nash.interp.Stdout() } 181 182 // Stderr is the interpreter standard error 183 func (nash *Shell) Stderr() io.Writer { return nash.interp.Stderr() } 184 185 // Setvar sets or updates the variable in the nash session. It 186 // returns true if variable was found and properly updated. 187 func (nash *Shell) Setvar(name string, value sh.Obj) bool { 188 return nash.interp.Setvar(name, value) 189 } 190 191 // Newvar creates a new variable in the interpreter scope 192 func (nash *Shell) Newvar(name string, value sh.Obj) { 193 nash.interp.Newvar(name, value) 194 } 195 196 // Getvar retrieves a variable from nash session 197 func (nash *Shell) Getvar(name string) (sh.Obj, bool) { 198 return nash.interp.Getvar(name) 199 } 200 201 func args2Nash(args []string) string { 202 ret := "(" 203 204 for i := 0; i < len(args); i++ { 205 ret += `"` + args[i] + `"` 206 207 if i < (len(args) - 1) { 208 ret += " " 209 } 210 } 211 212 return ret + ")" 213 }