rclone/cmd/test/info/internal/internal.go

158 lines
3.2 KiB
Go

// Package internal provides internal implementation for the info test command.
package internal
import (
"bytes"
"encoding/json"
"fmt"
"strings"
)
// Presence describes the presence of a filename in file listing
type Presence int
// Possible Presence states
const (
Absent Presence = iota
Present
Renamed
Multiple
)
// Position is the placement of the test character in the filename
type Position int
// Predefined positions
const (
PositionMiddle Position = 1 << iota
PositionLeft
PositionRight
PositionNone Position = 0
PositionAll Position = PositionRight<<1 - 1
)
// PositionList contains all valid positions
var PositionList = []Position{PositionMiddle, PositionLeft, PositionRight}
// ControlResult contains the result of a single character test
type ControlResult struct {
Text string `json:"-"`
WriteError map[Position]string
GetError map[Position]string
InList map[Position]Presence
}
// InfoReport is the structure of the JSON output
type InfoReport struct {
Remote string
ControlCharacters *map[string]ControlResult
MaxFileLength *int
CanStream *bool
CanWriteUnnormalized *bool
CanReadUnnormalized *bool
CanReadRenormalized *bool
}
func (e Position) String() string {
switch e {
case PositionNone:
return "none"
case PositionAll:
return "all"
}
var buf bytes.Buffer
if e&PositionMiddle != 0 {
buf.WriteString("middle")
e &= ^PositionMiddle
}
if e&PositionLeft != 0 {
if buf.Len() != 0 {
buf.WriteRune(',')
}
buf.WriteString("left")
e &= ^PositionLeft
}
if e&PositionRight != 0 {
if buf.Len() != 0 {
buf.WriteRune(',')
}
buf.WriteString("right")
e &= ^PositionRight
}
if e != PositionNone {
panic("invalid position")
}
return buf.String()
}
// MarshalText encodes the position when used as a map key
func (e Position) MarshalText() ([]byte, error) {
return []byte(e.String()), nil
}
// UnmarshalText decodes a position when used as a map key
func (e *Position) UnmarshalText(text []byte) error {
switch s := strings.ToLower(string(text)); s {
default:
*e = PositionNone
for _, p := range strings.Split(s, ",") {
switch p {
case "left":
*e |= PositionLeft
case "middle":
*e |= PositionMiddle
case "right":
*e |= PositionRight
default:
return fmt.Errorf("unknown position: %s", e)
}
}
case "none":
*e = PositionNone
case "all":
*e = PositionAll
}
return nil
}
func (e Presence) String() string {
switch e {
case Absent:
return "absent"
case Present:
return "present"
case Renamed:
return "renamed"
case Multiple:
return "multiple"
default:
panic("invalid presence")
}
}
// MarshalJSON encodes the presence when used as a JSON value
func (e Presence) MarshalJSON() ([]byte, error) {
return json.Marshal(e.String())
}
// UnmarshalJSON decodes a presence when used as a JSON value
func (e *Presence) UnmarshalJSON(text []byte) error {
var s string
if err := json.Unmarshal(text, &s); err != nil {
return err
}
switch s := strings.ToLower(s); s {
case "absent":
*e = Absent
case "present":
*e = Present
case "renamed":
*e = Renamed
case "multiple":
*e = Multiple
default:
return fmt.Errorf("unknown presence: %s", e)
}
return nil
}