-
Notifications
You must be signed in to change notification settings - Fork 33
/
flags.go
126 lines (113 loc) · 3.76 KB
/
flags.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"fmt"
"log/slog"
"math"
"os"
"strings"
"github.com/dalibo/ldap2pg/internal"
"github.com/knadh/koanf/providers/env"
"github.com/knadh/koanf/providers/posflag"
"github.com/knadh/koanf/v2"
"github.com/lithammer/dedent"
"github.com/mattn/go-isatty"
"github.com/spf13/pflag"
)
var k = koanf.New(".")
func init() {
pflag.Usage = func() {
fmt.Fprintf(os.Stderr, "usage: %s [OPTIONS] [dbname]\n\n", os.Args[0])
pflag.PrintDefaults()
os.Stderr.Write([]byte(dedent.Dedent(`
Optional argument dbname is alternatively the database name or a conninfo string or an URI.
See man psql(1) for more information.
By default, ldap2pg runs in dry mode.
ldap2pg requires a configuration file to describe LDAP searches and mappings.
See https://ldap2pg.readthedocs.io/en/latest/ for further details.
`)))
}
}
func loadEnvAndFlags() {
// env.Provider does not return error.
_ = k.Load(env.Provider("LDAP2PG_", k.Delim(), func(s string) string {
slog.Debug("Reading env.", "var", s)
s = strings.TrimPrefix(s, "LDAP2PG_")
s = strings.ToLower(s)
return s
}), nil)
// Actually, we don't need to use k.* to set default from environment
// because we pass k to posflag.ProviderWithFlag so that posflag provider
// checks whether parameter is set in environment.
pflag.Bool("check", false, "Check mode: exits with 1 if Postgres instance is unsynchronized.")
pflag.Bool("color", defaultColor(), "Force color output.")
pflag.StringP("config", "c", k.String("config"), "Path to YAML configuration file. Use - for stdin.")
pflag.StringP("directory", "C", "", "Path to directory containing configuration files.")
pflag.BoolP("real", "R", k.Bool("real"), "Real mode. Apply changes to Postgres instance.")
pflag.BoolP("skip-privileges", "P", k.Bool("skipprivileges"), "Turn off privilege synchronisation.")
pflag.BoolP("help", "?", false, "Show this help message and exit.")
pflag.BoolP("version", "V", false, "Show version and exit.")
pflag.CountP("quiet", "q", "Decrease log verbosity.")
pflag.CountP("verbose", "v", "Increase log verbosity.")
pflag.Parse()
// posflag.Provider does not return error.
_ = k.Load(posflag.ProviderWithFlag(pflag.CommandLine, ".", k, func(f *pflag.Flag) (string, interface{}) {
// remove hyphen from e.g. skip-privileges.
key := strings.ReplaceAll(f.Name, "-", "")
return key, posflag.FlagVal(pflag.CommandLine, f)
}), nil)
}
func defaultColor() bool {
plain := os.Getenv("NO_COLOR")
if plain != "" {
return false
}
return isatty.IsTerminal(os.Stderr.Fd())
}
// Controller holds flags/env values controlling the execution of ldap2pg.
type Controller struct {
Check bool
Color bool
Config string
Real bool
SkipPrivileges bool
Quiet int
Verbose int
Verbosity string
LogLevel slog.Level
Directory string
Dsn string
}
var levels = []slog.Level{
slog.LevelDebug,
slog.LevelInfo,
internal.LevelChange,
slog.LevelWarn,
slog.LevelError,
}
func unmarshalController() (controller Controller, err error) {
err = k.Unmarshal("", &controller)
verbosity := k.String("verbosity")
var level slog.LevelVar
switch verbosity {
case "":
// Default log level is INFO, which index is 1.
levelIndex := 1 - k.Int("verbose") + k.Int("quiet")
levelIndex = int(math.Max(0, float64(levelIndex)))
levelIndex = int(math.Min(float64(levelIndex), float64(len(levels)-1)))
controller.LogLevel = levels[levelIndex]
case "CHANGE":
controller.LogLevel = internal.LevelChange
default:
err := level.UnmarshalText([]byte(verbosity))
if err == nil {
controller.LogLevel = level.Level()
} else {
slog.Warn("Bad verbosity.", "source", "env", "value", verbosity)
}
}
args := pflag.Args()
if len(args) > 0 {
controller.Dsn = args[0]
}
return controller, err
}