Skip to content

Commit 0192192

Browse files
authored
Merge pull request #1445 from montag451/file-push-pull-comp
incus: Improve completion for `file push` and `file pull`
2 parents 1e6cf48 + d09af53 commit 0192192

15 files changed

+154
-35
lines changed

cmd/incus/cluster.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func (c *cmdClusterList) Command() *cobra.Command {
155155

156156
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
157157
if len(args) == 0 {
158-
return c.global.cmpRemotes(false)
158+
return c.global.cmpRemotes(toComplete, false)
159159
}
160160

161161
return nil, cobra.ShellCompDirectiveNoFileComp
@@ -791,7 +791,7 @@ func (c *cmdClusterEnable) Command() *cobra.Command {
791791

792792
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
793793
if len(args) == 0 {
794-
return c.global.cmpRemotes(false)
794+
return c.global.cmpRemotes(toComplete, false)
795795
}
796796

797797
return nil, cobra.ShellCompDirectiveNoFileComp
@@ -1095,7 +1095,7 @@ Pre-defined column shorthand chars:
10951095

10961096
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
10971097
if len(args) == 0 {
1098-
return c.global.cmpRemotes(false)
1098+
return c.global.cmpRemotes(toComplete, false)
10991099
}
11001100

11011101
return nil, cobra.ShellCompDirectiveNoFileComp

cmd/incus/cluster_group.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ incus cluster group create g1 < config.yaml
195195

196196
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
197197
if len(args) == 0 {
198-
return c.global.cmpRemotes(false)
198+
return c.global.cmpRemotes(toComplete, false)
199199
}
200200

201201
return nil, cobra.ShellCompDirectiveNoFileComp
@@ -481,7 +481,7 @@ Pre-defined column shorthand chars:
481481

482482
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
483483
if len(args) == 0 {
484-
return c.global.cmpRemotes(false)
484+
return c.global.cmpRemotes(toComplete, false)
485485
}
486486

487487
return nil, cobra.ShellCompDirectiveNoFileComp

cmd/incus/completion.go

Lines changed: 114 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ package main
22

33
import (
44
"fmt"
5+
"io/fs"
6+
"os"
7+
"path/filepath"
58
"regexp"
69
"strings"
710

@@ -71,7 +74,7 @@ func (g *cmdGlobal) cmpClusterGroups(toComplete string) ([]string, cobra.ShellCo
7174
}
7275

7376
if !strings.Contains(toComplete, ":") {
74-
remotes, directives := g.cmpRemotes(false)
77+
remotes, directives := g.cmpRemotes(toComplete, false)
7578
results = append(results, remotes...)
7679
cmpDirectives |= directives
7780
}
@@ -192,7 +195,7 @@ func (g *cmdGlobal) cmpClusterMembers(toComplete string) ([]string, cobra.ShellC
192195
}
193196

194197
if !strings.Contains(toComplete, ":") {
195-
remotes, directives := g.cmpRemotes(false)
198+
remotes, directives := g.cmpRemotes(toComplete, false)
196199
results = append(results, remotes...)
197200
cmpDirectives |= directives
198201
}
@@ -230,7 +233,7 @@ func (g *cmdGlobal) cmpImages(toComplete string) ([]string, cobra.ShellCompDirec
230233
}
231234

232235
if !strings.Contains(toComplete, ":") {
233-
remotes, directives := g.cmpRemotes(true)
236+
remotes, directives := g.cmpRemotes(toComplete, true)
234237
results = append(results, remotes...)
235238
cmpDirectives |= directives
236239
}
@@ -330,12 +333,16 @@ func (g *cmdGlobal) cmpInstances(toComplete string) ([]string, cobra.ShellCompDi
330333
name = fmt.Sprintf("%s:%s", resource.remote, instName)
331334
}
332335

336+
if !strings.HasPrefix(name, toComplete) {
337+
continue
338+
}
339+
333340
results = append(results, name)
334341
}
335342
}
336343

337344
if !strings.Contains(toComplete, ":") {
338-
remotes, directives := g.cmpRemotes(false)
345+
remotes, directives := g.cmpRemotes(toComplete, false)
339346
results = append(results, remotes...)
340347
cmpDirectives |= directives
341348
}
@@ -375,7 +382,7 @@ func (g *cmdGlobal) cmpInstancesAndSnapshots(toComplete string) ([]string, cobra
375382
}
376383

377384
if !strings.Contains(toComplete, ":") {
378-
remotes, directives := g.cmpRemotes(false)
385+
remotes, directives := g.cmpRemotes(toComplete, false)
379386
results = append(results, remotes...)
380387
cmpDirectives |= directives
381388
}
@@ -453,7 +460,7 @@ func (g *cmdGlobal) cmpNetworkACLs(toComplete string) ([]string, cobra.ShellComp
453460
}
454461

455462
if !strings.Contains(toComplete, ":") {
456-
remotes, directives := g.cmpRemotes(false)
463+
remotes, directives := g.cmpRemotes(toComplete, false)
457464
results = append(results, remotes...)
458465
cmpDirectives |= directives
459466
}
@@ -607,7 +614,7 @@ func (g *cmdGlobal) cmpNetworks(toComplete string) ([]string, cobra.ShellCompDir
607614
}
608615

609616
if !strings.Contains(toComplete, ":") {
610-
remotes, directives := g.cmpRemotes(false)
617+
remotes, directives := g.cmpRemotes(toComplete, false)
611618
results = append(results, remotes...)
612619
cmpDirectives |= directives
613620
}
@@ -789,7 +796,7 @@ func (g *cmdGlobal) cmpNetworkZones(toComplete string) ([]string, cobra.ShellCom
789796
}
790797

791798
if !strings.Contains(toComplete, ":") {
792-
remotes, directives := g.cmpRemotes(false)
799+
remotes, directives := g.cmpRemotes(toComplete, false)
793800
results = append(results, remotes...)
794801
cmpDirectives |= directives
795802
}
@@ -882,7 +889,7 @@ func (g *cmdGlobal) cmpProfiles(toComplete string, includeRemotes bool) ([]strin
882889
}
883890

884891
if includeRemotes && !strings.Contains(toComplete, ":") {
885-
remotes, directives := g.cmpRemotes(false)
892+
remotes, directives := g.cmpRemotes(toComplete, false)
886893
results = append(results, remotes...)
887894
cmpDirectives |= directives
888895
}
@@ -940,26 +947,34 @@ func (g *cmdGlobal) cmpProjects(toComplete string) ([]string, cobra.ShellCompDir
940947
}
941948

942949
if !strings.Contains(toComplete, ":") {
943-
remotes, directives := g.cmpRemotes(false)
950+
remotes, directives := g.cmpRemotes(toComplete, false)
944951
results = append(results, remotes...)
945952
cmpDirectives |= directives
946953
}
947954

948955
return results, cmpDirectives
949956
}
950957

