github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/cmd/info/internal/build_csv/main.go (about) 1 package main 2 3 import ( 4 "encoding/csv" 5 "encoding/json" 6 "flag" 7 "fmt" 8 "io" 9 "log" 10 "os" 11 "sort" 12 "strconv" 13 14 "github.com/rclone/rclone/cmd/info/internal" 15 ) 16 17 func main() { 18 fOut := flag.String("o", "out.csv", "Output file") 19 flag.Parse() 20 21 args := flag.Args() 22 remotes := make([]internal.InfoReport, 0, len(args)) 23 for _, fn := range args { 24 f, err := os.Open(fn) 25 if err != nil { 26 log.Fatalf("Unable to open %q: %s", fn, err) 27 } 28 var remote internal.InfoReport 29 dec := json.NewDecoder(f) 30 err = dec.Decode(&remote) 31 if err != nil { 32 log.Fatalf("Unable to decode %q: %s", fn, err) 33 } 34 if remote.ControlCharacters == nil { 35 log.Printf("Skipping remote %s: no ControlCharacters", remote.Remote) 36 } else { 37 remotes = append(remotes, remote) 38 } 39 if err := f.Close(); err != nil { 40 log.Fatalf("Closing %q failed: %s", fn, err) 41 } 42 } 43 44 charsMap := make(map[string]string) 45 var remoteNames []string 46 for _, r := range remotes { 47 remoteNames = append(remoteNames, r.Remote) 48 for k, v := range *r.ControlCharacters { 49 v.Text = k 50 quoted := strconv.Quote(k) 51 charsMap[k] = quoted[1 : len(quoted)-1] 52 } 53 } 54 sort.Strings(remoteNames) 55 56 chars := make([]string, 0, len(charsMap)) 57 for k := range charsMap { 58 chars = append(chars, k) 59 } 60 sort.Strings(chars) 61 62 // char remote output 63 recordsMap := make(map[string]map[string][]string) 64 // remote output 65 hRemoteMap := make(map[string][]string) 66 hOperation := []string{"Write", "Write", "Write", "Get", "Get", "Get", "List", "List", "List"} 67 hPosition := []string{"L", "M", "R", "L", "M", "R", "L", "M", "R"} 68 69 // remote 70 // write get list 71 // left middle right left middle right left middle right 72 73 for _, r := range remotes { 74 hRemoteMap[r.Remote] = []string{r.Remote, "", "", "", "", "", "", "", ""} 75 for k, v := range *r.ControlCharacters { 76 cMap, ok := recordsMap[k] 77 if !ok { 78 cMap = make(map[string][]string, 1) 79 recordsMap[k] = cMap 80 } 81 82 cMap[r.Remote] = []string{ 83 sok(v.WriteError[internal.PositionLeft]), sok(v.WriteError[internal.PositionMiddle]), sok(v.WriteError[internal.PositionRight]), 84 sok(v.GetError[internal.PositionLeft]), sok(v.GetError[internal.PositionMiddle]), sok(v.GetError[internal.PositionRight]), 85 pok(v.InList[internal.PositionLeft]), pok(v.InList[internal.PositionMiddle]), pok(v.InList[internal.PositionRight]), 86 } 87 } 88 } 89 90 records := [][]string{ 91 []string{"", ""}, 92 []string{"", ""}, 93 []string{"Bytes", "Char"}, 94 } 95 for _, r := range remoteNames { 96 records[0] = append(records[0], hRemoteMap[r]...) 97 records[1] = append(records[1], hOperation...) 98 records[2] = append(records[2], hPosition...) 99 } 100 for _, c := range chars { 101 k := charsMap[c] 102 row := []string{fmt.Sprintf("%X", c), k} 103 for _, r := range remoteNames { 104 if m, ok := recordsMap[c][r]; ok { 105 row = append(row, m...) 106 } else { 107 row = append(row, "", "", "", "", "", "", "", "", "") 108 } 109 } 110 records = append(records, row) 111 } 112 113 var writer io.Writer 114 if *fOut == "-" { 115 writer = os.Stdout 116 } else { 117 f, err := os.Create(*fOut) 118 if err != nil { 119 log.Fatalf("Unable to create %q: %s", *fOut, err) 120 } 121 defer func() { 122 if err := f.Close(); err != nil { 123 log.Fatalln("Error writing csv:", err) 124 } 125 }() 126 writer = f 127 } 128 129 w := csv.NewWriter(writer) 130 err := w.WriteAll(records) 131 if err != nil { 132 log.Fatalln("Error writing csv:", err) 133 } else if err := w.Error(); err != nil { 134 log.Fatalln("Error writing csv:", err) 135 } 136 } 137 138 func sok(s string) string { 139 if s != "" { 140 return "ERR" 141 } 142 return "OK" 143 } 144 145 func pok(p internal.Presence) string { 146 switch p { 147 case internal.Absent: 148 return "MIS" 149 case internal.Present: 150 return "OK" 151 case internal.Renamed: 152 return "REN" 153 case internal.Multiple: 154 return "MUL" 155 default: 156 return "ERR" 157 } 158 }