package main import ( "flag" "fmt" "log" "os" "os/exec" "strings" ) var commandEnvDescription = "load environment variable from .env file" func commandEnv(args []string) { var flagSet = flag.NewFlagSet("env", flag.ContinueOnError) envFilePath := flagSet.String("file", ".env", "the file contains environment variables to parse") printToScreen := flagSet.Bool("print", false, "wethear or not print to screen") _ = printToScreen printWithExport := flagSet.Bool("export", false, "wethear or not add `export` prefix to each variable when printing") flagSet.Parse(args[1:]) _, err := parseEnvFileAndSetEnv(*envFilePath, *printToScreen, *printWithExport) if err != nil { fmt.Printf("%v", err) os.Exit(2) } if len(flagSet.Args()) > 0 { cmd := exec.Command(flagSet.Args()[0], flagSet.Args()[1:]...) var out strings.Builder cmd.Stdout = &out err = cmd.Run() if err != nil { log.Fatal(err) } fmt.Printf(out.String()) } } func parseEnvFileAndSetEnv(filePath string, printToScreen, printWithExport bool) (string, error) { raw, err := os.ReadFile(filePath) if err != nil { return "", fmt.Errorf("read from %v has error: %w", filePath, err) } rawLines := strings.Split(string(raw), "\n") for i, line := range rawLines { trimedLine := strings.TrimSpace(line) if strings.HasPrefix(trimedLine, "#") { continue } if trimedLine == "" { continue } parts := strings.Split(trimedLine, "=") if len(parts) != 2 { return "", fmt.Errorf("line %v is malformed: `%v`", i+1, trimedLine) } if strings.TrimSpace(parts[0]) != parts[0] { return "", fmt.Errorf("line %v is malformed: between variable name and `=` can't has any space", i+1) } if strings.TrimSpace(parts[1]) != parts[1] { return "", fmt.Errorf("line %v is malformed: between `=` and value can't has any space", i+1) } os.Setenv(parts[0], parts[1]) if printToScreen { s := fmt.Sprintf("%v=%v\n", parts[0], parts[1]) if printWithExport { s = fmt.Sprintf("export %v", s) } fmt.Print(s) } } return "", nil }