951-
func (g *cmdGlobal) cmpRemotes(includeAll bool) ([]string, cobra.ShellCompDirective) {
958+
func (g *cmdGlobal) cmpRemotes(toComplete string, includeAll bool) ([]string, cobra.ShellCompDirective) {
952959
results := []string{}
953960

954961
for remoteName, rc := range g.conf.Remotes {
955962
if !includeAll && rc.Protocol != "incus" && rc.Protocol != "" {
956963
continue
957964
}
958965

966+
if !strings.HasPrefix(remoteName, toComplete) {
967+
continue
968+
}
969+
959970
results = append(results, fmt.Sprintf("%s:", remoteName))
960971
}
961972

962-
return results, cobra.ShellCompDirectiveNoSpace
973+
if len(results) > 0 {
974+
return results, cobra.ShellCompDirectiveNoSpace
975+
}
976+
977+
return results, cobra.ShellCompDirectiveNoFileComp
963978
}
964979

965980
func (g *cmdGlobal) cmpRemoteNames() ([]string, cobra.ShellCompDirective) {
@@ -1056,7 +1071,7 @@ func (g *cmdGlobal) cmpStoragePools(toComplete string) ([]string, cobra.ShellCom
10561071
}
10571072

10581073
if !strings.Contains(toComplete, ":") {
1059-
remotes, _ := g.cmpRemotes(false)
1074+
remotes, _ := g.cmpRemotes(toComplete, false)
10601075
results = append(results, remotes...)
10611076
}
10621077

@@ -1210,3 +1225,89 @@ func (g *cmdGlobal) cmpStoragePoolVolumes(poolName string) ([]string, cobra.Shel
12101225

12111226
return volumes, cobra.ShellCompDirectiveNoFileComp
12121227
}
1228+
1229+
func isSymlinkToDir(path string, d fs.DirEntry) bool {
1230+
if d.Type()&fs.ModeSymlink == 0 {
1231+
return false
1232+
}
1233+
1234+
info, err := os.Stat(path)
1235+
if err != nil || !info.IsDir() {
1236+
return false
1237+
}
1238+
1239+
return true
1240+
}
1241+
1242+
func (g *cmdGlobal) cmpFiles(toComplete string, includeLocalFiles bool) ([]string, cobra.ShellCompDirective) {
1243+
instances, directives := g.cmpInstances(toComplete)
1244+
for i := range instances {
1245+
if strings.HasSuffix(instances[i], ":") {
1246+
continue
1247+
}
1248+
1249+
instances[i] += "/"
1250+
}
1251+
1252+
if len(instances) == 0 {
1253+
if includeLocalFiles {
1254+
return nil, cobra.ShellCompDirectiveDefault
1255+
}
1256+
1257+
return instances, directives
1258+
}
1259+
1260+
directives |= cobra.ShellCompDirectiveNoSpace
1261+
1262+
if !includeLocalFiles {
1263+
return instances, directives
1264+
}
1265+
1266+
var files []string
1267+
sep := string(filepath.Separator)
1268+
dir, prefix := filepath.Split(toComplete)
1269+
switch prefix {
1270+
case ".":
1271+
files = append(files, dir+"."+sep)
1272+
fallthrough
1273+
case "..":
1274+
files = append(files, dir+".."+sep)
1275+
directives |= cobra.ShellCompDirectiveNoSpace
1276+
}
1277+
1278+
root, err := filepath.EvalSymlinks(filepath.Dir(dir))
1279+
if err != nil {
1280+
return append(instances, files...), directives
1281+
}
1282+
1283+
_ = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
1284+
if err != nil || path == root {
1285+
return err
1286+
}
1287+
1288+
base := filepath.Base(path)
1289+
if strings.HasPrefix(base, prefix) {
1290+
file := dir + base
1291+
switch {
1292+
case d.IsDir():
1293+
directives |= cobra.ShellCompDirectiveNoSpace
1294+
file += sep
1295+
case isSymlinkToDir(path, d):
1296+
directives |= cobra.ShellCompDirectiveNoSpace
1297+
if base == prefix {
1298+
file += sep
1299+
}
1300+
}
1301+
1302+
files = append(files, file)
1303+
}
1304+
1305+
if d.IsDir() {
1306+
return fs.SkipDir
1307+
}
1308+
1309+
return nil
1310+
})
1311+
1312+
return append(instances, files...), directives
1313+
}

