package main import ( "bufio" "flag" "fmt" "io" "os" "os/exec" "regexp" ) var ( EnvFilePath = flag.String("f", ".env", "environment file") EnvVarRegex = regexp.MustCompile(`^(.*?)=(.*?)$`) EnvCommentRegex = regexp.MustCompile(`^[ \t]*#.*?$`) ) func main() { flag.Parse() envFile, err := os.Open(*EnvFilePath) if err != nil { fmt.Fprintf(os.Stderr, "could not open file '%s': %s\n", *EnvFilePath, err.(*os.PathError).Err) return } defer envFile.Close() envVars := parseEnvFile(envFile) args := flag.Args() newEnv := append(os.Environ(), envVars...) if len(args) == 0 { for _, envVar := range newEnv { fmt.Println(envVar) } return } cmd := exec.Command(args[0], args[1:]...) cmd.Env = newEnv cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { if exitErr, ok := err.(*exec.ExitError); ok { os.Exit(exitErr.ExitCode()) return } else { panic(err) } } } func parseEnvFile(r io.Reader) []string { env := make([]string, 0) s := bufio.NewScanner(r) l := 0 for s.Scan() { l++ matches := EnvVarRegex.FindStringSubmatch(s.Text()) if len(matches) != 0 { key, value := matches[1], os.ExpandEnv(matches[2]) env = append(env, fmt.Sprintf("%s=%s", key, value)) } else if s.Text() != "" && !EnvCommentRegex.MatchString(s.Text()) { panic(fmt.Sprintf("invalid env syntax on line %d", l)) } } return env }