-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfilter.go
More file actions
157 lines (144 loc) · 3.74 KB
/
Copy pathfilter.go
File metadata and controls
157 lines (144 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package lamvms
import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"log/slog"
"os"
"os/exec"
"strings"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/lambdamicrovms"
"github.com/aws/aws-sdk-go-v2/service/lambdamicrovms/types"
)
func (app *App) selectMicrovmID(ctx context.Context, stateFilter ...types.MicrovmState) (string, error) {
existing, err := app.findMicrovmImageByName(ctx, aws.ToString(app.microvmImage.Name))
if err != nil {
return "", err
}
if existing == nil {
return "", fmt.Errorf("microvm image %q not found", aws.ToString(app.microvmImage.Name))
}
items, err := app.listMicrovms(ctx, aws.ToString(existing.ImageArn), stateFilter)
if err != nil {
return "", err
}
if len(items) == 0 {
return "", fmt.Errorf("no microvms found")
}
if len(items) == 1 {
return aws.ToString(items[0].MicrovmId), nil
}
var buf bytes.Buffer
for _, item := range items {
fmt.Fprintf(&buf, "%s\t%s\t%s\n",
aws.ToString(item.MicrovmId),
item.State,
createdAtOrZero(item.StartedAt).Format("2006-01-02T15:04:05"),
)
}
selected, err := app.runFilter(ctx, &buf, "MicroVM ID")
if err != nil {
return "", err
}
fields := strings.Fields(selected)
if len(fields) == 0 {
return "", fmt.Errorf("no MicroVM ID selected")
}
return fields[0], nil
}
func (app *App) listMicrovms(ctx context.Context, imageARN string, stateFilter []types.MicrovmState) ([]types.MicrovmItem, error) {
var items []types.MicrovmItem
var nextToken *string
for {
out, err := app.client.ListMicrovms(ctx, &lambdamicrovms.ListMicrovmsInput{
ImageIdentifier: aws.String(imageARN),
NextToken: nextToken,
})
if err != nil {
return nil, fmt.Errorf("list microvms: %w", err)
}
for _, item := range out.Items {
if len(stateFilter) == 0 || containsState(stateFilter, item.State) {
items = append(items, item)
}
}
if out.NextToken == nil {
break
}
nextToken = out.NextToken
}
return items, nil
}
func containsState(states []types.MicrovmState, s types.MicrovmState) bool {
for _, st := range states {
if st == s {
return true
}
}
return false
}
func (app *App) runFilter(ctx context.Context, src io.Reader, title string) (string, error) {
if app.filterCommand != "" {
return runExternalFilter(ctx, app.filterCommand, src)
}
return runInternalFilter(src, title)
}
func runExternalFilter(ctx context.Context, command string, src io.Reader) (string, error) {
var cmd *exec.Cmd
if strings.Contains(command, " ") {
cmd = exec.CommandContext(ctx, "sh", "-c", command)
} else {
cmd = exec.CommandContext(ctx, command)
}
cmd.Stderr = os.Stderr
p, err := cmd.StdinPipe()
if err != nil {
return "", fmt.Errorf("failed to create stdin pipe: %w", err)
}
go func() {
if _, err := io.Copy(p, src); err != nil {
return
}
if err := p.Close(); err != nil {
slog.Debug("failed to close stdin pipe", "error", err)
}
}()
b, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("failed to execute filter command: %w", err)
}
return strings.TrimRight(string(b), "\r\n"), nil
}
func runInternalFilter(src io.Reader, title string) (string, error) {
var items []string
s := bufio.NewScanner(src)
for s.Scan() {
line := s.Text()
fmt.Fprintln(os.Stderr, line)
items = append(items, line)
}
if err := s.Err(); err != nil {
return "", err
}
if len(items) == 0 {
return "", fmt.Errorf("no items to select")
}
fmt.Fprintf(os.Stderr, "Enter %s: ", title)
scanner := bufio.NewScanner(os.Stdin)
if !scanner.Scan() {
return "", fmt.Errorf("no input")
}
input := strings.TrimSpace(scanner.Text())
if input == "" {
return "", fmt.Errorf("no input")
}
for _, item := range items {
if strings.HasPrefix(item, input) {
return item, nil
}
}
return "", fmt.Errorf("no match for %q", input)
}