cmd/incus/copy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ The pull transfer mode is the default as it is compatible with all server versio
7171
}
7272

7373
if len(args) == 1 {
74-
return c.global.cmpRemotes(false)
74+
return c.global.cmpRemotes(toComplete, false)
7575
}
7676

7777
return nil, cobra.ShellCompDirectiveNoFileComp

cmd/incus/file.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,17 @@ func (c *cmdFilePull) Command() *cobra.Command {
475475

476476
cmd.Flags().BoolVarP(&c.file.flagMkdir, "create-dirs", "p", false, i18n.G("Create any directories necessary"))
477477
cmd.Flags().BoolVarP(&c.file.flagRecursive, "recursive", "r", false, i18n.G("Recursively transfer files"))
478+
478479
cmd.RunE = c.Run
479480

481+
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
482+
if len(args) == 0 {
483+
return c.global.cmpFiles(toComplete, false)
484+
}
485+
486+
return c.global.cmpFiles(toComplete, true)
487+
}
488+
480489
return cmd
481490
}
482491

@@ -697,8 +706,17 @@ func (c *cmdFilePush) Command() *cobra.Command {
697706
cmd.Flags().IntVar(&c.file.flagUID, "uid", -1, i18n.G("Set the file's uid on push")+"``")
698707
cmd.Flags().IntVar(&c.file.flagGID, "gid", -1, i18n.G("Set the file's gid on push")+"``")
699708
cmd.Flags().StringVar(&c.file.flagMode, "mode", "", i18n.G("Set the file's perms on push")+"``")
709+
700710
cmd.RunE = c.Run
701711

712+
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
713+
if len(args) == 0 {
714+
return nil, cobra.ShellCompDirectiveDefault
715+
}
716+
717+
return c.global.cmpFiles(toComplete, true)
718+
}
719+
702720
return cmd
703721
}
704722

