github.com/teddydd/sh@v2.6.4+incompatible/shell/source.go (about)

     1  // Copyright (c) 2018, Daniel Martí <mvdan@mvdan.cc>
     2  // See LICENSE for licensing information
     3  
     4  package shell
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"os"
    10  
    11  	"mvdan.cc/sh/expand"
    12  	"mvdan.cc/sh/interp"
    13  	"mvdan.cc/sh/syntax"
    14  )
    15  
    16  // SourceFile sources a shell file from disk and returns the variables
    17  // declared in it. It is a convenience function that uses a default shell
    18  // parser, parses a file from disk, and calls SourceNode.
    19  //
    20  // This function should be used with caution, as it can interpret arbitrary
    21  // code. Untrusted shell programs shoudn't be sourced outside of a sandbox
    22  // environment.
    23  func SourceFile(ctx context.Context, path string) (map[string]expand.Variable, error) {
    24  	f, err := os.Open(path)
    25  	if err != nil {
    26  		return nil, fmt.Errorf("could not open: %v", err)
    27  	}
    28  	defer f.Close()
    29  	file, err := syntax.NewParser().Parse(f, path)
    30  	if err != nil {
    31  		return nil, fmt.Errorf("could not parse: %v", err)
    32  	}
    33  	return SourceNode(ctx, file)
    34  }
    35  
    36  // SourceNode sources a shell program from a node and returns the
    37  // variables declared in it. It accepts the same set of node types that
    38  // interp/Runner.Run does.
    39  //
    40  // This function should be used with caution, as it can interpret arbitrary
    41  // code. Untrusted shell programs shoudn't be sourced outside of a sandbox
    42  // environment.
    43  func SourceNode(ctx context.Context, node syntax.Node) (map[string]expand.Variable, error) {
    44  	r, _ := interp.New()
    45  	if err := r.Run(ctx, node); err != nil {
    46  		return nil, fmt.Errorf("could not run: %v", err)
    47  	}
    48  	// delete the internal shell vars that the user is not
    49  	// interested in
    50  	delete(r.Vars, "PWD")
    51  	delete(r.Vars, "HOME")
    52  	delete(r.Vars, "PATH")
    53  	delete(r.Vars, "IFS")
    54  	delete(r.Vars, "OPTIND")
    55  	return r.Vars, nil
    56  }