github.com/coveo/gotemplate@v2.7.7+incompatible/utils/exec.go (about) 1 package utils 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "os/exec" 8 "regexp" 9 "runtime" 10 "strings" 11 ) 12 13 // https://regex101.com/r/ykVKPt/6 14 var shebang = regexp.MustCompile(`(?sm)^(?:\s*#!\s*(?P<program>[^\s]*)[ \t]*(?P<app>[^\s]*)?\s*$)?\s*(?P<source>.*)`) 15 16 // IsShebangScript determines if the supplied code has a Shebang definition #! program subprogram 17 func IsShebangScript(content string) bool { 18 matches := shebang.FindStringSubmatch(strings.TrimSpace(content)) 19 return len(matches) > 0 && matches[1] != "" 20 } 21 22 // ScriptParts splits up the supplied content into program, subprogram and source if the content matches Shebang defintion 23 func ScriptParts(content string) (program, subprogram, source string) { 24 matches := shebang.FindStringSubmatch(strings.TrimSpace(content)) 25 if len(matches) > 0 { 26 program = matches[1] 27 subprogram = matches[2] 28 source = matches[3] 29 } else { 30 source = content 31 } 32 return 33 } 34 35 // GetCommandFromFile returns an exec.Cmd structure to run the supplied script file 36 func GetCommandFromFile(filename string, args ...interface{}) (cmd *exec.Cmd, err error) { 37 script, err := ioutil.ReadFile(filename) 38 if err != nil { 39 return 40 } 41 42 executer, delegate, command := ScriptParts(strings.TrimSpace(string(script))) 43 44 strArgs := GlobFunc(args...) 45 46 if executer != "" { 47 command = executer 48 strArgs = append([]string{filename}, strArgs...) 49 if delegate != "" { 50 strArgs = append([]string{delegate}, strArgs...) 51 } 52 } else if _, errPath := exec.LookPath(command); errPath != nil { 53 if strings.Contains(command, " ") { 54 // The command is a string that should be splitted up into several parts 55 split := strings.Split(command, " ") 56 command = split[0] 57 strArgs = append(split[1:], strArgs...) 58 } else { 59 // The command does not exist 60 return 61 } 62 } 63 64 cmd = exec.Command(command, strArgs...) 65 return 66 } 67 68 // GetCommandFromString returns an exec.Cmd structure to run the supplied command 69 func GetCommandFromString(script string, args ...interface{}) (cmd *exec.Cmd, tempFile string, err error) { 70 if executer, delegate, command := ScriptParts(strings.TrimSpace(script)); executer != "" { 71 cmd, tempFile, err = saveTempFile(fmt.Sprintf("#! %s %s\n%s", executer, delegate, command), args...) 72 } else { 73 strArgs := GlobFunc(args...) 74 if _, err = exec.LookPath(command); err == nil { 75 cmd = exec.Command(command, strArgs...) 76 return 77 } 78 if IsCommand(command) { 79 // The command does just not exist, we return the error 80 return 81 } 82 83 if cmd, tempFile, err = saveTempFile(fmt.Sprintf("#! %s\n%s", getDefaultShell(), command), args...); err != nil { 84 return 85 } 86 } 87 return 88 } 89 90 // IsCommand ensures that the supplied command does not contain any shell specific characters 91 func IsCommand(command string) bool { 92 return !strings.ContainsAny(command, " \t|&$,;(){}<>[]") 93 } 94 95 func saveTempFile(content string, args ...interface{}) (cmd *exec.Cmd, fileName string, err error) { 96 var temp *os.File 97 if temp, err = ioutil.TempFile("", "exec_"); err != nil { 98 return 99 } 100 101 if _, err = temp.WriteString(content); err != nil { 102 return 103 } 104 temp.Close() 105 fileName = temp.Name() 106 cmd, err = GetCommandFromFile(fileName, args...) 107 return 108 } 109 110 func getDefaultShell() string { 111 if defaultShell != "" { 112 return defaultShell 113 } 114 defShells := []string{"bash", "sh", "zsh", "ksh"} 115 if runtime.GOOS == "windows" { 116 defShells = []string{"powershell", "pwsh", "cmd"} 117 } 118 for _, sh := range defShells { 119 if sh, err := exec.LookPath(sh); err == nil { 120 defaultShell = sh 121 break 122 } 123 } 124 return defaultShell 125 } 126 127 var defaultShell string 128 129 // GetEnv returns the environment variable value or defaultValue if it does not exist. 130 func GetEnv(varName, defaultValue string) string { 131 if value, exist := os.LookupEnv(varName); exist { 132 return value 133 } 134 return defaultValue 135 }