1
1
package main
2
2
3
3
import (
4
- "encoding/json"
5
4
"errors"
6
5
"fmt"
7
- "os/user"
8
6
"reflect"
9
7
"sort"
10
8
"strings"
11
- "text/tabwriter"
12
- "text/template"
13
9
14
- "github.com/docker/go-units"
15
10
"github.com/lima-vm/lima/pkg/store"
16
11
"github.com/sirupsen/logrus"
17
12
"github.com/spf13/cobra"
@@ -36,15 +31,26 @@ func fieldNames() []string {
36
31
37
32
func newListCommand () * cobra.Command {
38
33
listCommand := & cobra.Command {
39
- Use : "list [flags] [INSTANCE]..." ,
40
- Aliases : []string {"ls" },
41
- Short : "List instances of Lima." ,
34
+ Use : "list [flags] [INSTANCE]..." ,
35
+ Aliases : []string {"ls" },
36
+ Short : "List instances of Lima." ,
37
+ Long : `List instances of Lima.
38
+ The output can be presented in one of several formats, using the --format <format> flag.
39
+
40
+ --format json - output in json format
41
+ --format yaml - output in yaml format
42
+ --format table - output in table format
43
+ --format '{{ <go template> }}' - if the format begins and ends with '{{ }}', then it is used as a go template.
44
+
45
+ The following legacy flags continue to function:
46
+ --json - equal to '--format json'
47
+ ` ,
42
48
Args : cobra .ArbitraryArgs ,
43
49
RunE : listAction ,
44
50
ValidArgsFunction : listBashComplete ,
45
51
}
46
52
47
- listCommand .Flags ().StringP ("format" , "f" , "" , "Format the output using the given Go template" )
53
+ listCommand .Flags ().StringP ("format" , "f" , "table " , "output format, one of: json, yaml, table, go- template" )
48
54
listCommand .Flags ().Bool ("list-fields" , false , "List fields available for format" )
49
55
listCommand .Flags ().Bool ("json" , false , "JSONify output" )
50
56
listCommand .Flags ().BoolP ("quiet" , "q" , false , "Only show names" )
@@ -67,7 +73,7 @@ func listAction(cmd *cobra.Command, args []string) error {
67
73
if err != nil {
68
74
return err
69
75
}
70
- goFormat , err := cmd .Flags ().GetString ("format" )
76
+ format , err := cmd .Flags ().GetString ("format" )
71
77
if err != nil {
72
78
return err
73
79
}
@@ -80,131 +86,76 @@ func listAction(cmd *cobra.Command, args []string) error {
80
86
return err
81
87
}
82
88
83
- if goFormat != "" && listFields {
84
- return errors .New ("option --format conflicts with --list-fields" )
89
+ if jsonFormat {
90
+ format = "json"
91
+ }
92
+
93
+ // conflicts
94
+ if jsonFormat && cmd .Flags ().Changed ("format" ) {
95
+ return errors .New ("option --json conflicts with option --format" )
85
96
}
86
- if jsonFormat && listFields {
87
- return errors .New ("option --json conflicts with --list-fields" )
97
+ if listFields && cmd .Flags ().Changed ("format" ) {
98
+ return errors .New ("option --list-fields conflicts with option --format" )
99
+ }
100
+
101
+ if quiet && format != "table" {
102
+ return errors .New ("option --quiet can only be used with '--format table'" )
88
103
}
104
+
89
105
if listFields {
90
106
names := fieldNames ()
91
107
sort .Strings (names )
92
108
fmt .Println (strings .Join (names , "\n " ))
93
109
return nil
94
110
}
95
- if quiet && jsonFormat {
96
- return errors .New ("option --quiet conflicts with --json" )
97
- }
98
- if goFormat != "" && jsonFormat {
99
- return errors .New ("option --format conflicts with --json" )
100
- }
101
111
102
112
allinstances , err := store .Instances ()
103
113
if err != nil {
104
114
return err
105
115
}
116
+ if len (allinstances ) == 0 {
117
+ logrus .Warn ("No instance found. Run `limactl start` to create an instance." )
118
+ return nil
119
+ }
106
120
107
- instances := []string {}
121
+ instanceNames := []string {}
108
122
if len (args ) > 0 {
109
123
for _ , arg := range args {
110
124
matches := instanceMatches (arg , allinstances )
111
125
if len (matches ) > 0 {
112
- instances = append (instances , matches ... )
126
+ instanceNames = append (instanceNames , matches ... )
113
127
} else {
114
128
logrus .Warnf ("No instance matching %v found." , arg )
115
129
}
116
130
}
117
131
} else {
118
- instances = allinstances
132
+ instanceNames = allinstances
119
133
}
120
134
121
135
if quiet {
122
- for _ , instName := range instances {
136
+ for _ , instName := range instanceNames {
123
137
fmt .Fprintln (cmd .OutOrStdout (), instName )
124
138
}
125
139
return nil
126
140
}
127
141
128
- if goFormat != "" {
129
- tmpl , err := template .New ("format" ).Parse (goFormat )
142
+ // get the state and config for all the requested instances
143
+ var instances []* store.Instance
144
+ for _ , instanceName := range instanceNames {
145
+ instance , err := store .Inspect (instanceName )
130
146
if err != nil {
131
- return err
132
- }
133
- for _ , instName := range instances {
134
- inst , err := store .Inspect (instName )
135
- if err != nil {
136
- logrus .WithError (err ).Errorf ("instance %q does not exist?" , instName )
137
- continue
138
- }
139
- data , err := store .AddGlobalFields (inst )
140
- if err != nil {
141
- logrus .WithError (err ).Error ("Cannot add global fields to instance data" )
142
- continue
143
- }
144
- err = tmpl .Execute (cmd .OutOrStdout (), data )
145
- if err != nil {
146
- return err
147
- }
148
- fmt .Fprintln (cmd .OutOrStdout ())
149
- }
150
- return nil
151
- }
152
- if jsonFormat {
153
- for _ , instName := range instances {
154
- inst , err := store .Inspect (instName )
155
- if err != nil {
156
- logrus .WithError (err ).Errorf ("instance %q does not exist?" , instName )
157
- continue
158
- }
159
- b , err := json .Marshal (inst )
160
- if err != nil {
161
- return err
162
- }
163
- fmt .Fprintln (cmd .OutOrStdout (), string (b ))
147
+ return fmt .Errorf ("unable to load instance %s: %w" , instanceName , err )
164
148
}
165
- return nil
166
- }
167
-
168
- w := tabwriter .NewWriter (cmd .OutOrStdout (), 4 , 8 , 4 , ' ' , 0 )
169
- fmt .Fprintln (w , "NAME\t STATUS\t SSH\t VMTYPE\t ARCH\t CPUS\t MEMORY\t DISK\t DIR" )
170
-
171
- if len (allinstances ) == 0 {
172
- logrus .Warn ("No instance found. Run `limactl start` to create an instance." )
149
+ instances = append (instances , instance )
173
150
}
174
151
175
- u , err := user .Current ()
176
- if err != nil {
177
- return err
152
+ for _ , instance := range instances {
153
+ if len (instance .Errors ) > 0 {
154
+ logrus .WithField ("errors" , instance .Errors ).Warnf ("instance %q has errors" , instance .Name )
155
+ }
178
156
}
179
- homeDir := u .HomeDir
180
157
181
- for _ , instName := range instances {
182
- inst , err := store .Inspect (instName )
183
- if err != nil {
184
- logrus .WithError (err ).Errorf ("instance %q does not exist?" , instName )
185
- continue
186
- }
187
- if len (inst .Errors ) > 0 {
188
- logrus .WithField ("errors" , inst .Errors ).Warnf ("instance %q has errors" , instName )
189
- }
190
- dir := inst .Dir
191
- if strings .HasPrefix (dir , homeDir ) {
192
- dir = strings .Replace (dir , homeDir , "~" , 1 )
193
- }
194
- fmt .Fprintf (w , "%s\t %s\t %s\t %s\t %s\t %d\t %s\t %s\t %s\n " ,
195
- inst .Name ,
196
- inst .Status ,
197
- fmt .Sprintf ("127.0.0.1:%d" , inst .SSHLocalPort ),
198
- inst .VMType ,
199
- inst .Arch ,
200
- inst .CPUs ,
201
- units .BytesSize (float64 (inst .Memory )),
202
- units .BytesSize (float64 (inst .Disk )),
203
- dir ,
204
- )
205
- }
206
-
207
- return w .Flush ()
158
+ return store .PrintInstances (cmd .OutOrStdout (), instances , format )
208
159
}
209
160
210
161
func listBashComplete (cmd * cobra.Command , args []string , toComplete string ) ([]string , cobra.ShellCompDirective ) {
0 commit comments