Make the path to .pulumi folder configurable with an ENV variable (#3300)

Introduces `PULUMI_HOME` environment variable which points to a path to the path to `.pulumi` folder. Defaults to `<user's home dir> + ".pulumi"` if not specified.

Fixes #2966. In addition to plugins, it "moves" the credentials file, templates, workspaces.

`bin` folder is intact: to move it, we need to adjust all installation scripts to respect `PULUMI_HOME` and put executables in the proper `bin` folder.
This commit is contained in:
Mikhail Shilkov 2019-10-09 00:01:46 +02:00 committed by Pat Gavlin
parent 22799879e8
commit 69743fe2bf
7 changed files with 49 additions and 37 deletions

View file

@ -13,6 +13,9 @@ CHANGELOG
- Support renaming stack projects via `pulumi stack rename`.
[#3292](https://github.com/pulumi/pulumi/pull/3292)
- Make the location of `.pulumi` folder configurable with an environment variable.
[#3300](https://github.com/pulumi/pulumi/pull/3300) (Fixes [#2966](https://github.com/pulumi/pulumi/issues/2966))
- `pulumi update` can now be scoped to update a single resource by adding a `--target urn` or `-t urn`
argument. Multiple resources can be specified using `-t urn1 -t urn2`.

View file

@ -353,7 +353,7 @@ func getUpgradeCommand() string {
return "$ brew upgrade pulumi"
}
if filepath.Dir(exe) != filepath.Join(curUser.HomeDir, ".pulumi", "bin") {
if filepath.Dir(exe) != filepath.Join(curUser.HomeDir, workspace.BookkeepingDir, "bin") {
return ""
}

View file

@ -18,7 +18,6 @@ import (
"encoding/json"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"github.com/pkg/errors"
@ -84,18 +83,17 @@ type Credentials struct {
// getCredsFilePath returns the path to the Pulumi credentials file on disk, regardless of
// whether it exists or not.
func getCredsFilePath() (string, error) {
user, err := user.Current()
if user == nil || err != nil {
return "", errors.Wrapf(err, "getting creds file path: failed to get current user")
}
// Allow the folder we use to store credentials to be overridden by tests
pulumiFolder := os.Getenv(PulumiCredentialsPathEnvVar)
if pulumiFolder == "" {
pulumiFolder = filepath.Join(user.HomeDir, BookkeepingDir)
folder, err := GetPulumiHomeDir()
if err != nil {
return "", errors.Wrapf(err, "failed to get the home path")
}
pulumiFolder = folder
}
err = os.MkdirAll(pulumiFolder, 0700)
err := os.MkdirAll(pulumiFolder, 0700)
if err != nil {
return "", errors.Wrapf(err, "failed to create '%s'", pulumiFolder)
}

View file

@ -61,6 +61,11 @@ const (
WorkspaceFile = "workspace.json"
// CachedVersionFile is the name of the file we use to store when we last checked if the CLI was out of date
CachedVersionFile = ".cachedVersionInfo"
// PulumiHomeEnvVar is a path to the '.pulumi' folder with plugins, access token, etc.
// The folder can have any name, not necessarily '.pulumi'.
// It defaults to the '<user's home>/.pulumi' if not specified.
PulumiHomeEnvVar = "PULUMI_HOME"
)
// DetectProjectPath locates the closest project from the current working directory, or an error if not found.
@ -180,10 +185,33 @@ func isMarkupFile(path string, expect string) bool {
// GetCachedVersionFilePath returns the location where the CLI caches information from pulumi.com on the newest
// available version of the CLI
func GetCachedVersionFilePath() (string, error) {
return GetPulumiPath(CachedVersionFile)
}
// GetPulumiHomeDir returns the path of the '.pulumi' folder where Pulumi puts its artifacts.
func GetPulumiHomeDir() (string, error) {
// Allow the folder we use to be overridden by an environment variable
dir := os.Getenv(PulumiHomeEnvVar)
if dir != "" {
return dir, nil
}
// Otherwise, use the current user's home dir + .pulumi
user, err := user.Current()
if err != nil {
return "", errors.Wrapf(err, "getting current user")
}
return filepath.Join(user.HomeDir, BookkeepingDir), nil
}
// GetPulumiPath returns the path to a file or directory under the '.pulumi' folder. It joins the path of
// the '.pulumi' folder with elements passed as arguments.
func GetPulumiPath(elem ...string) (string, error) {
homeDir, err := GetPulumiHomeDir()
if err != nil {
return "", err
}
return filepath.Join(user.HomeDir, BookkeepingDir, CachedVersionFile), nil
return filepath.Join(append([]string{homeDir}, elem...)...), nil
}

View file

@ -21,7 +21,6 @@ import (
"net/http"
"os"
"os/exec"
"os/user"
"path"
"path/filepath"
"regexp"
@ -353,11 +352,7 @@ func HasPluginGTE(plug PluginInfo) (bool, error) {
// GetPolicyDir returns the directory in which policies on the current machine are managed.
func GetPolicyDir() (string, error) {
u, err := user.Current()
if u == nil || err != nil {
return "", errors.Wrapf(err, "getting user home directory")
}
return filepath.Join(u.HomeDir, BookkeepingDir, PolicyDir), nil
return GetPulumiPath(PolicyDir)
}
// GetPolicyPath finds a PolicyPack by its name version, as well as a bool marked true if the path
@ -385,11 +380,7 @@ func GetPolicyPath(name, version string) (string, bool, error) {
// GetPluginDir returns the directory in which plugins on the current machine are managed.
func GetPluginDir() (string, error) {
u, err := user.Current()
if u == nil || err != nil {
return "", errors.Wrapf(err, "getting user home directory")
}
return filepath.Join(u.HomeDir, BookkeepingDir, PluginDir), nil
return GetPulumiPath(PluginDir)
}
// GetPlugins returns a list of installed plugins.

View file

@ -18,14 +18,13 @@ import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"regexp"
"runtime"
"strings"
"github.com/texttheater/golang-levenshtein/levenshtein"
git "gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
"github.com/pkg/errors"
@ -382,17 +381,12 @@ func (template Template) CopyTemplateFiles(
func GetTemplateDir() (string, error) {
// Allow the folder we use to store templates to be overridden.
dir := os.Getenv(pulumiLocalTemplatePathEnvVar)
// Use the classic template directory if there is no override.
if dir == "" {
u, err := user.Current()
if u == nil || err != nil {
return "", errors.Wrap(err, "getting user home directory")
}
dir = filepath.Join(u.HomeDir, BookkeepingDir, TemplateDir)
if dir != "" {
return dir, nil
}
return dir, nil
// Use the classic template directory if there is no override.
return GetPulumiPath(TemplateDir)
}
// We are moving towards a world where these restrictions will be enforced by all our backends. When we get there,

View file

@ -21,7 +21,6 @@ import (
"encoding/json"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"strings"
"sync"
@ -167,11 +166,10 @@ func (pw *projectWorkspace) readSettings() error {
}
func (pw *projectWorkspace) settingsPath() string {
user, err := user.Current()
contract.AssertNoErrorf(err, "could not get current user")
uniqueFileName := string(pw.name) + "-" + sha1HexString(pw.project) + "-" + WorkspaceFile
return filepath.Join(user.HomeDir, BookkeepingDir, WorkspaceDir, uniqueFileName)
path, err := GetPulumiPath(WorkspaceDir, uniqueFileName)
contract.AssertNoErrorf(err, "could not get workspace path")
return path
}
// sha1HexString returns a hex string of the sha1 hash of value.