internal/pkg/term/selector/cfn.go (55 lines of code) (raw):
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package selector
import (
"fmt"
"sort"
"strings"
"github.com/aws/copilot-cli/internal/pkg/template"
"github.com/aws/copilot-cli/internal/pkg/term/prompt"
"gopkg.in/yaml.v3"
)
// CFNSelector represents a selector for a CloudFormation template.
type CFNSelector struct {
prompt Prompter
}
// NewCFNSelector initializes a CFNSelector.
func NewCFNSelector(prompt Prompter) *CFNSelector {
return &CFNSelector{
prompt: prompt,
}
}
// Resources prompts the user to multiselect resources from a CloudFormation template body.
// By default, the prompt filters out any custom resource in the template.
func (sel *CFNSelector) Resources(msg, finalMsg, help, body string) ([]template.CFNResource, error) {
tpl := struct {
Resources map[string]struct {
Type string `yaml:"Type"`
} `yaml:"Resources"`
}{}
if err := yaml.Unmarshal([]byte(body), &tpl); err != nil {
return nil, fmt.Errorf("unmarshal CloudFormation template: %v", err)
}
// Prompt for a selection.
var options []prompt.Option
for name, resource := range tpl.Resources {
if resource.Type == "AWS::Lambda::Function" || strings.HasPrefix(resource.Type, "Custom::") {
continue
}
options = append(options, prompt.Option{
Value: name,
Hint: resource.Type,
})
}
sort.Slice(options, func(i, j int) bool { // Sort options by resource type, if they're the same resource type then sort by logicalID.
if options[i].Hint == options[j].Hint {
return options[i].Value < options[j].Value
}
return options[i].Hint < options[j].Hint
})
logicalIDs, err := sel.prompt.MultiSelectOptions(msg, help, options, prompt.WithFinalMessage(finalMsg))
if err != nil {
return nil, fmt.Errorf("select CloudFormation resources: %v", err)
}
// Transform to template.CFNResource
out := make([]template.CFNResource, len(logicalIDs))
for i, logicalID := range logicalIDs {
out[i] = template.CFNResource{
Type: template.CFNType(tpl.Resources[logicalID].Type),
LogicalID: logicalID,
}
}
return out, nil
}