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 }