github.com/jonsyu1/godel@v0.0.0-20171017211503-64567a0cf169/apps/distgo/pkg/script/script.go (about) 1 // Copyright 2016 Palantir Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package script 16 17 import ( 18 "bytes" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "os/exec" 24 "strings" 25 26 "github.com/pkg/errors" 27 28 "github.com/palantir/godel/apps/distgo/params" 29 ) 30 31 func Write(buildSpec params.ProductBuildSpec, script string) (name string, cleanup func() error, rErr error) { 32 tmpFile, err := ioutil.TempFile(buildSpec.ProjectDir, "") 33 if err != nil { 34 return "", nil, errors.Wrapf(err, "Failed to create script file") 35 } 36 cleanup = func() error { 37 return os.Remove(tmpFile.Name()) 38 } 39 // clean up unless everything below succeeds 40 runCleanup := true 41 defer func() { 42 if runCleanup { 43 if err := cleanup(); err != nil && rErr == nil { 44 rErr = errors.Wrapf(err, "failed to remove script file %s", tmpFile.Name()) 45 } 46 } 47 }() 48 49 if _, err := tmpFile.WriteString(fmt.Sprintf("#!/bin/bash\n%v", script)); err != nil { 50 return "", nil, errors.Wrapf(err, "Failed to write script file") 51 } 52 53 if err := tmpFile.Close(); err != nil { 54 return "", nil, errors.Wrapf(err, "Failed to close %v", tmpFile.Name()) 55 } 56 57 if err := os.Chmod(tmpFile.Name(), 0755); err != nil { 58 return "", nil, errors.Wrapf(err, "Failed to set file mode of %v to 0755", tmpFile.Name()) 59 } 60 61 runCleanup = false 62 return tmpFile.Name(), cleanup, nil 63 } 64 65 func WriteAndExecute(buildSpec params.ProductBuildSpec, script string, stdOut, stdErr io.Writer, additionalEnvVars map[string]string) (rErr error) { 66 // if script exists, write it as a temporary file and execute it 67 if script != "" { 68 tmpFile, cleanup, err := Write(buildSpec, script) 69 if err != nil { 70 return err 71 } 72 defer func() { 73 if err := cleanup(); err != nil && rErr == nil { 74 rErr = errors.Wrapf(err, "failed to remove script file %s", tmpFile) 75 } 76 }() 77 78 currEnv := os.Environ() 79 distEnvVars := additionalEnvVars 80 env := make([]string, len(currEnv), len(currEnv)+len(distEnvVars)) 81 copy(env, currEnv) 82 for k, v := range distEnvVars { 83 env = append(env, fmt.Sprintf("%v=%v", k, v)) 84 } 85 86 cmd := exec.Command(tmpFile) 87 cmd.Env = env 88 cmd.Dir = buildSpec.ProjectDir 89 cmd.Stdout = stdOut 90 cmd.Stderr = stdErr 91 if err := cmd.Run(); err != nil { 92 return errors.Wrapf(err, "Dist script for %v failed", buildSpec.ProductName) 93 } 94 } 95 return nil 96 } 97 98 func GetBuildArgs(buildSpec params.ProductBuildSpec, script string) ([]string, error) { 99 stdoutBuf := bytes.Buffer{} 100 stderrBuf := bytes.Buffer{} 101 combinedBuf := bytes.Buffer{} 102 stdoutMW := io.MultiWriter(&stdoutBuf, &combinedBuf) 103 stderrMW := io.MultiWriter(&stderrBuf, &combinedBuf) 104 if err := WriteAndExecute(buildSpec, script, stdoutMW, stderrMW, nil); err != nil || stderrBuf.String() != "" { 105 return nil, errors.Wrapf(err, "failed to execute build args script for %v: %v", buildSpec.ProductName, combinedBuf.String()) 106 } 107 108 buildArgsString := strings.TrimSpace(stdoutBuf.String()) 109 if buildArgsString == "" { 110 return nil, nil 111 } 112 return strings.Split(buildArgsString, "\n"), nil 113 }