lsf: Add --csv flag for compliant CSV output
This commit is contained in:
parent
2a32e2d838
commit
e56be0dfd8
3 changed files with 61 additions and 7 deletions
|
@ -23,6 +23,7 @@ var (
|
||||||
hashType = hash.MD5
|
hashType = hash.MD5
|
||||||
filesOnly bool
|
filesOnly bool
|
||||||
dirsOnly bool
|
dirsOnly bool
|
||||||
|
csv bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -34,6 +35,7 @@ func init() {
|
||||||
flags.VarP(&hashType, "hash", "", "Use this hash when `h` is used in the format MD5|SHA-1|DropboxHash")
|
flags.VarP(&hashType, "hash", "", "Use this hash when `h` is used in the format MD5|SHA-1|DropboxHash")
|
||||||
flags.BoolVarP(&filesOnly, "files-only", "", false, "Only list files.")
|
flags.BoolVarP(&filesOnly, "files-only", "", false, "Only list files.")
|
||||||
flags.BoolVarP(&dirsOnly, "dirs-only", "", false, "Only list directories.")
|
flags.BoolVarP(&dirsOnly, "dirs-only", "", false, "Only list directories.")
|
||||||
|
flags.BoolVarP(&csv, "csv", "", false, "Output in CSV format.")
|
||||||
commandDefintion.Flags().BoolVarP(&recurse, "recursive", "R", false, "Recurse into the listing.")
|
commandDefintion.Flags().BoolVarP(&recurse, "recursive", "R", false, "Recurse into the listing.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,11 +115,28 @@ Eg
|
||||||
2018-04-26 08:52:53,0,,ferejej3gux/
|
2018-04-26 08:52:53,0,,ferejej3gux/
|
||||||
2016-06-25 18:55:40,37600,8fd37c3810dd660778137ac3a66cc06d,fubuwic
|
2016-06-25 18:55:40,37600,8fd37c3810dd660778137ac3a66cc06d,fubuwic
|
||||||
|
|
||||||
|
You can output in CSV standard format. This will escape things in "
|
||||||
|
if they contain ,
|
||||||
|
|
||||||
|
Eg
|
||||||
|
|
||||||
|
$ rclone lsf --csv --files-only --format ps remote:path
|
||||||
|
test.log,22355
|
||||||
|
test.sh,449
|
||||||
|
"this file contains a comma, in the file name.txt",6
|
||||||
|
|
||||||
` + lshelp.Help,
|
` + lshelp.Help,
|
||||||
Run: func(command *cobra.Command, args []string) {
|
Run: func(command *cobra.Command, args []string) {
|
||||||
cmd.CheckArgs(1, 1, command, args)
|
cmd.CheckArgs(1, 1, command, args)
|
||||||
fsrc := cmd.NewFsSrc(args)
|
fsrc := cmd.NewFsSrc(args)
|
||||||
cmd.Run(false, false, command, func() error {
|
cmd.Run(false, false, command, func() error {
|
||||||
|
// Work out if the separatorFlag was supplied or not
|
||||||
|
separatorFlag := command.Flags().Lookup("separator")
|
||||||
|
separatorFlagSupplied := separatorFlag != nil && separatorFlag.Changed
|
||||||
|
// Default the separator to , if using CSV
|
||||||
|
if csv && !separatorFlagSupplied {
|
||||||
|
separator = ","
|
||||||
|
}
|
||||||
return Lsf(fsrc, os.Stdout)
|
return Lsf(fsrc, os.Stdout)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
@ -128,6 +147,7 @@ Eg
|
||||||
func Lsf(fsrc fs.Fs, out io.Writer) error {
|
func Lsf(fsrc fs.Fs, out io.Writer) error {
|
||||||
var list operations.ListFormat
|
var list operations.ListFormat
|
||||||
list.SetSeparator(separator)
|
list.SetSeparator(separator)
|
||||||
|
list.SetCSV(csv)
|
||||||
list.SetDirSlash(dirSlash)
|
list.SetDirSlash(dirSlash)
|
||||||
|
|
||||||
for _, char := range format {
|
for _, char := range format {
|
||||||
|
|
|
@ -4,6 +4,7 @@ package operations
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/csv"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -1368,6 +1369,8 @@ type ListFormat struct {
|
||||||
dirSlash bool
|
dirSlash bool
|
||||||
output []func() string
|
output []func() string
|
||||||
entry fs.DirEntry
|
entry fs.DirEntry
|
||||||
|
csv *csv.Writer
|
||||||
|
buf bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSeparator changes separator in struct
|
// SetSeparator changes separator in struct
|
||||||
|
@ -1380,6 +1383,21 @@ func (l *ListFormat) SetDirSlash(dirSlash bool) {
|
||||||
l.dirSlash = dirSlash
|
l.dirSlash = dirSlash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCSV defines if the output should be csv
|
||||||
|
//
|
||||||
|
// Note that you should call SetSeparator before this if you want a
|
||||||
|
// custom separator
|
||||||
|
func (l *ListFormat) SetCSV(useCSV bool) {
|
||||||
|
if useCSV {
|
||||||
|
l.csv = csv.NewWriter(&l.buf)
|
||||||
|
if l.separator != "" {
|
||||||
|
l.csv.Comma = []rune(l.separator)[0]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
l.csv = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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() string) {
|
||||||
l.output = output
|
l.output = output
|
||||||
|
@ -1439,18 +1457,23 @@ func (l *ListFormat) AddMimeType() {
|
||||||
|
|
||||||
// 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() string) {
|
||||||
if len(l.output) > 0 {
|
|
||||||
l.output = append(l.output, func() string { return l.separator })
|
|
||||||
}
|
|
||||||
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) string {
|
func (l *ListFormat) Format(entry fs.DirEntry) (result string) {
|
||||||
l.entry = entry
|
l.entry = entry
|
||||||
var out string
|
var out []string
|
||||||
for _, fun := range l.output {
|
for _, fun := range l.output {
|
||||||
out += fun()
|
out = append(out, fun())
|
||||||
}
|
}
|
||||||
return out
|
if l.csv != nil {
|
||||||
|
l.buf.Reset()
|
||||||
|
_ = l.csv.Write(out) // can't fail writing to bytes.Buffer
|
||||||
|
l.csv.Flush()
|
||||||
|
result = strings.TrimRight(l.buf.String(), "\n")
|
||||||
|
} else {
|
||||||
|
result = strings.Join(out, l.separator)
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
@ -747,4 +747,15 @@ func TestListFormat(t *testing.T) {
|
||||||
assert.Equal(t, test.want, got)
|
assert.Equal(t, test.want, got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list.SetOutput(nil)
|
||||||
|
list.SetSeparator("|")
|
||||||
|
list.SetCSV(true)
|
||||||
|
list.AddSize()
|
||||||
|
list.AddPath()
|
||||||
|
list.AddModTime()
|
||||||
|
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, fmt.Sprintf("%d", items[1].Size())+"|subdir/|"+items[1].ModTime().Local().Format("2006-01-02 15:04:05"), list.Format(items[1]))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue