-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlist.go
110 lines (96 loc) · 2.55 KB
/
list.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package main
import (
"errors"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
"text/tabwriter"
)
type list struct {
optPathConfig
Recursive bool `kong:"short=r,help='recursively descend into folders'"`
}
func isSubfile(dir, f string) bool {
return dir == "/" || dir == f || strings.HasPrefix(f, dir+"/")
}
func (l *list) AfterApply() error {
if l.Path == "" && l.Recursive {
return errors.New("omitted path matches all shares, --recursive (-r) is unnecessary")
}
return l.optPathConfig.AfterApply()
}
func (l *list) Run() error {
accounts := l.accounts
if l.remoteFile != "" {
accounts = []account{l.account}
}
for _, acc := range accounts {
if len(accounts) > 1 {
fmt.Printf("%s on %s:\n", acc.user, acc.url)
}
shares, err := l.loadShares(acc)
if err != nil {
return err
}
l.writeShares(shares)
}
return nil
}
func (l *list) writeShares(shares []sharedFile) {
w := tabwriter.NewWriter(os.Stdout, 1, 1, 2, ' ', 0)
for _, e := range shares {
if l.Recursive {
if !isSubfile(l.remoteFile, e.Path) {
continue
}
relRemote := filepath.FromSlash(strings.TrimPrefix(e.Path, l.remoteFile))
sep := ""
if e.ItemType == "folder" {
sep = string(filepath.Separator)
}
fmt.Fprint(w, filepath.Join(l.Path, relRemote), sep, "\t")
} else if l.remoteFile == "" {
sep := ""
if e.ItemType == "folder" {
sep = "/"
}
fmt.Fprint(w, e.Path, sep, "\t")
}
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", e.ID, e.fmtShareLink(l.url), fmtExpiry(e.Expiration), e.fmtNote())
}
w.Flush()
}
func (l *list) Help() string {
return `
Lists all shares with their data ([path], id, url, expiry date) on local file or folder.
If recursive, it prints the paths, relative to the one passed as argument.
When no file is supplied, shares of all accounts are printed with full server paths.`
}
// loadShares loads and returns all shared files that matches path from command
// line. Empty path matches shared files.
func (l *list) loadShares(acc account) ([]sharedFile, error) {
v := url.Values{}
// recursive query needs to fetch the whole list
if !l.Recursive && l.remoteFile != "" {
v.Set("path", l.remoteFile)
}
data, err := request[shares](acc, "GET", v)
if err != nil {
return nil, fmt.Errorf("loading shares: %w", err)
}
pos := 0
for i, e := range data.Elements {
// filter out non matching recursive elements
if l.Recursive && !strings.HasPrefix(e.Path, l.remoteFile) {
continue
}
data.Elements[pos] = data.Elements[i]
pos++
}
return data.Elements[:pos], nil
}
type shares struct {
Elements []sharedFile `xml:"element"`
}