mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 08:23:47 +01:00
fs: re-implement CutoffMode, LogLevel, TerminalColorMode with Enum
This almost 100% backwards compatible. The only difference being that in the rc options/get output CutoffMode, LogLevel, TerminalColorMode will be output as strings instead of integers. This is a lot more convenient for the user. They still accept integer inputs though so the fallout from this should be minimal.
This commit is contained in:
parent
60a6ef914c
commit
3092f82dcc
@ -1,58 +1,22 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
type cutoffModeChoices struct{}
|
||||||
"fmt"
|
|
||||||
"strings"
|
func (cutoffModeChoices) Choices() []string {
|
||||||
)
|
return []string{
|
||||||
|
CutoffModeHard: "HARD",
|
||||||
|
CutoffModeSoft: "SOFT",
|
||||||
|
CutoffModeCautious: "CAUTIOUS",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CutoffMode describes the possible delete modes in the config
|
// CutoffMode describes the possible delete modes in the config
|
||||||
type CutoffMode byte
|
type CutoffMode = Enum[cutoffModeChoices]
|
||||||
|
|
||||||
// MaxTransferMode constants
|
// CutoffMode constants
|
||||||
const (
|
const (
|
||||||
CutoffModeHard CutoffMode = iota
|
CutoffModeHard CutoffMode = iota
|
||||||
CutoffModeSoft
|
CutoffModeSoft
|
||||||
CutoffModeCautious
|
CutoffModeCautious
|
||||||
CutoffModeDefault = CutoffModeHard
|
CutoffModeDefault = CutoffModeHard
|
||||||
)
|
)
|
||||||
|
|
||||||
var cutoffModeToString = []string{
|
|
||||||
CutoffModeHard: "HARD",
|
|
||||||
CutoffModeSoft: "SOFT",
|
|
||||||
CutoffModeCautious: "CAUTIOUS",
|
|
||||||
}
|
|
||||||
|
|
||||||
// String turns a LogLevel into a string
|
|
||||||
func (m CutoffMode) String() string {
|
|
||||||
if m >= CutoffMode(len(cutoffModeToString)) {
|
|
||||||
return fmt.Sprintf("CutoffMode(%d)", m)
|
|
||||||
}
|
|
||||||
return cutoffModeToString[m]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a LogLevel
|
|
||||||
func (m *CutoffMode) Set(s string) error {
|
|
||||||
for n, name := range cutoffModeToString {
|
|
||||||
if s != "" && name == strings.ToUpper(s) {
|
|
||||||
*m = CutoffMode(n)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("unknown cutoff mode %q", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type of the value
|
|
||||||
func (m CutoffMode) Type() string {
|
|
||||||
return "string"
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON makes sure the value can be parsed as a string or integer in JSON
|
|
||||||
func (m *CutoffMode) UnmarshalJSON(in []byte) error {
|
|
||||||
return UnmarshalJSONFlag(in, m, func(i int64) error {
|
|
||||||
if i < 0 || i >= int64(len(cutoffModeToString)) {
|
|
||||||
return fmt.Errorf("out of range cutoff mode %d", i)
|
|
||||||
}
|
|
||||||
*m = (CutoffMode)(i)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -22,7 +22,7 @@ func TestCutoffModeString(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{CutoffModeHard, "HARD"},
|
{CutoffModeHard, "HARD"},
|
||||||
{CutoffModeSoft, "SOFT"},
|
{CutoffModeSoft, "SOFT"},
|
||||||
{99, "CutoffMode(99)"},
|
{99, "Unknown(99)"},
|
||||||
} {
|
} {
|
||||||
cm := test.in
|
cm := test.in
|
||||||
got := cm.String()
|
got := cm.String()
|
||||||
|
15
fs/enum.go
15
fs/enum.go
@ -91,14 +91,17 @@ func (e *Enum[C]) Scan(s fmt.ScanState, ch rune) error {
|
|||||||
return e.Set(string(token))
|
return e.Set(string(token))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON parses it as a string
|
// UnmarshalJSON parses it as a string or an integer
|
||||||
func (e *Enum[C]) UnmarshalJSON(in []byte) error {
|
func (e *Enum[C]) UnmarshalJSON(in []byte) error {
|
||||||
var choice string
|
choices := e.Choices()
|
||||||
err := json.Unmarshal(in, &choice)
|
return UnmarshalJSONFlag(in, e, func(i int64) error {
|
||||||
if err != nil {
|
if i < 0 || i >= int64(len(choices)) {
|
||||||
return err
|
return fmt.Errorf("%d is out of range: must be 0..%d", i, len(choices))
|
||||||
}
|
}
|
||||||
return e.Set(choice)
|
*e = Enum[C](i)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON encodes it as string
|
// MarshalJSON encodes it as string
|
||||||
|
@ -107,16 +107,20 @@ func TestEnumUnmarshalJSON(t *testing.T) {
|
|||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
in string
|
in string
|
||||||
want choice
|
want choice
|
||||||
err bool
|
err string
|
||||||
}{
|
}{
|
||||||
{`"A"`, choiceA, false},
|
{`"A"`, choiceA, ""},
|
||||||
{`"B"`, choiceB, false},
|
{`"B"`, choiceB, ""},
|
||||||
{`"D"`, choice(0), true},
|
{`0`, choiceA, ""},
|
||||||
|
{`1`, choiceB, ""},
|
||||||
|
{`"D"`, choice(0), `invalid choice "D" from: A, B, C`},
|
||||||
|
{`100`, choice(0), `100 is out of range: must be 0..3`},
|
||||||
} {
|
} {
|
||||||
var got choice
|
var got choice
|
||||||
err := json.Unmarshal([]byte(test.in), &got)
|
err := json.Unmarshal([]byte(test.in), &got)
|
||||||
if test.err {
|
if test.err != "" {
|
||||||
require.Error(t, err, test.in)
|
require.Error(t, err, test.in)
|
||||||
|
assert.ErrorContains(t, err, test.err)
|
||||||
} else {
|
} else {
|
||||||
require.NoError(t, err, test.in)
|
require.NoError(t, err, test.in)
|
||||||
}
|
}
|
||||||
|
41
fs/log.go
41
fs/log.go
@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// LogLevel describes rclone's logs. These are a subset of the syslog log levels.
|
// LogLevel describes rclone's logs. These are a subset of the syslog log levels.
|
||||||
type LogLevel byte
|
type LogLevel = Enum[logLevelChoices]
|
||||||
|
|
||||||
// Log levels. These are the syslog levels of which we only use a
|
// Log levels. These are the syslog levels of which we only use a
|
||||||
// subset.
|
// subset.
|
||||||
@ -34,7 +34,10 @@ const (
|
|||||||
LogLevelDebug // Debug level, needs -vv
|
LogLevelDebug // Debug level, needs -vv
|
||||||
)
|
)
|
||||||
|
|
||||||
var logLevelToString = []string{
|
type logLevelChoices struct{}
|
||||||
|
|
||||||
|
func (logLevelChoices) Choices() []string {
|
||||||
|
return []string{
|
||||||
LogLevelEmergency: "EMERGENCY",
|
LogLevelEmergency: "EMERGENCY",
|
||||||
LogLevelAlert: "ALERT",
|
LogLevelAlert: "ALERT",
|
||||||
LogLevelCritical: "CRITICAL",
|
LogLevelCritical: "CRITICAL",
|
||||||
@ -43,43 +46,13 @@ var logLevelToString = []string{
|
|||||||
LogLevelNotice: "NOTICE",
|
LogLevelNotice: "NOTICE",
|
||||||
LogLevelInfo: "INFO",
|
LogLevelInfo: "INFO",
|
||||||
LogLevelDebug: "DEBUG",
|
LogLevelDebug: "DEBUG",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String turns a LogLevel into a string
|
func (logLevelChoices) Type() string {
|
||||||
func (l LogLevel) String() string {
|
|
||||||
if l >= LogLevel(len(logLevelToString)) {
|
|
||||||
return fmt.Sprintf("LogLevel(%d)", l)
|
|
||||||
}
|
|
||||||
return logLevelToString[l]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a LogLevel
|
|
||||||
func (l *LogLevel) Set(s string) error {
|
|
||||||
for n, name := range logLevelToString {
|
|
||||||
if s != "" && name == s {
|
|
||||||
*l = LogLevel(n)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("unknown log level %q", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type of the value
|
|
||||||
func (l LogLevel) Type() string {
|
|
||||||
return "LogLevel"
|
return "LogLevel"
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON makes sure the value can be parsed as a string or integer in JSON
|
|
||||||
func (l *LogLevel) UnmarshalJSON(in []byte) error {
|
|
||||||
return UnmarshalJSONFlag(in, l, func(i int64) error {
|
|
||||||
if i < 0 || i >= int64(LogLevel(len(logLevelToString))) {
|
|
||||||
return fmt.Errorf("unknown log level %d", i)
|
|
||||||
}
|
|
||||||
*l = (LogLevel)(i)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPrintPid enables process pid in log
|
// LogPrintPid enables process pid in log
|
||||||
var LogPrintPid = false
|
var LogPrintPid = false
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ func TestLogLevelString(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{LogLevelEmergency, "EMERGENCY"},
|
{LogLevelEmergency, "EMERGENCY"},
|
||||||
{LogLevelDebug, "DEBUG"},
|
{LogLevelDebug, "DEBUG"},
|
||||||
{99, "LogLevel(99)"},
|
{99, "Unknown(99)"},
|
||||||
} {
|
} {
|
||||||
logLevel := test.in
|
logLevel := test.in
|
||||||
got := logLevel.String()
|
got := logLevel.String()
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TerminalColorMode describes how ANSI codes should be handled
|
// TerminalColorMode describes how ANSI codes should be handled
|
||||||
type TerminalColorMode byte
|
type TerminalColorMode = Enum[terminalColorModeChoices]
|
||||||
|
|
||||||
// TerminalColorMode constants
|
// TerminalColorMode constants
|
||||||
const (
|
const (
|
||||||
@ -15,43 +10,12 @@ const (
|
|||||||
TerminalColorModeAlways
|
TerminalColorModeAlways
|
||||||
)
|
)
|
||||||
|
|
||||||
var terminalColorModeToString = []string{
|
type terminalColorModeChoices struct{}
|
||||||
|
|
||||||
|
func (terminalColorModeChoices) Choices() []string {
|
||||||
|
return []string{
|
||||||
TerminalColorModeAuto: "AUTO",
|
TerminalColorModeAuto: "AUTO",
|
||||||
TerminalColorModeNever: "NEVER",
|
TerminalColorModeNever: "NEVER",
|
||||||
TerminalColorModeAlways: "ALWAYS",
|
TerminalColorModeAlways: "ALWAYS",
|
||||||
}
|
|
||||||
|
|
||||||
// String converts a TerminalColorMode to a string
|
|
||||||
func (m TerminalColorMode) String() string {
|
|
||||||
if m >= TerminalColorMode(len(terminalColorModeToString)) {
|
|
||||||
return fmt.Sprintf("TerminalColorMode(%d)", m)
|
|
||||||
}
|
}
|
||||||
return terminalColorModeToString[m]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a TerminalColorMode
|
|
||||||
func (m *TerminalColorMode) Set(s string) error {
|
|
||||||
for n, name := range terminalColorModeToString {
|
|
||||||
if s != "" && name == strings.ToUpper(s) {
|
|
||||||
*m = TerminalColorMode(n)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fmt.Errorf("unknown terminal color mode %q", s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type of TerminalColorMode
|
|
||||||
func (m TerminalColorMode) Type() string {
|
|
||||||
return "string"
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON converts a string/integer in JSON to a TerminalColorMode
|
|
||||||
func (m *TerminalColorMode) UnmarshalJSON(in []byte) error {
|
|
||||||
return UnmarshalJSONFlag(in, m, func(i int64) error {
|
|
||||||
if i < 0 || i >= int64(len(terminalColorModeToString)) {
|
|
||||||
return fmt.Errorf("out of range terminal color mode %d", i)
|
|
||||||
}
|
|
||||||
*m = (TerminalColorMode)(i)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ func TestTerminalColorModeString(t *testing.T) {
|
|||||||
{TerminalColorModeAuto, "AUTO"},
|
{TerminalColorModeAuto, "AUTO"},
|
||||||
{TerminalColorModeAlways, "ALWAYS"},
|
{TerminalColorModeAlways, "ALWAYS"},
|
||||||
{TerminalColorModeNever, "NEVER"},
|
{TerminalColorModeNever, "NEVER"},
|
||||||
{36, "TerminalColorMode(36)"},
|
{36, "Unknown(36)"},
|
||||||
} {
|
} {
|
||||||
tcm := test.in
|
tcm := test.in
|
||||||
assert.Equal(t, test.want, tcm.String(), test.in)
|
assert.Equal(t, test.want, tcm.String(), test.in)
|
||||||
|
Loading…
Reference in New Issue
Block a user