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}