Browse Source

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>
master
elcore 5 years ago
committed by GitHub
parent
commit
62c9f2cf3e
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      cmd/commandfuncs.go
  2. 6
      cmd/commands.go
  3. 68
      cmd/main.go

9
cmd/commandfuncs.go

@ -151,11 +151,20 @@ func cmdRun(fl Flags) (int, error) {
runCmdConfigFlag := fl.String("config") runCmdConfigFlag := fl.String("config")
runCmdConfigAdapterFlag := fl.String("adapter") runCmdConfigAdapterFlag := fl.String("adapter")
runCmdResumeFlag := fl.Bool("resume") runCmdResumeFlag := fl.Bool("resume")
runCmdLoadEnvfileFlag := fl.String("envfile")
runCmdPrintEnvFlag := fl.Bool("environ") runCmdPrintEnvFlag := fl.Bool("environ")
runCmdWatchFlag := fl.Bool("watch") runCmdWatchFlag := fl.Bool("watch")
runCmdPidfileFlag := fl.String("pidfile") runCmdPidfileFlag := fl.String("pidfile")
runCmdPingbackFlag := fl.String("pingback") runCmdPingbackFlag := fl.String("pingback")
// load all additional envs as soon as possible
if runCmdLoadEnvfileFlag != "" {
if err := loadEnvFromFile(runCmdLoadEnvfileFlag); err != nil {
return caddy.ExitCodeFailedStartup,
fmt.Errorf("loading additional environment variables: %v", err)
}
}
// if we are supposed to print the environment, do that first // if we are supposed to print the environment, do that first
if runCmdPrintEnvFlag { if runCmdPrintEnvFlag {
printEnvironment() printEnvironment()

6
cmd/commands.go

@ -96,7 +96,7 @@ using 'caddy run' instead to keep it in the foreground.`,
RegisterCommand(Command{ RegisterCommand(Command{
Name: "run", Name: "run",
Func: cmdRun, Func: cmdRun,
Usage: "[--config <path> [--adapter <name>]] [--environ] [--resume] [--watch] [--pidfile <fil>]", Usage: "[--config <path> [--adapter <name>]] [--envfile <path>] [--environ] [--resume] [--watch] [--pidfile <fil>]",
Short: `Starts the Caddy process and blocks indefinitely`, Short: `Starts the Caddy process and blocks indefinitely`,
Long: ` Long: `
Starts the Caddy process, optionally bootstrapped with an initial config file, 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
that file will be loaded and used to configure Caddy, even without any command that file will be loaded and used to configure Caddy, even without any command
line flags. line flags.
If --envfile is specified, an environment file with environment variables in
the KEY=VALUE format will be loaded into the Caddy process.
If --environ is specified, the environment as seen by the Caddy process will If --environ is specified, the environment as seen by the Caddy process will
be printed before starting. This is the same as the environ command but does be printed before starting. This is the same as the environ command but does
not quit after printing, and can be useful for troubleshooting. not quit after printing, and can be useful for troubleshooting.
@ -130,6 +133,7 @@ development environment.`,
fs := flag.NewFlagSet("run", flag.ExitOnError) fs := flag.NewFlagSet("run", flag.ExitOnError)
fs.String("config", "", "Configuration file") fs.String("config", "", "Configuration file")
fs.String("adapter", "", "Name of config adapter to apply") fs.String("adapter", "", "Name of config adapter to apply")
fs.String("envfile", "", "Environment file to load")
fs.Bool("environ", false, "Print environment") fs.Bool("environ", false, "Print environment")
fs.Bool("resume", false, "Use saved config, if any (and prefer over --config file)") fs.Bool("resume", false, "Use saved config, if any (and prefer over --config file)")
fs.Bool("watch", false, "Watch config file for changes and reload it automatically") fs.Bool("watch", false, "Watch config file for changes and reload it automatically")

68
cmd/main.go

@ -15,6 +15,7 @@
package caddycmd package caddycmd
import ( import (
"bufio"
"bytes" "bytes"
"flag" "flag"
"fmt" "fmt"
@ -339,6 +340,73 @@ func flagHelp(fs *flag.FlagSet) string {
return buf.String() return buf.String()
} }
func loadEnvFromFile(envFile string) error {
file, err := os.Open(envFile)
if err != nil {
return fmt.Errorf("reading environment file: %v", err)
}
defer file.Close()
envMap, err := parseEnvFile(file)
if err != nil {
return fmt.Errorf("parsing environment file: %v", err)
}
for k, v := range envMap {
if err := os.Setenv(k, v); err != nil {
return fmt.Errorf("setting environment variables: %v", err)
}
}
return nil
}
func parseEnvFile(envInput io.Reader) (map[string]string, error) {
envMap := make(map[string]string)
scanner := bufio.NewScanner(envInput)
var line string
lineNumber := 0
for scanner.Scan() {
line = strings.TrimSpace(scanner.Text())
lineNumber++
// skip lines starting with comment
if strings.HasPrefix(line, "#") {
continue
}
// skip empty line
if len(line) == 0 {
continue
}
fields := strings.SplitN(line, "=", 2)
if len(fields) != 2 {
return nil, fmt.Errorf("can't parse line %d; line should be in KEY=VALUE format", lineNumber)
}
if strings.Contains(fields[0], " ") {
return nil, fmt.Errorf("bad key on line %d: contains whitespace", lineNumber)
}
key := fields[0]
val := fields[1]
if key == "" {
return nil, fmt.Errorf("missing or empty key on line %d", lineNumber)
}
envMap[key] = val
}
if err := scanner.Err(); err != nil {
return nil, err
}
return envMap, nil
}
func printEnvironment() { func printEnvironment() {
fmt.Printf("caddy.HomeDir=%s\n", caddy.HomeDir()) fmt.Printf("caddy.HomeDir=%s\n", caddy.HomeDir())
fmt.Printf("caddy.AppDataDir=%s\n", caddy.AppDataDir()) fmt.Printf("caddy.AppDataDir=%s\n", caddy.AppDataDir())

Loading…
Cancel
Save