github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/test/info/internal/build_csv/main.go (about)

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