@marcel91200 / caddy Mirror · read-only / commits / 62c9f2cf
Fork 0

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())