Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 14, 05:15 UTC
cmd: Add --envfile flag to run command (#3278)
* run: Add the possibility to load an env file * run: change envfile flag var * run: do not ignore err values * Apply suggestions from code review Co-authored-by: Matt Holt <mholt@users.noreply.github.com> Co-authored-by: Matt Holt <mholt@users.noreply.github.com>
elcore committed
May 15, 2020 at 23:49 UTC
62c9f2cf3e86f8aaea7a1583f09adb6b8007cfe6
3 files changed
+82
-1
cmd/commandfuncs.go
+9
@@ -151,11 +151,20 @@ func cmdRun(fl Flags) (int, error) {
151
runCmdConfigFlag := fl.String("config")
152
runCmdConfigAdapterFlag := fl.String("adapter")
153
runCmdResumeFlag := fl.Bool("resume")
154
+ runCmdLoadEnvfileFlag := fl.String("envfile")
155
runCmdPrintEnvFlag := fl.Bool("environ")
156
runCmdWatchFlag := fl.Bool("watch")
157
runCmdPidfileFlag := fl.String("pidfile")
158
runCmdPingbackFlag := fl.String("pingback")
159
160
+ // load all additional envs as soon as possible
161
+ if runCmdLoadEnvfileFlag != "" {
162
+ if err := loadEnvFromFile(runCmdLoadEnvfileFlag); err != nil {
163
+ return caddy.ExitCodeFailedStartup,
164
+ fmt.Errorf("loading additional environment variables: %v", err)
165
+ }
166
+ }
167
+
168
// if we are supposed to print the environment, do that first
169
if runCmdPrintEnvFlag {
170
printEnvironment()
cmd/commands.go
+5
-1
@@ -96,7 +96,7 @@ using 'caddy run' instead to keep it in the foreground.`,
96
RegisterCommand(Command{
97
Name: "run",
98
Func: cmdRun,
99
- Usage: "[--config <path> [--adapter <name>]] [--environ] [--resume] [--watch] [--pidfile <fil>]",
99
+ Usage: "[--config <path> [--adapter <name>]] [--envfile <path>] [--environ] [--resume] [--watch] [--pidfile <fil>]",
100
Short: `Starts the Caddy process and blocks indefinitely`,
101
Long: `
102
Starts the Caddy process, optionally bootstrapped with an initial config file,
@@ -116,6 +116,9 @@ As a special case, if the current working directory has a file called
116
that file will be loaded and used to configure Caddy, even without any command
117
line flags.
118
119
+If --envfile is specified, an environment file with environment variables in
120
+the KEY=VALUE format will be loaded into the Caddy process.
121
+
122
If --environ is specified, the environment as seen by the Caddy process will
123
be printed before starting. This is the same as the environ command but does
124
not quit after printing, and can be useful for troubleshooting.
@@ -130,6 +133,7 @@ development environment.`,
133
fs := flag.NewFlagSet("run", flag.ExitOnError)
134
fs.String("config", "", "Configuration file")
135
fs.String("adapter", "", "Name of config adapter to apply")
136
+ fs.String("envfile", "", "Environment file to load")
137
fs.Bool("environ", false, "Print environment")
138
fs.Bool("resume", false, "Use saved config, if any (and prefer over --config file)")
139
fs.Bool("watch", false, "Watch config file for changes and reload it automatically")
cmd/main.go
+68
@@ -15,6 +15,7 @@
15
package caddycmd
16
17
import (
18
+ "bufio"
19
"bytes"
20
"flag"
21
"fmt"
@@ -339,6 +340,73 @@ func flagHelp(fs *flag.FlagSet) string {
340
return buf.String()
341
}
342
343
+func loadEnvFromFile(envFile string) error {
344
+ file, err := os.Open(envFile)
345
+ if err != nil {
346
+ return fmt.Errorf("reading environment file: %v", err)
347
+ }
348
+ defer file.Close()
349
+
350
+ envMap, err := parseEnvFile(file)
351
+ if err != nil {
352
+ return fmt.Errorf("parsing environment file: %v", err)
353
+ }
354
+
355
+ for k, v := range envMap {
356
+ if err := os.Setenv(k, v); err != nil {
357
+ return fmt.Errorf("setting environment variables: %v", err)
358
+ }
359
+ }
360
+
361
+ return nil
362
+}
363
+
364
+func parseEnvFile(envInput io.Reader) (map[string]string, error) {
365
+ envMap := make(map[string]string)
366
+
367
+ scanner := bufio.NewScanner(envInput)
368
+ var line string
369
+ lineNumber := 0
370
+
371
+ for scanner.Scan() {
372
+ line = strings.TrimSpace(scanner.Text())
373
+ lineNumber++
374
+
375
+ // skip lines starting with comment
376
+ if strings.HasPrefix(line, "#") {
377
+ continue
378
+ }
379
+
380
+ // skip empty line
381
+ if len(line) == 0 {
382
+ continue
383
+ }
384
+
385
+ fields := strings.SplitN(line, "=", 2)
386
+ if len(fields) != 2 {
387
+ return nil, fmt.Errorf("can't parse line %d; line should be in KEY=VALUE format", lineNumber)
388
+ }
389
+
390
+ if strings.Contains(fields[0], " ") {
391
+ return nil, fmt.Errorf("bad key on line %d: contains whitespace", lineNumber)
392
+ }
393
+
394
+ key := fields[0]
395
+ val := fields[1]
396
+
397
+ if key == "" {
398
+ return nil, fmt.Errorf("missing or empty key on line %d", lineNumber)
399
+ }
400
+ envMap[key] = val
401
+ }
402
+
403
+ if err := scanner.Err(); err != nil {
404
+ return nil, err
405
+ }
406
+
407
+ return envMap, nil
408
+}
409
+
410
func printEnvironment() {
411
fmt.Printf("caddy.HomeDir=%s\n", caddy.HomeDir())
412
fmt.Printf("caddy.AppDataDir=%s\n", caddy.AppDataDir())