Skip to content

Commit daec308

Browse files
committed
Refactor config profile command
1 parent e8acfde commit daec308

4 files changed

Lines changed: 76 additions & 20 deletions

File tree

cmd/config.go

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@ import (
44
"fmt"
55

66
"github.com/localstack/lstk/internal/config"
7-
"github.com/localstack/lstk/internal/ui"
87
"github.com/localstack/lstk/internal/env"
9-
"github.com/localstack/lstk/internal/endpoint"
10-
"github.com/localstack/lstk/internal/output"
118
"github.com/localstack/lstk/internal/telemetry"
9+
"github.com/localstack/lstk/internal/ui"
1210
"github.com/spf13/cobra"
1311
)
1412

@@ -33,27 +31,11 @@ func newConfigProfileCmd(cfg *env.Env, tel *telemetry.Client) *cobra.Command {
3331
return fmt.Errorf("failed to get config: %w", err)
3432
}
3533

36-
var awsContainer *config.ContainerConfig
37-
for i := range appConfig.Containers {
38-
if appConfig.Containers[i].Type == config.EmulatorAWS {
39-
awsContainer = &appConfig.Containers[i]
40-
break
41-
}
42-
}
43-
if awsContainer == nil {
44-
return fmt.Errorf("no aws emulator configured")
45-
}
46-
47-
resolvedHost, dnsOK := endpoint.ResolveHost(awsContainer.Port, cfg.LocalStackHost)
48-
if !dnsOK {
49-
output.EmitNote(output.NewPlainSink(cmd.OutOrStdout()), `Could not resolve "localhost.localstack.cloud" - your system may have DNS rebind protection enabled. Using 127.0.0.1 as the endpoint.`)
50-
}
51-
5234
if !isInteractiveMode(cfg) {
5335
return fmt.Errorf("config profile requires an interactive terminal")
5436
}
5537

56-
return ui.RunAWSProfileSetup(cmd.Context(), resolvedHost)
38+
return ui.RunConfigProfile(cmd.Context(), appConfig.Containers, cfg.LocalStackHost)
5739
}),
5840
}
5941
}

internal/awsconfig/awsconfig.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"gopkg.in/ini.v1"
1313

14+
"github.com/localstack/lstk/internal/config"
1415
"github.com/localstack/lstk/internal/endpoint"
1516
"github.com/localstack/lstk/internal/output"
1617
)
@@ -245,6 +246,27 @@ func NotifyIfMissing(ctx context.Context, sink output.Sink, interactive bool, re
245246
return nil
246247
}
247248

249+
// RunProfileSetup runs the AWS profile setup flow: resolves the host, checks DNS,
250+
// verifies interactive mode, and runs the TUI if all checks pass.
251+
// Returns an error if no AWS container is configured or if not running in interactive mode.
252+
func RunProfileSetup(ctx context.Context, sink output.Sink, containers []config.ContainerConfig, localStackHost string, interactive bool) error {
253+
awsContainer := config.GetAWSContainer(containers)
254+
if awsContainer == nil {
255+
return fmt.Errorf("no aws emulator configured")
256+
}
257+
258+
resolvedHost, dnsOK := endpoint.ResolveHost(awsContainer.Port, localStackHost)
259+
if !dnsOK {
260+
output.EmitNote(sink, `Could not resolve "localhost.localstack.cloud" - your system may have DNS rebind protection enabled. Using 127.0.0.1 as the endpoint.`)
261+
}
262+
263+
if !interactive {
264+
return fmt.Errorf("config profile requires an interactive terminal")
265+
}
266+
267+
return Setup(ctx, sink, resolvedHost)
268+
}
269+
248270
// Setup checks for the localstack AWS profile and prompts to create or update it if needed.
249271
// resolvedHost must be a host:port string (e.g. "localhost.localstack.cloud:4566").
250272
func Setup(ctx context.Context, sink output.Sink, resolvedHost string) error {

internal/config/containers.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,14 @@ func (c *ContainerConfig) ProductName() (string, error) {
138138
}
139139
return productName, nil
140140
}
141+
142+
// GetAWSContainer returns the AWS container config from the list of containers.
143+
// Returns nil if no AWS container is configured.
144+
func GetAWSContainer(containers []ContainerConfig) *ContainerConfig {
145+
for i := range containers {
146+
if containers[i].Type == EmulatorAWS {
147+
return &containers[i]
148+
}
149+
}
150+
return nil
151+
}

internal/ui/run_awsconfig.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,50 @@ import (
77

88
tea "github.com/charmbracelet/bubbletea"
99
"github.com/localstack/lstk/internal/awsconfig"
10+
"github.com/localstack/lstk/internal/config"
1011
"github.com/localstack/lstk/internal/output"
1112
)
1213

14+
// RunConfigProfile runs the AWS profile setup flow with TUI output.
15+
// It resolves the host from the AWS container config and runs the setup.
16+
func RunConfigProfile(parentCtx context.Context, containers []config.ContainerConfig, localStackHost string) error {
17+
ctx, cancel := context.WithCancel(parentCtx)
18+
defer cancel()
19+
20+
app := NewApp("", "", "", cancel, withoutHeader())
21+
p := tea.NewProgram(app, tea.WithInput(os.Stdin), tea.WithOutput(os.Stdout))
22+
runErrCh := make(chan error, 1)
23+
24+
go func() {
25+
err := awsconfig.RunProfileSetup(ctx, output.NewTUISink(programSender{p: p}), containers, localStackHost, true)
26+
runErrCh <- err
27+
if err != nil && !errors.Is(err, context.Canceled) {
28+
p.Send(runErrMsg{err: err})
29+
return
30+
}
31+
p.Send(runDoneMsg{})
32+
}()
33+
34+
model, err := p.Run()
35+
if err != nil {
36+
return err
37+
}
38+
39+
if app, ok := model.(App); ok && app.Err() != nil {
40+
return output.NewSilentError(app.Err())
41+
}
42+
43+
runErr := <-runErrCh
44+
if runErr != nil && !errors.Is(runErr, context.Canceled) {
45+
return runErr
46+
}
47+
48+
return nil
49+
}
50+
51+
// RunAWSProfileSetup runs the AWS profile setup flow with TUI output.
52+
// resolvedHost must be a host:port string (e.g. "localhost.localstack.cloud:4566").
53+
// Deprecated: Use RunConfigProfile instead, which accepts container config and resolves the host.
1354
func RunAWSProfileSetup(parentCtx context.Context, resolvedHost string) error {
1455
ctx, cancel := context.WithCancel(parentCtx)
1556
defer cancel()

0 commit comments

Comments
 (0)