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  }