2015-10-16 20:32:36 -04:00
|
|
|
package packer
|
|
|
|
|
2015-10-16 20:36:29 -04:00
|
|
|
import (
|
2018-11-30 09:47:43 -05:00
|
|
|
"log"
|
2015-10-16 20:36:29 -04:00
|
|
|
"os"
|
2018-11-30 09:47:43 -05:00
|
|
|
"os/user"
|
2015-10-16 20:36:29 -04:00
|
|
|
"path/filepath"
|
2018-12-02 19:56:33 -05:00
|
|
|
"strings"
|
2015-10-16 20:36:29 -04:00
|
|
|
)
|
|
|
|
|
2015-10-16 20:32:36 -04:00
|
|
|
// ConfigFile returns the default path to the configuration file. On
|
|
|
|
// Unix-like systems this is the ".packerconfig" file in the home directory.
|
|
|
|
// On Windows, this is the "packer.config" file in the application data
|
|
|
|
// directory.
|
|
|
|
func ConfigFile() (string, error) {
|
|
|
|
return configFile()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConfigDir returns the configuration directory for Packer.
|
|
|
|
func ConfigDir() (string, error) {
|
|
|
|
return configDir()
|
|
|
|
}
|
2015-10-16 20:36:29 -04:00
|
|
|
|
2018-11-30 09:47:43 -05:00
|
|
|
func homeDir() (string, error) {
|
2020-08-31 08:35:15 -04:00
|
|
|
// Prefer $APPDATA over $HOME in Windows.
|
|
|
|
// This makes it possible to use packer plugins (as installed by Chocolatey)
|
|
|
|
// in cmd/ps and msys2.
|
|
|
|
// See https://github.com/hashicorp/packer/issues/9795
|
|
|
|
if home := os.Getenv("APPDATA"); home != "" {
|
2018-11-30 09:47:43 -05:00
|
|
|
return home, nil
|
|
|
|
}
|
|
|
|
|
2020-08-31 08:35:15 -04:00
|
|
|
// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
|
|
|
|
if home := os.Getenv("HOME"); home != "" {
|
2019-01-04 08:10:30 -05:00
|
|
|
return home, nil
|
|
|
|
}
|
|
|
|
|
2018-11-30 09:47:43 -05:00
|
|
|
// Fall back to the passwd database if not found which follows
|
|
|
|
// the same semantics as bourne shell
|
|
|
|
u, err := user.Current()
|
|
|
|
|
|
|
|
// Get homedir from specified username
|
|
|
|
// if it is set and different than what we have
|
|
|
|
if username := os.Getenv("USER"); username != "" && err == nil && u.Username != username {
|
|
|
|
u, err = user.Lookup(username)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fail if we were unable to read the record
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return u.HomeDir, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func configFile() (string, error) {
|
2019-07-25 16:06:41 -04:00
|
|
|
var dir string
|
|
|
|
if cd := os.Getenv("PACKER_CONFIG_DIR"); cd != "" {
|
|
|
|
log.Printf("Detected config directory from env var: %s", cd)
|
|
|
|
dir = cd
|
|
|
|
} else {
|
|
|
|
homedir, err := homeDir()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
dir = homedir
|
2018-11-30 09:47:43 -05:00
|
|
|
}
|
|
|
|
return filepath.Join(dir, defaultConfigFile), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func configDir() (string, error) {
|
2019-07-25 16:06:41 -04:00
|
|
|
var dir string
|
|
|
|
if cd := os.Getenv("PACKER_CONFIG_DIR"); cd != "" {
|
|
|
|
log.Printf("Detected config directory from env var: %s", cd)
|
|
|
|
dir = cd
|
|
|
|
} else {
|
|
|
|
homedir, err := homeDir()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
dir = homedir
|
2018-11-30 09:47:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
return filepath.Join(dir, defaultConfigDir), nil
|
|
|
|
}
|
2018-12-02 19:56:33 -05:00
|
|
|
|
|
|
|
// Given a path, check to see if it's using ~ to reference a user directory.
|
2018-12-05 18:34:09 -05:00
|
|
|
// If so, then replace that component with the requested user directory.
|
|
|
|
// In "~/", "~" gets replaced by current user's home dir.
|
|
|
|
// In "~root/", "~user" gets replaced by root's home dir.
|
|
|
|
// ~ has to be the first character of path for ExpandUser change it.
|
2018-12-02 19:56:33 -05:00
|
|
|
func ExpandUser(path string) (string, error) {
|
|
|
|
var (
|
|
|
|
u *user.User
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
// refuse to do anything with a zero-length path
|
|
|
|
if len(path) == 0 {
|
|
|
|
return path, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no expansion was specified, then refuse that too
|
|
|
|
if path[0] != '~' {
|
|
|
|
return path, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab everything up to the first filepath.Separator
|
|
|
|
idx := strings.IndexAny(path, `/\`)
|
|
|
|
if idx == -1 {
|
|
|
|
idx = len(path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we should be able to extract the username
|
|
|
|
username := path[:idx]
|
|
|
|
|
|
|
|
// Check if the current user was requested
|
|
|
|
if username == "~" {
|
|
|
|
u, err = user.Current()
|
|
|
|
} else {
|
|
|
|
u, err = user.Lookup(username[1:])
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we couldn't figure that out, then fail here
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now we can replace the path with u.HomeDir
|
|
|
|
return filepath.Join(u.HomeDir, path[idx:]), nil
|
|
|
|
}
|