cmd/incus/image.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ It requires the source to be an alias and for it to be public.`))
167167
}
168168

169169
if len(args) == 1 {
170-
return c.global.cmpRemotes(false)
170+
return c.global.cmpRemotes(toComplete, false)
171171
}
172172

173173
return nil, cobra.ShellCompDirectiveNoFileComp
@@ -680,7 +680,7 @@ Directory import is only available on Linux and must be performed as root.`))
680680
}
681681

682682
if len(args) == 1 {
683-
return c.global.cmpRemotes(false)
683+
return c.global.cmpRemotes(toComplete, false)
684684
}
685685

686686
return nil, cobra.ShellCompDirectiveNoFileComp

cmd/incus/list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ incus list -c ns,user.comment:comment
138138

139139
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
140140
if len(args) == 0 {
141-
return c.global.cmpRemotes(false)
141+
return c.global.cmpRemotes(toComplete, false)
142142
}
143143

144144
return nil, cobra.ShellCompDirectiveNoFileComp

cmd/incus/move.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ incus move <instance>/<old snapshot name> <instance>/<new snapshot name>
7171
}
7272

7373
if len(args) == 1 {
74-
return c.global.cmpRemotes(false)
74+
return c.global.cmpRemotes(toComplete, false)
7575
}
7676

7777
return nil, cobra.ShellCompDirectiveNoFileComp

cmd/incus/network.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ incus network create bar network=baz --type ovn
354354
return nil, cobra.ShellCompDirectiveNoFileComp
355355
}
356356

357-
return c.global.cmpRemotes(false)
357+
return c.global.cmpRemotes(toComplete, false)
358358
}
359359

360360
return cmd
@@ -1079,7 +1079,7 @@ u - Used by (count)`))
10791079
return nil, cobra.ShellCompDirectiveNoFileComp
10801080
}
10811081

1082-
return c.global.cmpRemotes(false)
1082+
return c.global.cmpRemotes(toComplete, false)
10831083
}
10841084

10851085
return cmd

cmd/incus/network_acl.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (c *cmdNetworkACLList) Command() *cobra.Command {
9999

100100
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
101101
if len(args) == 0 {
102-
return c.global.cmpRemotes(false)
102+
return c.global.cmpRemotes(toComplete, false)
103103
}
104104

105105
return nil, cobra.ShellCompDirectiveNoFileComp

cmd/incus/network_zone.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Pre-defined column shorthand chars:
116116

117117
cmd.ValidArgsFunction = func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
118118
if len(args) == 0 {
119-
return c.global.cmpRemotes(false)
119+
return c.global.cmpRemotes(toComplete, false)
120120
}
121121

122122
return nil, cobra.ShellCompDirectiveNoFileComp

0 commit comments

Comments
 (0)