warn.go

 1package restic
 2
 3import (
 4	"fmt"
 5	"io"
 6	"os"
 7	"strings"
 8
 9	"git.secluded.site/keld/internal/config"
10)
11
12// WarnUnknownFlags writes warnings to stderr for flags that don't exist in
13// restic's generated command metadata. Warnings are non-fatal and execution
14// continues.
15func WarnUnknownFlags(command string, flags []config.Flag) {
16	warnUnknownFlags(os.Stderr, command, flags)
17}
18
19func warnUnknownFlags(w io.Writer, command string, flags []config.Flag) {
20	unknown := unknownFlags(command, flags)
21	if len(unknown) == 0 {
22		return
23	}
24
25	commandLabel := command
26	if commandLabel == "" {
27		commandLabel = "global"
28	}
29
30	for _, flag := range unknown {
31		_, _ = fmt.Fprintf(w, "warning: unknown restic flag %q for command %q\n", flag, commandLabel)
32	}
33}
34
35func unknownFlags(command string, flags []config.Flag) []string {
36	knownLong, knownAlias := knownOptionNames(command)
37	seen := make(map[string]struct{})
38	unknown := make([]string, 0)
39
40	for _, flag := range flags {
41		name := strings.TrimSpace(flag.Name)
42		if name == "" {
43			continue
44		}
45
46		normalized := strings.TrimLeft(name, "-")
47		if normalized == "" {
48			continue
49		}
50
51		known := false
52		if len(normalized) == 1 {
53			_, known = knownAlias[normalized]
54			if !known {
55				_, known = knownLong[normalized]
56			}
57		} else {
58			_, known = knownLong[normalized]
59		}
60
61		if known {
62			continue
63		}
64
65		if _, dup := seen[name]; dup {
66			continue
67		}
68		seen[name] = struct{}{}
69		unknown = append(unknown, name)
70	}
71
72	return unknown
73}
74
75func knownOptionNames(command string) (map[string]struct{}, map[string]struct{}) {
76	long := make(map[string]struct{})
77	alias := make(map[string]struct{})
78
79	addOptions := func(opts []Option) {
80		for _, opt := range opts {
81			if opt.Name != "" {
82				long[opt.Name] = struct{}{}
83			}
84			if opt.Alias != "" {
85				alias[opt.Alias] = struct{}{}
86			}
87		}
88	}
89
90	if global, ok := Commands["global"]; ok {
91		addOptions(global.Options)
92	}
93	if commandCfg, ok := Commands[command]; ok {
94		addOptions(commandCfg.Options)
95	}
96
97	return long, alias
98}