lsf: add 'e' format to show encrypted names and 'o' for original IDs
This brings it up to par with lsjson. This commit also reworks the framework to use ListJSON internally which removes duplicated code and makes testing easier.
This commit is contained in:
parent
240c15883f
commit
0b9d7fec0c
3 changed files with 130 additions and 79 deletions
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/ncw/rclone/fs"
|
"github.com/ncw/rclone/fs"
|
||||||
"github.com/ncw/rclone/fs/hash"
|
"github.com/ncw/rclone/fs/hash"
|
||||||
"github.com/ncw/rclone/fs/operations"
|
"github.com/ncw/rclone/fs/operations"
|
||||||
"github.com/ncw/rclone/fs/walk"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -67,8 +66,10 @@ output:
|
||||||
s - size
|
s - size
|
||||||
t - modification time
|
t - modification time
|
||||||
h - hash
|
h - hash
|
||||||
i - ID of object if known
|
i - ID of object
|
||||||
|
o - Original ID of underlying object
|
||||||
m - MimeType of object if known
|
m - MimeType of object if known
|
||||||
|
e - encrypted name
|
||||||
|
|
||||||
So if you wanted the path, size and modification time, you would use
|
So if you wanted the path, size and modification time, you would use
|
||||||
--format "pst", or maybe --format "tsp" to put the path last.
|
--format "pst", or maybe --format "tsp" to put the path last.
|
||||||
|
@ -161,6 +162,10 @@ func Lsf(fsrc fs.Fs, out io.Writer) error {
|
||||||
list.SetCSV(csv)
|
list.SetCSV(csv)
|
||||||
list.SetDirSlash(dirSlash)
|
list.SetDirSlash(dirSlash)
|
||||||
list.SetAbsolute(absolute)
|
list.SetAbsolute(absolute)
|
||||||
|
var opt = operations.ListJSONOpt{
|
||||||
|
NoModTime: true,
|
||||||
|
Recurse: recurse,
|
||||||
|
}
|
||||||
|
|
||||||
for _, char := range format {
|
for _, char := range format {
|
||||||
switch char {
|
switch char {
|
||||||
|
@ -168,38 +173,38 @@ func Lsf(fsrc fs.Fs, out io.Writer) error {
|
||||||
list.AddPath()
|
list.AddPath()
|
||||||
case 't':
|
case 't':
|
||||||
list.AddModTime()
|
list.AddModTime()
|
||||||
|
opt.NoModTime = false
|
||||||
case 's':
|
case 's':
|
||||||
list.AddSize()
|
list.AddSize()
|
||||||
case 'h':
|
case 'h':
|
||||||
list.AddHash(hashType)
|
list.AddHash(hashType)
|
||||||
|
opt.ShowHash = true
|
||||||
case 'i':
|
case 'i':
|
||||||
list.AddID()
|
list.AddID()
|
||||||
case 'm':
|
case 'm':
|
||||||
list.AddMimeType()
|
list.AddMimeType()
|
||||||
|
case 'e':
|
||||||
|
list.AddEncrypted()
|
||||||
|
opt.ShowEncrypted = true
|
||||||
|
case 'o':
|
||||||
|
list.AddOrigID()
|
||||||
|
opt.ShowOrigIDs = true
|
||||||
default:
|
default:
|
||||||
return errors.Errorf("Unknown format character %q", char)
|
return errors.Errorf("Unknown format character %q", char)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return walk.Walk(fsrc, "", false, operations.ConfigMaxDepth(recurse), func(path string, entries fs.DirEntries, err error) error {
|
return operations.ListJSON(fsrc, "", &opt, func(item *operations.ListJSONItem) error {
|
||||||
if err != nil {
|
if item.IsDir {
|
||||||
fs.CountError(err)
|
if filesOnly {
|
||||||
fs.Errorf(path, "error listing: %v", err)
|
return nil
|
||||||
return nil
|
}
|
||||||
}
|
} else {
|
||||||
for _, entry := range entries {
|
if dirsOnly {
|
||||||
_, isDir := entry.(fs.Directory)
|
return nil
|
||||||
if isDir {
|
|
||||||
if filesOnly {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if dirsOnly {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintln(out, list.Format(entry))
|
|
||||||
}
|
}
|
||||||
|
_, _ = fmt.Fprintln(out, list.Format(item))
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1479,8 +1479,7 @@ type ListFormat struct {
|
||||||
separator string
|
separator string
|
||||||
dirSlash bool
|
dirSlash bool
|
||||||
absolute bool
|
absolute bool
|
||||||
output []func() string
|
output []func(entry *ListJSONItem) string
|
||||||
entry fs.DirEntry
|
|
||||||
csv *csv.Writer
|
csv *csv.Writer
|
||||||
buf bytes.Buffer
|
buf bytes.Buffer
|
||||||
}
|
}
|
||||||
|
@ -1516,76 +1515,91 @@ func (l *ListFormat) SetCSV(useCSV bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetOutput sets functions used to create files information
|
// SetOutput sets functions used to create files information
|
||||||
func (l *ListFormat) SetOutput(output []func() string) {
|
func (l *ListFormat) SetOutput(output []func(entry *ListJSONItem) string) {
|
||||||
l.output = output
|
l.output = output
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddModTime adds file's Mod Time to output
|
// AddModTime adds file's Mod Time to output
|
||||||
func (l *ListFormat) AddModTime() {
|
func (l *ListFormat) AddModTime() {
|
||||||
l.AppendOutput(func() string { return l.entry.ModTime().Local().Format("2006-01-02 15:04:05") })
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
|
return entry.ModTime.When.Local().Format("2006-01-02 15:04:05")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSize adds file's size to output
|
// AddSize adds file's size to output
|
||||||
func (l *ListFormat) AddSize() {
|
func (l *ListFormat) AddSize() {
|
||||||
l.AppendOutput(func() string {
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
return strconv.FormatInt(l.entry.Size(), 10)
|
return strconv.FormatInt(entry.Size, 10)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// normalisePath makes sure the path has the correct slashes for the current mode
|
||||||
|
func (l *ListFormat) normalisePath(entry *ListJSONItem, remote string) string {
|
||||||
|
if l.absolute && !strings.HasPrefix(remote, "/") {
|
||||||
|
remote = "/" + remote
|
||||||
|
}
|
||||||
|
if entry.IsDir && l.dirSlash {
|
||||||
|
remote += "/"
|
||||||
|
}
|
||||||
|
return remote
|
||||||
|
}
|
||||||
|
|
||||||
// AddPath adds path to file to output
|
// AddPath adds path to file to output
|
||||||
func (l *ListFormat) AddPath() {
|
func (l *ListFormat) AddPath() {
|
||||||
l.AppendOutput(func() string {
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
remote := l.entry.Remote()
|
return l.normalisePath(entry, entry.Path)
|
||||||
if l.absolute && !strings.HasPrefix(remote, "/") {
|
})
|
||||||
remote = "/" + remote
|
}
|
||||||
}
|
|
||||||
_, isDir := l.entry.(fs.Directory)
|
// AddEncrypted adds the encrypted path to file to output
|
||||||
if isDir && l.dirSlash {
|
func (l *ListFormat) AddEncrypted() {
|
||||||
remote += "/"
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
}
|
return l.normalisePath(entry, entry.Encrypted)
|
||||||
return remote
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddHash adds the hash of the type given to the output
|
// AddHash adds the hash of the type given to the output
|
||||||
func (l *ListFormat) AddHash(ht hash.Type) {
|
func (l *ListFormat) AddHash(ht hash.Type) {
|
||||||
l.AppendOutput(func() string {
|
hashName := ht.String()
|
||||||
o, ok := l.entry.(fs.Object)
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
if !ok {
|
if entry.IsDir {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return hashSum(ht, o)
|
return entry.Hashes[hashName]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddID adds file's ID to the output if known
|
// AddID adds file's ID to the output if known
|
||||||
func (l *ListFormat) AddID() {
|
func (l *ListFormat) AddID() {
|
||||||
l.AppendOutput(func() string {
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
if do, ok := l.entry.(fs.IDer); ok {
|
return entry.ID
|
||||||
return do.ID()
|
})
|
||||||
}
|
}
|
||||||
return ""
|
|
||||||
|
// AddOrigID adds file's Original ID to the output if known
|
||||||
|
func (l *ListFormat) AddOrigID() {
|
||||||
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
|
return entry.OrigID
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddMimeType adds file's MimeType to the output if known
|
// AddMimeType adds file's MimeType to the output if known
|
||||||
func (l *ListFormat) AddMimeType() {
|
func (l *ListFormat) AddMimeType() {
|
||||||
l.AppendOutput(func() string {
|
l.AppendOutput(func(entry *ListJSONItem) string {
|
||||||
return fs.MimeTypeDirEntry(l.entry)
|
return entry.MimeType
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// AppendOutput adds string generated by specific function to printed output
|
// AppendOutput adds string generated by specific function to printed output
|
||||||
func (l *ListFormat) AppendOutput(functionToAppend func() string) {
|
func (l *ListFormat) AppendOutput(functionToAppend func(item *ListJSONItem) string) {
|
||||||
l.output = append(l.output, functionToAppend)
|
l.output = append(l.output, functionToAppend)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format prints information about the DirEntry in the format defined
|
// Format prints information about the DirEntry in the format defined
|
||||||
func (l *ListFormat) Format(entry fs.DirEntry) (result string) {
|
func (l *ListFormat) Format(entry *ListJSONItem) (result string) {
|
||||||
l.entry = entry
|
|
||||||
var out []string
|
var out []string
|
||||||
for _, fun := range l.output {
|
for _, fun := range l.output {
|
||||||
out = append(out, fun())
|
out = append(out, fun(entry))
|
||||||
}
|
}
|
||||||
if l.csv != nil {
|
if l.csv != nil {
|
||||||
l.buf.Reset()
|
l.buf.Reset()
|
||||||
|
|
|
@ -39,7 +39,6 @@ import (
|
||||||
"github.com/ncw/rclone/fs/accounting"
|
"github.com/ncw/rclone/fs/accounting"
|
||||||
"github.com/ncw/rclone/fs/filter"
|
"github.com/ncw/rclone/fs/filter"
|
||||||
"github.com/ncw/rclone/fs/hash"
|
"github.com/ncw/rclone/fs/hash"
|
||||||
"github.com/ncw/rclone/fs/list"
|
|
||||||
"github.com/ncw/rclone/fs/operations"
|
"github.com/ncw/rclone/fs/operations"
|
||||||
"github.com/ncw/rclone/fstest"
|
"github.com/ncw/rclone/fstest"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -873,61 +872,90 @@ func TestCheckEqualReaders(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListFormat(t *testing.T) {
|
func TestListFormat(t *testing.T) {
|
||||||
r := fstest.NewRun(t)
|
item0 := &operations.ListJSONItem{
|
||||||
defer r.Finalise()
|
Path: "a",
|
||||||
file1 := r.WriteObject("a", "a", t1)
|
Name: "a",
|
||||||
file2 := r.WriteObject("subdir/b", "b", t1)
|
Encrypted: "encryptedFileName",
|
||||||
|
Size: 1,
|
||||||
|
MimeType: "application/octet-stream",
|
||||||
|
ModTime: operations.Timestamp{
|
||||||
|
When: t1,
|
||||||
|
Format: "2006-01-02T15:04:05.000000000Z07:00"},
|
||||||
|
IsDir: false,
|
||||||
|
Hashes: map[string]string{
|
||||||
|
"MD5": "0cc175b9c0f1b6a831c399e269772661",
|
||||||
|
"SHA-1": "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
|
||||||
|
"DropboxHash": "bf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8",
|
||||||
|
"QuickXorHash": "6100000000000000000000000100000000000000"},
|
||||||
|
ID: "fileID",
|
||||||
|
OrigID: "fileOrigID",
|
||||||
|
}
|
||||||
|
|
||||||
fstest.CheckItems(t, r.Fremote, file1, file2)
|
item1 := &operations.ListJSONItem{
|
||||||
|
Path: "subdir",
|
||||||
|
Name: "subdir",
|
||||||
|
Encrypted: "encryptedDirName",
|
||||||
|
Size: -1,
|
||||||
|
MimeType: "inode/directory",
|
||||||
|
ModTime: operations.Timestamp{
|
||||||
|
When: t2,
|
||||||
|
Format: "2006-01-02T15:04:05.000000000Z07:00"},
|
||||||
|
IsDir: true,
|
||||||
|
Hashes: map[string]string(nil),
|
||||||
|
ID: "dirID",
|
||||||
|
OrigID: "dirOrigID",
|
||||||
|
}
|
||||||
|
|
||||||
items, _ := list.DirSorted(r.Fremote, true, "")
|
|
||||||
var list operations.ListFormat
|
var list operations.ListFormat
|
||||||
list.AddPath()
|
list.AddPath()
|
||||||
list.SetDirSlash(false)
|
list.SetDirSlash(false)
|
||||||
assert.Equal(t, "subdir", list.Format(items[1]))
|
assert.Equal(t, "subdir", list.Format(item1))
|
||||||
|
|
||||||
list.SetDirSlash(true)
|
list.SetDirSlash(true)
|
||||||
assert.Equal(t, "subdir/", list.Format(items[1]))
|
assert.Equal(t, "subdir/", list.Format(item1))
|
||||||
|
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
assert.Equal(t, "", list.Format(items[1]))
|
assert.Equal(t, "", list.Format(item1))
|
||||||
|
|
||||||
list.AppendOutput(func() string { return "a" })
|
list.AppendOutput(func(item *operations.ListJSONItem) string { return "a" })
|
||||||
list.AppendOutput(func() string { return "b" })
|
list.AppendOutput(func(item *operations.ListJSONItem) string { return "b" })
|
||||||
assert.Equal(t, "ab", list.Format(items[1]))
|
assert.Equal(t, "ab", list.Format(item1))
|
||||||
list.SetSeparator(":::")
|
list.SetSeparator(":::")
|
||||||
assert.Equal(t, "a:::b", list.Format(items[1]))
|
assert.Equal(t, "a:::b", list.Format(item1))
|
||||||
|
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
list.AddModTime()
|
list.AddModTime()
|
||||||
assert.Equal(t, items[0].ModTime().Local().Format("2006-01-02 15:04:05"), list.Format(items[0]))
|
assert.Equal(t, t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0))
|
||||||
|
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
|
list.SetSeparator("|")
|
||||||
list.AddID()
|
list.AddID()
|
||||||
_ = list.Format(items[0]) // Can't really check anything - at least it didn't panic!
|
list.AddOrigID()
|
||||||
|
assert.Equal(t, "fileID|fileOrigID", list.Format(item0))
|
||||||
|
assert.Equal(t, "dirID|dirOrigID", list.Format(item1))
|
||||||
|
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
list.AddMimeType()
|
list.AddMimeType()
|
||||||
assert.Contains(t, list.Format(items[0]), "/")
|
assert.Contains(t, list.Format(item0), "/")
|
||||||
assert.Equal(t, "inode/directory", list.Format(items[1]))
|
assert.Equal(t, "inode/directory", list.Format(item1))
|
||||||
|
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
list.AddPath()
|
list.AddPath()
|
||||||
list.SetAbsolute(true)
|
list.SetAbsolute(true)
|
||||||
assert.Equal(t, "/a", list.Format(items[0]))
|
assert.Equal(t, "/a", list.Format(item0))
|
||||||
list.SetAbsolute(false)
|
list.SetAbsolute(false)
|
||||||
assert.Equal(t, "a", list.Format(items[0]))
|
assert.Equal(t, "a", list.Format(item0))
|
||||||
|
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
list.AddSize()
|
list.AddSize()
|
||||||
assert.Equal(t, "1", list.Format(items[0]))
|
assert.Equal(t, "1", list.Format(item0))
|
||||||
|
|
||||||
list.AddPath()
|
list.AddPath()
|
||||||
list.AddModTime()
|
list.AddModTime()
|
||||||
list.SetDirSlash(true)
|
list.SetDirSlash(true)
|
||||||
list.SetSeparator("__SEP__")
|
list.SetSeparator("__SEP__")
|
||||||
assert.Equal(t, "1__SEP__a__SEP__"+items[0].ModTime().Local().Format("2006-01-02 15:04:05"), list.Format(items[0]))
|
assert.Equal(t, "1__SEP__a__SEP__"+t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0))
|
||||||
assert.Equal(t, fmt.Sprintf("%d", items[1].Size())+"__SEP__subdir/__SEP__"+items[1].ModTime().Local().Format("2006-01-02 15:04:05"), list.Format(items[1]))
|
assert.Equal(t, "-1__SEP__subdir/__SEP__"+t2.Local().Format("2006-01-02 15:04:05"), list.Format(item1))
|
||||||
|
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
ht hash.Type
|
ht hash.Type
|
||||||
|
@ -939,10 +967,7 @@ func TestListFormat(t *testing.T) {
|
||||||
} {
|
} {
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
list.AddHash(test.ht)
|
list.AddHash(test.ht)
|
||||||
got := list.Format(items[0])
|
assert.Equal(t, test.want, list.Format(item0))
|
||||||
if got != "UNSUPPORTED" && got != "" {
|
|
||||||
assert.Equal(t, test.want, got)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
list.SetOutput(nil)
|
list.SetOutput(nil)
|
||||||
|
@ -952,8 +977,15 @@ func TestListFormat(t *testing.T) {
|
||||||
list.AddPath()
|
list.AddPath()
|
||||||
list.AddModTime()
|
list.AddModTime()
|
||||||
list.SetDirSlash(true)
|
list.SetDirSlash(true)
|
||||||
assert.Equal(t, "1|a|"+items[0].ModTime().Local().Format("2006-01-02 15:04:05"), list.Format(items[0]))
|
assert.Equal(t, "1|a|"+t1.Local().Format("2006-01-02 15:04:05"), list.Format(item0))
|
||||||
assert.Equal(t, fmt.Sprintf("%d", items[1].Size())+"|subdir/|"+items[1].ModTime().Local().Format("2006-01-02 15:04:05"), list.Format(items[1]))
|
assert.Equal(t, "-1|subdir/|"+t2.Local().Format("2006-01-02 15:04:05"), list.Format(item1))
|
||||||
|
|
||||||
|
list.SetOutput(nil)
|
||||||
|
list.SetSeparator("|")
|
||||||
|
list.AddPath()
|
||||||
|
list.AddEncrypted()
|
||||||
|
assert.Equal(t, "a|encryptedFileName", list.Format(item0))
|
||||||
|
assert.Equal(t, "subdir/|encryptedDirName/", list.Format(item1))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue