Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cft/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ func Reader(r io.Reader) (*cft.Template, error) {

// File returns a cft.Template parsed from a file specified by fileName
func File(fileName string) (*cft.Template, error) {
if fileName == "-" {
return Reader(os.Stdin)
}

source, err := os.ReadFile(fileName)
if err != nil {
return &cft.Template{}, fmt.Errorf("unable to read file: %s", err)
Expand Down
32 changes: 32 additions & 0 deletions cft/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,38 @@ func TestReadFile(t *testing.T) {
}
}

func TestReadFile_stdin(t *testing.T) {
r, w, err := os.Pipe()
if err != nil {
t.Error(err)
}

_, err = w.WriteString(testTemplate)
if err != nil {
t.Error(err)
}

err = w.Close()
if err != nil {
t.Error(err)
}

oldStdin := os.Stdin
defer func() {
os.Stdin = oldStdin
}()
os.Stdin = r

actual, err := parse.File("-")
if err != nil {
t.Error(err)
}

if diff := cmp.Diff(actual.Map(), expected.Map()); diff != "" {
t.Errorf(diff)
}
}

func TestReadString(t *testing.T) {
actual, err := parse.String(testTemplate)
if err != nil {
Expand Down
29 changes: 26 additions & 3 deletions internal/cmd/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var Cmd = &cobra.Command{
Long: `Creates or updates a CloudFormation stack named <stack> from the template file <template>.
You can also create and execute changesets with this command.
If you don't specify a stack name, rain will use the template filename minus its extension.
You can use "-" as the template filename to read from stdin.

If a template needs to be packaged before it can be deployed, rain will package the template first.
Rain will attempt to create an S3 bucket to store artifacts that it packages and deploys.
Expand Down Expand Up @@ -103,7 +104,13 @@ To list and delete changesets, use the ls and rm commands.
} else {

fn = args[0]
base := filepath.Base(fn)
// Handle stdin case with "-" filename
var base string
if fn == "-" {
base = "stdin"
} else {
base = filepath.Base(fn)
}

var suppliedStackName string

Expand Down Expand Up @@ -133,8 +140,16 @@ To list and delete changesets, use the ls and rm commands.

// Process metadata Rain Content before (Run build scripts before deployment)
if !changeset {
// Use current directory for stdin input
var dir string
if fn == "-" {
dir = "."
} else {
dir = filepath.Dir(fn)
}

err := processMetadataBefore(cft.Template{Node: templateNode},
stackName, filepath.Dir(fn))
stackName, dir)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -273,8 +288,16 @@ To list and delete changesets, use the ls and rm commands.

// Process Rain Metadata commands (Content)
if !changeset {
// Use current directory for stdin input
var dir string
if fn == "-" {
dir = "."
} else {
dir = filepath.Dir(fn)
}

err := processMetadataAfter(cft.Template{Node: templateNode},
stackName, filepath.Dir(fn))
stackName, dir)
if err != nil {
panic(err)
}
Expand Down
9 changes: 8 additions & 1 deletion internal/cmd/deploy/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,20 @@ func formatChangeSet(stackName, changeSetName string) string {
return strings.TrimSpace(out.String())
}

// PackageTemplate reads and packages a template from a file or stdin
func PackageTemplate(fn string, yes bool) *cft.Template {
// Call RainBucket for side-effects in case we want to force bucket creation
s3.RainBucket(yes)

// Handle stdin case with "-" filename
templateName := fn
if fn == "-" {
templateName = "stdin"
}

t, err := pkg.File(fn)
if err != nil {
panic(ui.Errorf(err, "error packaging template '%s'", fn))
panic(ui.Errorf(err, "error packaging template '%s'", templateName))
}

return t
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var longDiff = false
var Cmd = &cobra.Command{
Use: "diff <from> <to>",
Short: "Compare CloudFormation templates",
Long: "Outputs a summary of the changes necessary to transform the CloudFormation template named <from> into the template named <to>.",
Long: "Outputs a summary of the changes necessary to transform the CloudFormation template named <from> into the template named <to>.\n\nYou can use \"-\" as a filename to read from stdin.",
Args: cobra.ExactArgs(2),
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
Expand Down
40 changes: 23 additions & 17 deletions internal/cmd/fmt/fmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,19 @@ func formatFile(filename string) result {
return res
}

r, err := os.Open(filename)
if err != nil {
return result{
name: filename,
err: ui.Errorf(err, "unable to read '%s'", filename),
var r *os.File
var err error

if filename == "-" {
r = os.Stdin
filename = "stdin"
} else {
r, err = os.Open(filename)
if err != nil {
return result{
name: filename,
err: ui.Errorf(err, "unable to read '%s'", filename),
}
}
}

Expand All @@ -145,24 +153,22 @@ var Cmd = &cobra.Command{
// Check there's data on stdin
stat, err := os.Stdin.Stat()
if err != nil {
panic(ui.Errorf(err, "unable to open stdin"))
cmd.Help()
os.Exit(0)
}

if stat.Mode()&os.ModeNamedPipe == 0 && stat.Size() == 0 {
fmt.Println("CAKES")
panic(cmd.Help())
cmd.Help()
os.Exit(0)
}

writeFlag = false // Can't write back to stdin ;)
// There is data on stdin, assume the user intends to format it
args = []string{"-"}
}

results = []result{
formatReader("<stdin>", os.Stdin),
}
} else {
results = make([]result, len(args))
for i, filename := range args {
results[i] = formatFile(filename)
}
results = make([]result, len(args))
for i, filename := range args {
results[i] = formatFile(filename)
}

hasErr := false
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/forecast/forecast.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,8 @@ template has been checked to make sure it has a valid syntax.

This command checks for some common issues across all resources, and
resource-specific checks. See the README for more details.

You can use "-" as a filename to read the template from stdin.
`,
Args: cobra.RangeArgs(1, 2),
DisableFlagsInUseLine: true,
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/merge/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var outFn = ""
var Cmd = &cobra.Command{
Use: "merge <template> <template> ...",
Short: "Merge two or more CloudFormation templates",
Long: "Merges all specified CloudFormation templates, print the resultant template to standard out",
Long: "Merges all specified CloudFormation templates, print the resultant template to standard out.\n\nYou can use \"-\" as a filename to read from stdin for any of the template arguments.",
Args: cobra.MinimumNArgs(2),
DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var twoWayTree = false
var Cmd = &cobra.Command{
Use: "tree [template]",
Short: "Find dependencies of Resources and Outputs in a local template",
Long: "Find and display the dependencies between Parameters, Resources, and Outputs in a CloudFormation template.",
Long: "Find and display the dependencies between Parameters, Resources, and Outputs in a CloudFormation template.\n\nYou can use \"-\" as a filename to read from stdin.",
Args: cobra.ExactArgs(1),
Aliases: []string{"graph"},
DisableFlagsInUseLine: true,
Expand Down