@@ -3,6 +3,7 @@ package cmd
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "strings"
6
7
7
8
"cdr.dev/coder-cli/coder-sdk"
8
9
"cdr.dev/coder-cli/internal/clog"
@@ -81,3 +82,94 @@ func findEnv(ctx context.Context, client *coder.Client, envName, userEmail strin
81
82
clog .Tipf ("run \" coder envs ls\" to view your environments" ),
82
83
)
83
84
}
85
+
86
+ func findImg (ctx context.Context , client * coder.Client , email , imgName string ) (* coder.Image , error ) {
87
+ userImgs , err := lookupUserImgs (ctx , client , email , imgName )
88
+ if err != nil {
89
+ return nil , err
90
+ }
91
+
92
+ numImgs := len (userImgs )
93
+
94
+ if numImgs == 0 {
95
+ return nil , xerrors .New ("image not found - did you forget to import this image?" )
96
+ }
97
+
98
+ if numImgs > 1 {
99
+ var lines []string
100
+
101
+ for _ , img := range userImgs {
102
+ lines = append (lines , img .Repository )
103
+ }
104
+
105
+ clog .LogInfo (
106
+ fmt .Sprintf ("Found %d possible matches for %q." , numImgs , imgName ),
107
+ clog .Tipf ("Did you mean?\n \t %s" , strings .Join (lines , "\n \t " )),
108
+ )
109
+
110
+ return nil , xerrors .New ("please refine your search" )
111
+ }
112
+ return userImgs [0 ], nil
113
+ }
114
+
115
+ func getImgs (ctx context.Context , client * coder.Client , userEmail string ) ([]* coder.Image , error ) {
116
+ u , err := client .UserByEmail (ctx , userEmail )
117
+ if err != nil {
118
+ return nil , err
119
+ }
120
+
121
+ orgs , err := client .Organizations (ctx )
122
+ if err != nil {
123
+ return nil , err
124
+ }
125
+
126
+ orgs = lookupUserOrgs (u , orgs )
127
+ var importedImgs []* coder.Image
128
+
129
+ // Get all of the imported images for all of the orgs the user belongs to.
130
+ for _ , org := range orgs {
131
+ imgs , err := client .GetOrganizationImages (ctx , org .ID )
132
+ if err != nil {
133
+ return nil , err
134
+ }
135
+ importedImgs = append (importedImgs , imgs ... )
136
+ }
137
+ return importedImgs , nil
138
+ }
139
+
140
+ // returns all images that contain imgName as a substring and have been imported by the user.
141
+ func lookupUserImgs (ctx context.Context , client * coder.Client , email , imgName string ) ([]* coder.Image , error ) {
142
+ switch {
143
+ case client == nil :
144
+ return nil , xerrors .New ("nil client" )
145
+ case email == "" :
146
+ return nil , xerrors .New ("user email unset" )
147
+ case imgName == "" :
148
+ return nil , xerrors .New ("image name unset" )
149
+ }
150
+
151
+ // Get all imported images for each org the user belongs to.
152
+ imgs , err := getImgs (ctx , client , email )
153
+ if err != nil {
154
+ return nil , err
155
+ }
156
+
157
+ var userImgs []* coder.Image
158
+
159
+ // The user may provide an image thats not an exact match
160
+ // to one of their imported images but they may be close.
161
+ // We can assist the user by collecting images that contain
162
+ // the user provided image flag value as a substring.
163
+ for _ , img := range imgs {
164
+ if strings .Contains (img .Repository , imgName ) {
165
+ userImgs = append (userImgs , img )
166
+ }
167
+ // If it's an exact match we can overwrite the slice and exit the loop
168
+ // since we won't need the fuzzy matched images anymore.
169
+ if img .Repository == imgName {
170
+ userImgs = []* coder.Image {img }
171
+ break
172
+ }
173
+ }
174
+ return userImgs , nil
175
+ }
0 commit comments