Skip to content

Commit 18b614b

Browse files
authored
Batch mode UI improvement (#177)
This PR makes several UI improvements: - A tiny improvement on the output dir non-empty warning message, also ensure it is not shown in the `res` mode, as it is meant to be run non-interactively - Removes the warning about missing mapping file when run in `rg` batch mode, which looks too verbose - In `rg` batch mode and `res` mode, rather than printing the status line by line, use a spinner to show the current status, and optionally show some detail info.
1 parent ff0ad4b commit 18b614b

File tree

5 files changed

+96
-66
lines changed

5 files changed

+96
-66
lines changed

go.mod

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ require (
99
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.0.0
1010
github.com/charmbracelet/bubbles v0.10.4-0.20220412141214-292a1dd7ba97
1111
github.com/charmbracelet/bubbletea v0.20.1-0.20220516164627-a5f28a3a04bb
12-
github.com/charmbracelet/lipgloss v0.4.0
12+
github.com/charmbracelet/lipgloss v0.5.0
1313
github.com/hashicorp/go-version v1.4.0
1414
github.com/hashicorp/hc-install v0.3.3-0.20220510130859-d615262197ec
1515
github.com/hashicorp/hcl/v2 v2.11.1
1616
github.com/hashicorp/terraform-exec v0.16.0
1717
github.com/magodo/armid v0.0.0-20220707115142-d2d9f6fb551b
1818
github.com/magodo/aztft v0.1.0
19+
github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6
1920
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0
2021
github.com/magodo/tfadd v0.10.0
2122
github.com/mitchellh/go-wordwrap v1.0.0

go.sum

+5-1
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,9 @@ github.com/charmbracelet/bubbletea v0.20.1-0.20220516164627-a5f28a3a04bb h1:bRxI
102102
github.com/charmbracelet/bubbletea v0.20.1-0.20220516164627-a5f28a3a04bb/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
103103
github.com/charmbracelet/harmonica v0.1.0 h1:lFKeSd6OAckQ/CEzPVd2mqj+YMEubQ/3FM2IYY3xNm0=
104104
github.com/charmbracelet/harmonica v0.1.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
105-
github.com/charmbracelet/lipgloss v0.4.0 h1:768h64EFkGUr8V5yAKV7/Ta0NiVceiPaV+PphaW1K9g=
106105
github.com/charmbracelet/lipgloss v0.4.0/go.mod h1:vmdkHvce7UzX6xkyf4cca8WlwdQ5RQr8fzta+xl7BOM=
106+
github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8=
107+
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
107108
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
108109
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
109110
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -249,6 +250,8 @@ github.com/magodo/armid v0.0.0-20220707115142-d2d9f6fb551b h1:MizLjMfDMkcTcgb9ho
249250
github.com/magodo/armid v0.0.0-20220707115142-d2d9f6fb551b/go.mod h1:rR8E7zfGMbmfnSQvrkFiWYdhrfTqsVSltelnZB09BwA=
250251
github.com/magodo/aztft v0.1.0 h1:QyNrMBt7ARNG1EZ+6hvHCEkjG9F/K2C8ERFg7h1Uqhc=
251252
github.com/magodo/aztft v0.1.0/go.mod h1:CQemtiO/6opZSdNTU0URJm/ShvIqT7MTsR2OQhyXwY8=
253+
github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6 h1:CElHO4hPXC+Eivy8sUC/WrnH3jmQzdF2x0lEXBEYul8=
254+
github.com/magodo/spinner v0.0.0-20220720073946-50f31b2dc5a6/go.mod h1:Cn4fFwFH/Ddw9sjWPeSS72bNaxbM+FRXf7pkGEDReq8=
252255
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0 h1:aNtr4iNv/tex2t8W1u3scAoNHEnFlTKhNNHOpYStqbs=
253256
github.com/magodo/textinput v0.0.0-20210913072708-7d24f2b4b0c0/go.mod h1:MqYhNP+PC386Bjsx5piZe7T4vDm5QIPv8b1RU0prVnU=
254257
github.com/magodo/tfadd v0.10.0 h1:HxYLXWksFXldHdaLcQst9Nvr6xJqatgeyGdeSCgM8bA=
@@ -290,6 +293,7 @@ github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIW
290293
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
291294
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
292295
github.com/muesli/termenv v0.9.0/go.mod h1:R/LzAKf+suGs4IsO95y7+7DpFHO0KABgnZqtlyx2mBw=
296+
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
293297
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 h1:QANkGiGr39l1EESqrE0gZw0/AJNYzIvoGLhIoVYtluI=
294298
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
295299
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=

internal/meta/meta.go

+7-5
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,14 @@ func NewMeta(cfg config.CommonConfig) (*Meta, error) {
8484
}
8585

8686
// Interactive mode
87-
fmt.Printf(`The output directory is not empty. Please choose one of actions below:
87+
fmt.Printf(`
88+
The output directory is not empty. Please choose one of actions below:
8889
89-
[O] To overwrite everything inside the output directory, press "O"
90-
[A] To append (state and config) into the output directory, press "A"
91-
[Other] Press other keys to quit
92-
`)
90+
* To overwrite everything inside the output directory, press "O"
91+
* To append (state and config) into the output directory, press "A"
92+
* Press other keys to quit
93+
94+
> `)
9395
var ans string
9496
fmt.Scanf("%s", &ans)
9597
switch strings.ToLower(ans) {

internal/run.go

+78-54
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,61 @@ package internal
22

33
import (
44
"fmt"
5+
"os"
6+
"strings"
57

68
"github.com/Azure/aztfy/internal/config"
79
"github.com/Azure/aztfy/internal/meta"
810
"github.com/Azure/aztfy/internal/tfaddr"
11+
"github.com/Azure/aztfy/internal/ui/common"
12+
bspinner "github.com/charmbracelet/bubbles/spinner"
13+
"github.com/magodo/spinner"
914
)
1015

1116
func ResourceImport(cfg config.ResConfig) error {
12-
fmt.Printf("Target Azure Resource: %s\n", cfg.ResourceId)
1317
c, err := meta.NewResMeta(cfg)
1418
if err != nil {
1519
return err
1620
}
17-
fmt.Println("Initializing...")
18-
if err := c.Init(); err != nil {
19-
return err
20-
}
2121

22-
fmt.Println("Querying Terraform resource type and id...")
23-
rt, tfid, err := c.QueryResourceTypeAndId()
24-
if err != nil {
25-
return err
26-
}
22+
s := bspinner.NewModel()
23+
s.Spinner = common.Spinner
2724

28-
item := meta.ImportItem{
29-
ResourceID: tfid,
30-
TFAddr: tfaddr.TFAddr{
31-
Type: rt,
32-
Name: c.ResourceName,
33-
},
34-
}
25+
return spinner.Run(s, func(msg spinner.Messager) error {
26+
msg.SetStatus("Initializing...")
27+
if err := c.Init(); err != nil {
28+
return err
29+
}
3530

36-
fmt.Printf("\nResource type: %s\nResource Id: %s\n\n", item.TFAddr.Type, item.ResourceID)
37-
fmt.Println("Importing...")
38-
c.Import(&item)
39-
if err := item.ImportError; err != nil {
40-
return fmt.Errorf("failed to import %s as %s: %v", item.ResourceID, item.TFAddr, err)
41-
}
31+
msg.SetStatus("Querying Terraform resource type and id...")
32+
rt, tfid, err := c.QueryResourceTypeAndId()
33+
if err != nil {
34+
return err
35+
}
4236

43-
fmt.Println("Generating Terraform configurations...")
44-
if err := c.GenerateCfg(meta.ImportList{item}); err != nil {
45-
return fmt.Errorf("generating Terraform configuration: %v", err)
46-
}
37+
item := meta.ImportItem{
38+
ResourceID: tfid,
39+
TFAddr: tfaddr.TFAddr{
40+
Type: rt,
41+
Name: c.ResourceName,
42+
},
43+
}
44+
msg.SetDetail(fmt.Sprintf(`Resource Type: %s
45+
Resource Id : %s`, item.TFAddr.Type, item.ResourceID))
46+
47+
msg.SetStatus("Importing...")
48+
c.Import(&item)
49+
if err := item.ImportError; err != nil {
50+
return fmt.Errorf("failed to import %s as %s: %v", item.ResourceID, item.TFAddr, err)
51+
}
4752

48-
return nil
53+
msg.SetStatus("Generating Terraform configurations...")
54+
if err := c.GenerateCfg(meta.ImportList{item}); err != nil {
55+
return fmt.Errorf("generating Terraform configuration: %v", err)
56+
}
57+
58+
return nil
59+
})
4960
}
5061

5162
func BatchImport(cfg config.RgConfig, continueOnError bool) error {
@@ -54,38 +65,51 @@ func BatchImport(cfg config.RgConfig, continueOnError bool) error {
5465
return err
5566
}
5667

57-
fmt.Println("Initializing...")
58-
if err := c.Init(); err != nil {
59-
return err
60-
}
68+
s := bspinner.NewModel()
69+
s.Spinner = common.Spinner
6170

62-
fmt.Println("List resources...")
63-
list, err := c.ListResource()
64-
if err != nil {
65-
return err
66-
}
71+
var warnings []string
72+
err = spinner.Run(s, func(msg spinner.Messager) error {
73+
msg.SetStatus("Initializing...")
74+
if err := c.Init(); err != nil {
75+
return err
76+
}
6777

68-
fmt.Println("Import resources...")
69-
for i := range list {
70-
if list[i].Skip() {
71-
fmt.Printf("[WARN] No mapping information for resource: %s, skip it\n", list[i].ResourceID)
72-
continue
78+
msg.SetStatus("Listing resources...")
79+
list, err := c.ListResource()
80+
if err != nil {
81+
return err
7382
}
74-
fmt.Printf("Importing %s as %s\n", list[i].ResourceID, list[i].TFAddr)
75-
c.Import(&list[i])
76-
if err := list[i].ImportError; err != nil {
77-
msg := fmt.Sprintf("Failed to import %s as %s: %v", list[i].ResourceID, list[i].TFAddr, err)
78-
if !continueOnError {
79-
return fmt.Errorf(msg)
83+
84+
msg.SetStatus("Importing resources...")
85+
for i := range list {
86+
if list[i].Skip() {
87+
warnings = append(warnings, fmt.Sprintf("No mapping information for resource: %s, skip it", list[i].ResourceID))
88+
msg.SetDetail(strings.Join(warnings, "\n"))
89+
continue
90+
}
91+
msg.SetStatus(fmt.Sprintf("Importing %s as %s", list[i].ResourceID, list[i].TFAddr))
92+
c.Import(&list[i])
93+
if err := list[i].ImportError; err != nil {
94+
msg := fmt.Sprintf("Failed to import %s as %s: %v", list[i].ResourceID, list[i].TFAddr, err)
95+
if !continueOnError {
96+
return fmt.Errorf(msg)
97+
}
98+
warnings = append(warnings, msg)
8099
}
81-
fmt.Println("[ERROR] " + msg)
82100
}
83-
}
84101

85-
fmt.Println("Generating Terraform configurations...")
86-
if err := c.GenerateCfg(list); err != nil {
87-
return fmt.Errorf("generating Terraform configuration: %v", err)
102+
msg.SetStatus("Generating Terraform configurations...")
103+
if err := c.GenerateCfg(list); err != nil {
104+
return fmt.Errorf("generating Terraform configuration: %v", err)
105+
}
106+
return nil
107+
})
108+
109+
// Print out the warnings, if any
110+
if len(warnings) != 0 {
111+
fmt.Fprintln(os.Stderr, "Warnings:\n"+strings.Join(warnings, "\n"))
88112
}
89113

90-
return nil
114+
return err
91115
}

main.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"encoding/json"
66
"fmt"
7-
"github.com/magodo/armid"
87
"io"
98
"log"
109
"os"
@@ -13,6 +12,8 @@ import (
1312
"strconv"
1413
"strings"
1514

15+
"github.com/magodo/armid"
16+
1617
"github.com/Azure/aztfy/internal"
1718
"github.com/Azure/aztfy/internal/config"
1819
"github.com/Azure/aztfy/internal/ui"
@@ -176,9 +177,6 @@ func main() {
176177
if c.NArg() > 1 {
177178
return fmt.Errorf("More than one resource groups specified")
178179
}
179-
if flagBatchMode && flagMappingFile == "" {
180-
fmt.Println("[WARN]: No resource mapping file specified! Only the recognized resources will be imported.")
181-
}
182180
if flagContinue && !flagBatchMode {
183181
return fmt.Errorf("`--continue` must be used together with `--batch`")
184182
}
@@ -307,6 +305,7 @@ func main() {
307305
OutputDir: flagOutputDir,
308306
Overwrite: flagOverwrite,
309307
Append: flagAppend,
308+
BatchMode: true,
310309
BackendType: flagBackendType,
311310
BackendConfig: flagBackendConfig.Value(),
312311
},
@@ -323,7 +322,7 @@ func main() {
323322
sort.Sort(cli.FlagsByName(app.Flags))
324323

325324
if err := app.Run(os.Args); err != nil {
326-
fmt.Fprintf(os.Stderr, "Error: %v", err)
325+
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
327326
os.Exit(1)
328327
}
329328
}

0 commit comments

Comments
 (0)