-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdoc.go
More file actions
141 lines (141 loc) · 5.89 KB
/
Copy pathdoc.go
File metadata and controls
141 lines (141 loc) · 5.89 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Package env bridges .env files, the process environment and Go structures.
//
// It does three things:
//
// 1. Loads .env files into the process environment (a small Load/Overload
// API: Load, Overload, LoadRaw, OverloadRaw, LoadReader, MustLoad).
// 2. Maps the environment to and from Go structs (an encoding/json-style API:
// Unmarshal, Marshal and their Map/File/Reader/Writer/String variants) with
// struct tags, defaults, validation and rich type support.
// 3. Parses .env data into plain maps without side effects (Read, Parse, All,
// ReadSeq).
//
// # Loading
//
// Load and friends read one or more .env files (variadic; with no argument
// they default to ".env") into the process environment. Load keeps existing
// keys; Overload overwrites them. The Raw variants do not expand ${VAR}/$VAR.
// MustLoad is like Load but panics on error (handy in init or main).
//
// if err := env.Load(".env"); err != nil {
// log.Fatal(err)
// }
//
// # Decoding into a struct
//
// Unmarshal reads the process environment into a struct; UnmarshalMap,
// UnmarshalFile, UnmarshalReader and UnmarshalString read a map, a file, an
// io.Reader or a string directly without touching the environment.
//
// type Config struct {
// Host string `env:"HOST"`
// Port int `env:"PORT" def:"80"`
// Hosts []string `env:"ALLOWED_HOSTS" sep:":"`
// Timeout time.Duration `env:"TIMEOUT" def:"30s"`
// }
//
// var cfg Config
// if err := env.Unmarshal(&cfg); err != nil {
// log.Fatal(err)
// }
//
// # Encoding a struct
//
// Marshal writes a struct into the environment; MarshalMap, MarshalFile,
// MarshalWriter and MarshalString produce a map, a file, an io.Writer or a
// string without changing the environment.
//
// The File/Reader/Writer/String encode and decode functions each have a Raw
// variant (e.g. UnmarshalFileRaw, MarshalStringRaw) that skips ${VAR}/$VAR
// expansion, so any value round-trips verbatim.
//
// # Options
//
// Options set call-level defaults that a per-field tag can override
// (precedence: field tag > option > built-in default):
//
// - WithPrefix sets a key namespace; levels are joined with "_", so
// WithPrefix("APP") maps PORT to APP_PORT.
// - WithSeparator sets the default list separator.
// - WithTimeLayout sets the default time.Time layout.
// - WithFileMode sets the file permissions used by MarshalFile.
// - WithParser/WithEncoder register a decoder/encoder for a custom type that
// does not implement encoding.TextUnmarshaler/TextMarshaler.
// - WithRequiredAll makes every leaf field required during decoding.
//
// # Struct tags
//
// - env: the key name; "-" ignores the field; an inline "required" flag
// (env:"KEY,required") makes it mandatory, and an inline "absolute" flag
// (env:"DATABASE_URL,absolute") names the variable in full, ignoring the
// prefix its enclosing structs would otherwise contribute - which is how
// a nested struct reaches a name the deployment already fixed.
// - def: a default value used when the key is absent.
// - sep: the separator for slice/array values (default: a comma).
// - layout: the layout for time.Time fields (default: RFC3339).
//
// # Supported types
//
// All sized int/uint, float32/64, string, bool, url.URL, time.Duration,
// time.Time, any type implementing encoding.TextMarshaler/TextUnmarshaler
// (e.g. net.IP, custom enums), nested structs, pointers and slices/arrays of
// these.
//
// A pointer field is optional: it is decoded as nil when its key is absent and
// omitted on encode, so optional values round-trip (see DOC.md for details).
//
// # Custom marshaling
//
// Types implementing Marshaler or Unmarshaler take full control, mirroring
// encoding/json: MarshalEnv returns a map of key/value pairs and UnmarshalEnv
// receives the resolved source map.
//
// # The .env format
//
// The parser follows the de-facto .env format: single/double/backtick
// quotes, escape sequences in double quotes (\n, \t, \r, \\, \"), multi-line
// quoted values, full-line and inline comments, the optional export prefix and
// ${VAR}/$VAR expansion (in unquoted and double-quoted values only).
//
// # Concurrency
//
// Loading and marshaling act on the global process environment. Beyond the
// guarantees of the standard os package there is no extra synchronization, so
// callers should not load and read the same keys concurrently. The map-, file-
// and reader/writer-based variants (Read, Parse, All, UnmarshalMap, MarshalMap,
// UnmarshalFile, MarshalFile, UnmarshalReader, MarshalWriter) have no global
// side effects.
//
// # Validating what was decoded
//
// The canonical shape of a config loader is three steps, and the third is
// yours:
//
// func Load(files ...string) (*Config, error) {
// _ = env.Load(files...)
// var c Config
// if err := env.Unmarshal(&c); err != nil {
// return nil, err
// }
// if err := c.Validate(); err != nil {
// return nil, err
// }
// return &c, nil
// }
//
// The "required" flag covers presence, which is the part a tag can express.
// Rules that involve more than one field cannot be: that two secrets must
// differ, that a limit must sit below a ceiling, that a key must be long
// enough to sign with. Those live in a Validate method the application writes
// and calls, and calling it at startup is what turns a misconfiguration into a
// process that refuses to start rather than one that fails on the first
// request that happens to need the value.
//
// Unmarshal deliberately does not call such a method for you, even when the
// target has one. The footgun is symmetrical - forgetting to write the method
// is exactly as easy as forgetting to call it - and an implicit call would
// have a decoder invoking application logic, which is a surprising thing for a
// decoder to do and a hard thing to find when it misbehaves.
//
// See DOC.md (English) and DOC.UK.md (Ukrainian) for the full reference.
package env