Skip to content

Commit cb110f7

Browse files
Add support for auto-complete in 'mc admin config' commands (#2975)
1 parent 21a79b4 commit cb110f7

File tree

1 file changed

+117
-42
lines changed

1 file changed

+117
-42
lines changed

cmd/complete.go renamed to cmd/auto-complete.go

Lines changed: 117 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,28 @@ func (fs fsComplete) Predict(a complete.Args) (prediction []string) {
3333
return complete.PredictFiles("*").Predict(a)
3434
}
3535

36+
func completeAdminConfigKeys(aliasPath string, keyPrefix string) (prediction []string) {
37+
// Convert alias/bucket/incompl to alias/bucket/ to list its contents
38+
parentDirPath := filepath.Dir(aliasPath) + "/"
39+
clnt, err := newAdminClient(parentDirPath)
40+
if err != nil {
41+
return nil
42+
}
43+
44+
h, e := clnt.HelpConfigKV("", "", false)
45+
if e != nil {
46+
return nil
47+
}
48+
49+
for _, hkv := range h.KeysHelp {
50+
if strings.HasPrefix(hkv.Key, keyPrefix) {
51+
prediction = append(prediction, hkv.Key)
52+
}
53+
}
54+
55+
return prediction
56+
}
57+
3658
// Complete S3 path. If the prediction result is only one directory,
3759
// then recursively scans it. This is needed to satisfy posener/complete
3860
// (look at posener/complete.PredictFiles)
@@ -51,14 +73,14 @@ func completeS3Path(s3Path string) (prediction []string) {
5173
// List dirPath content and only pick elements that corresponds
5274
// to the path that we want to complete
5375
for content := range clnt.List(false, false, false, DirFirst) {
54-
completeS3Path := alias + getKey(content)
76+
cmplS3Path := alias + getKey(content)
5577
if content.Type.IsDir() {
56-
if !strings.HasSuffix(completeS3Path, "/") {
57-
completeS3Path += "/"
78+
if !strings.HasSuffix(cmplS3Path, "/") {
79+
cmplS3Path += "/"
5880
}
5981
}
60-
if strings.HasPrefix(completeS3Path, s3Path) {
61-
prediction = append(prediction, completeS3Path)
82+
if strings.HasPrefix(cmplS3Path, s3Path) {
83+
prediction = append(prediction, cmplS3Path)
6284
}
6385
}
6486

@@ -70,6 +92,43 @@ func completeS3Path(s3Path string) (prediction []string) {
7092
return
7193
}
7294

95+
type adminConfigComplete struct{}
96+
97+
func (adm adminConfigComplete) Predict(a complete.Args) (prediction []string) {
98+
defer func() {
99+
sort.Strings(prediction)
100+
}()
101+
102+
loadMcConfig = loadMcConfigFactory()
103+
conf, err := loadMcConfig()
104+
if err != nil {
105+
return
106+
}
107+
108+
// We have already predicted the keys, we are done.
109+
if len(a.Completed) == 3 {
110+
return
111+
}
112+
113+
arg := a.Last
114+
lastArg := a.LastCompleted
115+
if _, ok := conf.Hosts[filepath.Clean(a.LastCompleted)]; !ok {
116+
if strings.IndexByte(arg, '/') == -1 {
117+
// Only predict alias since '/' is not found
118+
for alias := range conf.Hosts {
119+
if strings.HasPrefix(alias, arg) {
120+
prediction = append(prediction, alias+"/")
121+
}
122+
}
123+
} else {
124+
prediction = completeAdminConfigKeys(arg, "")
125+
}
126+
} else {
127+
prediction = completeAdminConfigKeys(lastArg, arg)
128+
}
129+
return
130+
}
131+
73132
// s3Complete knows how to complete an mc s3 path
74133
type s3Complete struct {
75134
deepLevel int
@@ -136,44 +195,68 @@ func (al aliasComplete) Predict(a complete.Args) (prediction []string) {
136195
return
137196
}
138197

198+
var adminConfigCompleter = adminConfigComplete{}
139199
var s3Completer = s3Complete{}
140200
var aliasCompleter = aliasComplete{}
141201
var fsCompleter = fsComplete{}
142202

143203
// The list of all commands supported by mc with their mapping
144204
// with their bash completer function
145205
var completeCmds = map[string]complete.Predictor{
146-
"/ls": complete.PredictOr(s3Completer, fsCompleter),
147-
"/cp": complete.PredictOr(s3Completer, fsCompleter),
148-
"/rm": complete.PredictOr(s3Completer, fsCompleter),
149-
"/rb": complete.PredictOr(s3Complete{deepLevel: 2}, fsCompleter),
150-
"/cat": complete.PredictOr(s3Completer, fsCompleter),
151-
"/head": complete.PredictOr(s3Completer, fsCompleter),
152-
"/diff": complete.PredictOr(s3Completer, fsCompleter),
153-
"/find": complete.PredictOr(s3Completer, fsCompleter),
154-
"/mirror": complete.PredictOr(s3Completer, fsCompleter),
155-
"/pipe": complete.PredictOr(s3Completer, fsCompleter),
156-
"/stat": complete.PredictOr(s3Completer, fsCompleter),
157-
"/watch": complete.PredictOr(s3Completer, fsCompleter),
158-
"/policy": complete.PredictOr(s3Completer, fsCompleter),
159-
"/tree": complete.PredictOr(s3Complete{deepLevel: 2}, fsCompleter),
160-
"/du": complete.PredictOr(s3Complete{deepLevel: 2}, fsCompleter),
161-
162-
"/mb": aliasCompleter,
163-
"/sql": s3Completer,
164-
165-
"/admin/info": aliasCompleter,
166-
"/admin/heal": s3Completer,
167-
"/admin/credential": aliasCompleter,
168-
169-
"/admin/config/get": aliasCompleter,
170-
"/admin/config/set": aliasCompleter,
171-
172-
"/admin/service/status": aliasCompleter,
173-
"/admin/service/restart": aliasCompleter,
206+
// S3 API level commands
207+
"/ls": complete.PredictOr(s3Completer, fsCompleter),
208+
"/cp": complete.PredictOr(s3Completer, fsCompleter),
209+
"/rm": complete.PredictOr(s3Completer, fsCompleter),
210+
"/rb": complete.PredictOr(s3Complete{deepLevel: 2}, fsCompleter),
211+
"/cat": complete.PredictOr(s3Completer, fsCompleter),
212+
"/head": complete.PredictOr(s3Completer, fsCompleter),
213+
"/diff": complete.PredictOr(s3Completer, fsCompleter),
214+
"/find": complete.PredictOr(s3Completer, fsCompleter),
215+
"/mirror": complete.PredictOr(s3Completer, fsCompleter),
216+
"/pipe": complete.PredictOr(s3Completer, fsCompleter),
217+
"/stat": complete.PredictOr(s3Completer, fsCompleter),
218+
"/watch": complete.PredictOr(s3Completer, fsCompleter),
219+
"/policy": complete.PredictOr(s3Completer, fsCompleter),
220+
"/tree": complete.PredictOr(s3Complete{deepLevel: 2}, fsCompleter),
221+
"/du": complete.PredictOr(s3Complete{deepLevel: 2}, fsCompleter),
222+
"/retention": s3Completer,
223+
"/sql": s3Completer,
224+
"/lock": complete.PredictOr(s3Complete{deepLevel: 2}),
225+
"/mb": aliasCompleter,
226+
227+
"/event/add": aliasCompleter,
228+
"/event/list": aliasCompleter,
229+
"/event/remove": aliasCompleter,
230+
231+
"/share/download": s3Completer,
232+
"/share/list": nil,
233+
"/share/upload": s3Completer,
234+
235+
// Admin API commands MinIO only.
236+
"/admin/heal": s3Completer,
237+
238+
"/admin/info/server": aliasCompleter,
239+
"/admin/info/cpu": aliasCompleter,
240+
"/admin/info/mem": aliasCompleter,
241+
242+
"/admin/config/get": adminConfigCompleter,
243+
"/admin/config/set": adminConfigCompleter,
244+
"/admin/config/del": adminConfigCompleter,
245+
"/admin/config/import": aliasCompleter,
246+
"/admin/config/export": aliasCompleter,
247+
"/admin/config/history/restore": aliasCompleter,
248+
"/admin/config/history/list": aliasCompleter,
249+
"/admin/config/history/clear": aliasCompleter,
250+
251+
"/admin/trace": aliasCompleter,
252+
"/admin/console": aliasCompleter,
253+
"/admin/update": aliasCompleter,
254+
"/admin/top/locks": aliasCompleter,
255+
174256
"/admin/service/stop": aliasCompleter,
257+
"/admin/service/restart": aliasCompleter,
175258

176-
"/admin/trace": aliasCompleter,
259+
"/admin/prometheus/generate": aliasCompleter,
177260

178261
"/admin/profile/start": aliasCompleter,
179262
"/admin/profile/stop": aliasCompleter,
@@ -198,18 +281,10 @@ var completeCmds = map[string]complete.Predictor{
198281
"/admin/group/remove": aliasCompleter,
199282
"/admin/group/info": aliasCompleter,
200283

201-
"/event/add": aliasCompleter,
202-
"/event/list": aliasCompleter,
203-
"/event/remove": aliasCompleter,
204-
205284
"/session/clear": nil,
206285
"/session/list": nil,
207286
"/session/resume": nil,
208287

209-
"/share/download": nil,
210-
"/share/list": nil,
211-
"/share/upload": nil,
212-
213288
"/config/host/add": nil,
214289
"/config/host/list": aliasCompleter,
215290
"/config/host/remove": aliasCompleter,

0 commit comments

Comments
 (0)