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.
105 lines
2.3 KiB
Go
105 lines
2.3 KiB
Go
// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/pulumi/pulumi/pkg/encoding"
|
|
|
|
"github.com/pulumi/pulumi/pkg/tokens"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/pulumi/pulumi/pkg/util/cmdutil"
|
|
)
|
|
|
|
func newStackLsCmd() *cobra.Command {
|
|
return &cobra.Command{
|
|
Use: "ls",
|
|
Short: "List all known stacks",
|
|
Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error {
|
|
currentStack, err := getCurrentStack()
|
|
if err != nil {
|
|
// If we couldn't figure out the current stack, just don't print the '*' later
|
|
// on instead of failing.
|
|
currentStack = tokens.QName("")
|
|
}
|
|
|
|
stacks, err := getStacks()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fmt.Printf("%-20s %-48s %-12s\n", "NAME", "LAST UPDATE", "RESOURCE COUNT")
|
|
for _, stack := range stacks {
|
|
_, _, snapshot, err := getStack(stack)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
// Now print out the name, last deployment time (if any), and resources (if any).
|
|
lastDeploy := "n/a"
|
|
resourceCount := "n/a"
|
|
if snapshot != nil {
|
|
lastDeploy = snapshot.Time.String()
|
|
resourceCount = strconv.Itoa(len(snapshot.Resources))
|
|
}
|
|
display := stack.String()
|
|
if stack == currentStack {
|
|
display += "*" // fancify the current stack.
|
|
}
|
|
fmt.Printf("%-20s %-48s %-12s\n", display, lastDeploy, resourceCount)
|
|
}
|
|
|
|
return nil
|
|
}),
|
|
}
|
|
}
|
|
|
|
func getStacks() ([]tokens.QName, error) {
|
|
var stacks []tokens.QName
|
|
|
|
w, err := newWorkspace()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Read the stack directory.
|
|
path := w.StackPath("")
|
|
|
|
files, err := ioutil.ReadDir(path)
|
|
if err != nil && !os.IsNotExist(err) {
|
|
return nil, errors.Errorf("could not read stacks: %v", err)
|
|
}
|
|
|
|
for _, file := range files {
|
|
// Ignore directories.
|
|
if file.IsDir() {
|
|
continue
|
|
}
|
|
|
|
// Skip files without valid extensions (e.g., *.bak files).
|
|
stackfn := file.Name()
|
|
ext := filepath.Ext(stackfn)
|
|
if _, has := encoding.Marshalers[ext]; !has {
|
|
continue
|
|
}
|
|
|
|
// Read in this stack's information.
|
|
name := tokens.QName(stackfn[:len(stackfn)-len(ext)])
|
|
_, _, _, err := getStack(name)
|
|
if err != nil {
|
|
continue // failure reading the stack information.
|
|
}
|
|
|
|
stacks = append(stacks, name)
|
|
}
|
|
|
|
return stacks, nil
|
|
}
|