lsf: Add --csv flag for compliant CSV output

This commit is contained in:
Nick Craig-Wood 2018-05-13 12:15:05 +01:00
parent 2a32e2d838
commit e56be0dfd8
3 changed files with 61 additions and 7 deletions

View File

@ -23,6 +23,7 @@ var (
hashType = hash.MD5
filesOnly bool
dirsOnly bool
csv bool
)
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.BoolVarP(&filesOnly, "files-only", "", false, "Only list files.")
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.")
}
@ -113,11 +115,28 @@ Eg
2018-04-26 08:52:53,0,,ferejej3gux/
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,
Run: func(command *cobra.Command, args []string) {
cmd.CheckArgs(1, 1, command, args)
fsrc := cmd.NewFsSrc(args)
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)
})
},
@ -128,6 +147,7 @@ Eg
func Lsf(fsrc fs.Fs, out io.Writer) error {
var list operations.ListFormat
list.SetSeparator(separator)
list.SetCSV(csv)
list.SetDirSlash(dirSlash)
for _, char := range format {

View File

@ -4,6 +4,7 @@ package operations
import (
"bytes"
"context"
"encoding/csv"
"fmt"
"io"
"io/ioutil"
@ -1368,6 +1369,8 @@ type ListFormat struct {
dirSlash bool
output []func() string
entry fs.DirEntry
csv *csv.Writer
buf bytes.Buffer
}
// SetSeparator changes separator in struct
@ -1380,6 +1383,21 @@ func (l *ListFormat) SetDirSlash(dirSlash bool) {
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
func (l *ListFormat) SetOutput(output []func() string) {
l.output = output
@ -1439,18 +1457,23 @@ func (l *ListFormat) AddMimeType() {
// AppendOutput adds string generated by specific function to printed output
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)
}
// 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
var out string
var out []string
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
}

View File

@ -747,4 +747,15 @@ func TestListFormat(t *testing.T) {
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]))
}