blob: d3ce838af399e92442f3b08292011423c8ac5e8e [file] [log] [blame]
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package maker
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
)
var (
// EnvVars holds the environment overrides used when spawning external commands.
EnvVars = map[string][]string{}
)
// ExecAt executes "path" with the specified arguments with the working
// directory set to "wd".
func ExecAt(wd string, verbose int, path string, args ...string) error {
before := time.Now()
cmd := exec.Command(path, args...)
cmd.Env = getEnvVars()
cmd.Dir = wd
if verbose > 0 {
log.Printf("-> %s", strings.Join(cmd.Args, " "))
}
if verbose > 1 {
log.Printf("Working directory: %v", cmd.Dir)
log.Printf("Environment:")
for _, v := range cmd.Env {
log.Printf("• %s", v)
}
}
output, err := cmd.CombinedOutput()
duration := time.Now().Sub(before)
switch {
case err != nil:
err = fmt.Errorf("Command: \"%v\" %v", strings.Join(cmd.Args, " "), err)
log.Printf("\n\n%s\n%v", string(output), err)
return err
case verbose > 1:
if msg := string(output); msg != "" {
log.Printf("\n%s\n--- %s %v succeeded ---", msg, path, duration)
} else {
log.Printf("%s %v succeeded", path, duration)
}
}
return nil
}
// Command builds and returns a new Step that runs the specified external binary
// with the supplied arguments. The newly created Step will be made to depend on
// the binary.
func Command(binary Entity, args ...string) *Step {
wd := Paths.Root
return NewStep(func(step *Step) error {
return ExecAt(wd, Config.Verbose, binary.Name(), args...)
}).DependsOn(binary)
}
type envVar struct {
key, value string
}
func getEnvVars() []string {
env := map[string]envVar{}
for _, pair := range os.Environ() {
v := strings.LastIndex(pair, "=")
key, value := pair[:v], pair[v+1:]
env[strings.ToUpper(key)] = envVar{key, value}
}
sep := fmt.Sprintf("%c", filepath.ListSeparator)
for key, values := range EnvVars {
keyUpper := strings.ToUpper(key)
if existing, found := env[keyUpper]; found {
values = append(values, existing.value)
env[keyUpper] = envVar{existing.key, strings.Join(values, sep)}
} else {
env[keyUpper] = envVar{key, strings.Join(values, sep)}
}
}
vars := []string{}
for _, v := range env {
vars = append(vars, v.key+"="+v.value)
}
return vars
}