pulumi/cmd/creds.go
Matt Ellis 3f1197ef84 Move .pulumi to root of a repository
Now, instead of having a .pulumi folder next to each project, we have
a single .pulumi folder in the root of the repository. This is created
by running `pulumi init`.

When run in a git repository, `pulumi init` will place the .pulumi
file next to the .git folder, so it can be shared across all projects
in a repository. When not in a git repository, it will be created in
the current working directory.

We also start tracking information about the repository itself, in a
new `repo.json` file stored in the root of the .pulumi folder. The
information we track are "owner" and "name" which map to information
we use on pulumi.com.

When run in a git repository with a remote named origin pointing to a
GitHub project, we compute the owner and name by deconstructing
information from the remote's URL. Otherwise, we just use the current
user's username and the name of the current working directory as the
owner and name, respectively.
2017-10-27 11:46:21 -07:00

108 lines
3 KiB
Go

// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
package cmd
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"os/user"
"path"
"github.com/pkg/errors"
)
// pulumiSettingsFolder is the name of the folder we put in the user's home dir to store settings.
// TODO(pulumi/pulumi-service#49): Return this from a function that takes OS-idioms into account.
const pulumiSettingsFolder = ".pulumi"
// permUserRWRestNone defines the file permissions that the
// user has RW access, and group and other have no access.
const permUserRWRestNone = 0600
// permUserAllRestNone defines the file permissions that the
// user has RWX access, and group and other have no access.
const permUserAllRestNone = 0700
// accountCredentials hold the information necessary for authenticating Pulumi Cloud API requests.
type accountCredentials struct {
AccessToken string `json:"accessToken"`
}
// getCredsFilePath returns the path to the Pulumi credentials file on disk, if it
// exists. Otherwise nil and the related OS error.
func getCredsFilePath() (string, error) {
user, err := user.Current()
if user == nil || err != nil {
return "", fmt.Errorf("getting creds file path: failed to get current user")
}
pulumiFolder := path.Join(user.HomeDir, pulumiSettingsFolder)
err = os.MkdirAll(pulumiFolder, permUserAllRestNone)
if err != nil {
return "", fmt.Errorf("failed to create '%s'", pulumiFolder)
}
return path.Join(pulumiFolder, "credentials.json"), nil
}
// errCredsNotFound is the error returned if the credentials file is not found.
var errCredsNotFound = errors.New("credentials file not found")
// getStoredCredentials returns any credentials stored on the local machine. Returns any
// IO error if found. errCredsNotFound if no credentials file is present.
func getStoredCredentials() (accountCredentials, error) {
var creds accountCredentials
credsFile, err := getCredsFilePath()
if err != nil {
return creds, err
}
// Creds file does not exist.
if _, err = os.Stat(credsFile); os.IsNotExist(err) {
return creds, errCredsNotFound
}
c, err := ioutil.ReadFile(credsFile)
if err != nil {
return creds, fmt.Errorf("reading '%s': %v", credsFile, err)
}
if err = json.Unmarshal(c, &creds); err != nil {
return creds, fmt.Errorf("unmarshalling credentials file: %v", err)
}
return creds, nil
}
// storeCredentials updates the stored credentials on the machine, replacing the
// existing set.
func storeCredentials(creds accountCredentials) error {
credsFile, err := getCredsFilePath()
if err != nil {
return err
}
raw, err := json.Marshal(creds)
if err != nil {
return fmt.Errorf("marshalling credentials object: %v", err)
}
return ioutil.WriteFile(credsFile, raw, permUserRWRestNone)
}
// deleteStoredCredentials deletes the user's stored credentials.
func deleteStoredCredentials() error {
credsFile, err := getCredsFilePath()
if err != nil {
return err
}
_, err = os.Stat(credsFile)
if os.IsNotExist(err) {
return nil
}
return os.Remove(credsFile)
}