Merge pull request #192 from c4milo/loading-cli-config

Ports Packer code to load CLI configuration and external plugins
This commit is contained in:
Mitchell Hashimoto 2014-08-19 10:52:33 -07:00
commit 2edc7a5c9b
4 changed files with 141 additions and 0 deletions

9
cliconfig.go Normal file
View File

@ -0,0 +1,9 @@
package main
// ConfigFile returns the default path to the configuration file. On
// Unix-like systems this is the ".terraformrc" file in the home directory.
// On Windows, this is the "terraform.rc" file in the application data
// directory.
func ConfigFile() (string, error) {
return configFile()
}

45
cliconfig_unix.go Normal file
View File

@ -0,0 +1,45 @@
// +build darwin freebsd linux netbsd openbsd
package main
import (
"bytes"
"errors"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
)
func configFile() (string, error) {
dir, err := configDir()
if err != nil {
return "", err
}
return filepath.Join(dir, ".terraformrc"), nil
}
func configDir() (string, error) {
// First prefer the HOME environmental variable
if home := os.Getenv("HOME"); home != "" {
log.Printf("Detected home directory from env var: %s", home)
return home, nil
}
// If that fails, try the shell
var stdout bytes.Buffer
cmd := exec.Command("sh", "-c", "eval echo ~$USER")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err
}
result := strings.TrimSpace(stdout.String())
if result == "" {
return "", errors.New("blank output")
}
return result, nil
}

37
cliconfig_windows.go Normal file
View File

@ -0,0 +1,37 @@
// +build windows
package main
import (
"path/filepath"
"syscall"
"unsafe"
)
var (
shell = syscall.MustLoadDLL("Shell32.dll")
getFolderPath = shell.MustFindProc("SHGetFolderPathW")
)
const CSIDL_APPDATA = 26
func configFile() (string, error) {
dir, err := configDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "terraform.rc"), nil
}
func configDir() (string, error) {
b := make([]uint16, syscall.MAX_PATH)
// See: http://msdn.microsoft.com/en-us/library/windows/desktop/bb762181(v=vs.85).aspx
r, _, err := getFolderPath.Call(0, CSIDL_APPDATA, 0, 0, uintptr(unsafe.Pointer(&b[0])))
if uint32(r) != 0 {
return "", err
}
return syscall.UTF16ToString(b), nil
}

50
main.go
View File

@ -107,6 +107,24 @@ func wrappedMain() int {
HelpWriter: os.Stdout, HelpWriter: os.Stdout,
} }
clicfgFile, err := cliConfigFile()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading CLI configuration: \n\n%s\n", err)
return 1
}
usrcfg, err := LoadConfig(clicfgFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading CLI configuration: \n\n%s\n", err)
return 1
}
config = *config.Merge(usrcfg)
// Initialize the TFConfig settings for the commands...
ContextOpts.Providers = config.ProviderFactories()
ContextOpts.Provisioners = config.ProvisionerFactories()
exitCode, err := cli.Run() exitCode, err := cli.Run()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error()) fmt.Fprintf(os.Stderr, "Error executing CLI: %s\n", err.Error())
@ -116,6 +134,38 @@ func wrappedMain() int {
return exitCode return exitCode
} }
func cliConfigFile() (string, error) {
mustExist := true
configFilePath := os.Getenv("TERRAFORM_CONFIG")
if configFilePath == "" {
var err error
configFilePath, err = configFile()
mustExist = false
if err != nil {
log.Printf("Error detecting default CLI config file path: %s", err)
}
}
log.Printf("Attempting to open CLI config file: %s", configFilePath)
f, err := os.Open(configFilePath)
if err != nil {
if !os.IsNotExist(err) {
return "", err
}
if mustExist {
return "", err
}
log.Println("File doesn't exist, but doesn't need to. Ignoring.")
return "", nil
}
defer f.Close()
return configFilePath, nil
}
// copyOutput uses output prefixes to determine whether data on stdout // copyOutput uses output prefixes to determine whether data on stdout
// should go to stdout or stderr. This is due to panicwrap using stderr // should go to stdout or stderr. This is due to panicwrap using stderr
// as the log and error channel. // as the log and error channel.