2017-03-02 11:46:20 +02:00
|
|
|
package task
|
|
|
|
|
|
|
|
import (
|
2017-03-05 21:49:44 +02:00
|
|
|
"bytes"
|
2017-03-02 12:28:34 +02:00
|
|
|
"encoding/json"
|
2017-03-09 00:03:17 +02:00
|
|
|
"errors"
|
2017-03-02 12:28:34 +02:00
|
|
|
"io/ioutil"
|
2017-03-02 11:46:20 +02:00
|
|
|
"os"
|
2017-03-05 21:49:44 +02:00
|
|
|
"runtime"
|
2017-03-02 11:46:20 +02:00
|
|
|
"strings"
|
2017-03-05 21:49:44 +02:00
|
|
|
"text/template"
|
2017-03-02 12:28:34 +02:00
|
|
|
|
2017-03-12 22:18:59 +02:00
|
|
|
"github.com/go-task/task/execext"
|
|
|
|
|
2017-03-02 12:28:34 +02:00
|
|
|
"github.com/BurntSushi/toml"
|
2017-03-05 11:08:24 +02:00
|
|
|
"gopkg.in/yaml.v2"
|
2017-03-02 12:28:34 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2017-03-05 21:21:22 +02:00
|
|
|
// TaskvarsFilePath file containing additional variables
|
|
|
|
TaskvarsFilePath = "Taskvars"
|
2017-03-09 00:03:17 +02:00
|
|
|
// ErrMultilineResultCmd is returned when a command returns multiline result
|
|
|
|
ErrMultilineResultCmd = errors.New("Got multiline result from command")
|
2017-03-02 11:46:20 +02:00
|
|
|
)
|
|
|
|
|
2017-03-09 01:13:52 +02:00
|
|
|
var varCmds = make(map[string]string)
|
|
|
|
|
2017-03-07 21:07:03 +02:00
|
|
|
func handleDynamicVariableContent(value string) (string, error) {
|
2017-03-08 23:34:44 +02:00
|
|
|
if value == "" || value[0] != '$' {
|
2017-03-07 21:07:03 +02:00
|
|
|
return value, nil
|
|
|
|
}
|
2017-03-09 01:13:52 +02:00
|
|
|
if result, ok := varCmds[value]; ok {
|
|
|
|
return result, nil
|
|
|
|
}
|
2017-03-12 22:18:59 +02:00
|
|
|
cmd := execext.NewCommand(value[1:])
|
2017-03-07 21:07:03 +02:00
|
|
|
cmd.Stdin = os.Stdin
|
|
|
|
cmd.Stderr = os.Stderr
|
2017-03-09 00:03:17 +02:00
|
|
|
b, err := cmd.Output()
|
2017-03-07 21:07:03 +02:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2017-03-09 00:03:17 +02:00
|
|
|
if b[len(b)-1] == '\n' {
|
|
|
|
b = b[:len(b)-1]
|
|
|
|
}
|
|
|
|
if bytes.ContainsRune(b, '\n') {
|
|
|
|
return "", ErrMultilineResultCmd
|
|
|
|
}
|
2017-03-09 01:13:52 +02:00
|
|
|
result := strings.TrimSpace(string(b))
|
|
|
|
varCmds[value] = result
|
|
|
|
return result, nil
|
2017-03-07 21:07:03 +02:00
|
|
|
}
|
|
|
|
|
2017-03-08 23:36:05 +02:00
|
|
|
func (t *Task) handleVariables() (map[string]string, error) {
|
2017-03-02 11:46:20 +02:00
|
|
|
localVariables := make(map[string]string)
|
2017-03-05 20:56:07 +02:00
|
|
|
for key, value := range t.Vars {
|
2017-03-07 21:07:03 +02:00
|
|
|
val, err := handleDynamicVariableContent(value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
localVariables[key] = val
|
2017-03-02 11:46:20 +02:00
|
|
|
}
|
2017-03-05 21:21:22 +02:00
|
|
|
if fileVariables, err := readTaskvarsFile(); err == nil {
|
2017-03-02 12:28:34 +02:00
|
|
|
for key, value := range fileVariables {
|
2017-03-07 21:07:03 +02:00
|
|
|
val, err := handleDynamicVariableContent(value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
localVariables[key] = val
|
2017-03-02 12:28:34 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-02 11:46:20 +02:00
|
|
|
for key, value := range getEnvironmentVariables() {
|
2017-03-09 01:03:21 +02:00
|
|
|
localVariables[key] = value
|
2017-03-02 11:46:20 +02:00
|
|
|
}
|
2017-03-02 12:28:34 +02:00
|
|
|
return localVariables, nil
|
2017-03-02 11:46:20 +02:00
|
|
|
}
|
|
|
|
|
2017-03-05 21:49:44 +02:00
|
|
|
var templateFuncs = template.FuncMap{
|
|
|
|
"OS": func() string { return runtime.GOOS },
|
|
|
|
"ARCH": func() string { return runtime.GOARCH },
|
2017-03-12 22:18:59 +02:00
|
|
|
"IsSH": func() bool { return execext.ShExists },
|
2017-03-05 21:49:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// ReplaceVariables writes vars into initial string
|
|
|
|
func ReplaceVariables(initial string, vars map[string]string) (string, error) {
|
|
|
|
t, err := template.New("").Funcs(templateFuncs).Parse(initial)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
b := bytes.NewBuffer(nil)
|
|
|
|
if err = t.Execute(b, vars); err != nil {
|
|
|
|
return "", err
|
2017-03-02 11:46:20 +02:00
|
|
|
}
|
2017-03-05 21:49:44 +02:00
|
|
|
return b.String(), nil
|
2017-03-02 11:46:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetEnvironmentVariables returns environment variables as map
|
|
|
|
func getEnvironmentVariables() map[string]string {
|
2017-03-25 16:01:44 +02:00
|
|
|
var (
|
|
|
|
env = os.Environ()
|
|
|
|
m = make(map[string]string, len(env))
|
|
|
|
)
|
|
|
|
|
|
|
|
for _, e := range env {
|
|
|
|
keyVal := strings.SplitN(e, "=", 2)
|
|
|
|
key, val := keyVal[0], keyVal[1]
|
|
|
|
m[key] = val
|
2017-03-02 11:46:20 +02:00
|
|
|
}
|
2017-03-25 16:01:44 +02:00
|
|
|
return m
|
2017-03-02 11:46:20 +02:00
|
|
|
}
|
2017-03-02 12:28:34 +02:00
|
|
|
|
2017-03-05 21:21:22 +02:00
|
|
|
func readTaskvarsFile() (map[string]string, error) {
|
2017-03-02 12:28:34 +02:00
|
|
|
var variables map[string]string
|
2017-03-05 21:21:22 +02:00
|
|
|
if b, err := ioutil.ReadFile(TaskvarsFilePath + ".yml"); err == nil {
|
2017-03-02 12:28:34 +02:00
|
|
|
if err := yaml.Unmarshal(b, &variables); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-05 21:21:22 +02:00
|
|
|
return variables, nil
|
2017-03-02 12:28:34 +02:00
|
|
|
}
|
2017-03-05 21:21:22 +02:00
|
|
|
if b, err := ioutil.ReadFile(TaskvarsFilePath + ".json"); err == nil {
|
2017-03-02 12:28:34 +02:00
|
|
|
if err := json.Unmarshal(b, &variables); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-05 21:21:22 +02:00
|
|
|
return variables, nil
|
2017-03-02 12:28:34 +02:00
|
|
|
}
|
2017-03-05 21:21:22 +02:00
|
|
|
if b, err := ioutil.ReadFile(TaskvarsFilePath + ".toml"); err == nil {
|
2017-03-02 12:28:34 +02:00
|
|
|
if err := toml.Unmarshal(b, &variables); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-03-05 21:21:22 +02:00
|
|
|
return variables, nil
|
2017-03-02 12:28:34 +02:00
|
|
|
}
|
|
|
|
return variables, nil
|
|
|
|
}
|