Skip to content

Commit 856c991

Browse files
committed
godotenv binary now execs on non-Windows
Using exec is better in this case as it makes the process tree simpler, and allows the child's signals to be handled by the caller. In addition the `Exec` function has been removed as it's not really great as a library function. Users should manually call the `Load` function and run `exec.Command` or `syscall.Exec` appropriately. In the future we probably want to handle signals for Windows anyway. This is based on joho/godotenv#77 and also addresses the following PRs in upstream: - joho/godotenv#119
1 parent 683ef29 commit 856c991

File tree

4 files changed

+42
-23
lines changed

4 files changed

+42
-23
lines changed

cmd/godotenv/cmd.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ import (
44
"errors"
55
"flag"
66
"fmt"
7+
"github.com/hoshsadiq/godotenv"
78
"log"
89
"os"
9-
10-
"github.com/hoshsadiq/godotenv"
1110
)
1211

1312
func main() {
@@ -56,11 +55,17 @@ Options:
5655
os.Exit(1)
5756
}
5857

58+
err = godotenv.Load(envFilenames...)
59+
if err != nil {
60+
log.Fatal(err)
61+
return
62+
}
63+
5964
// take rest of args and "exec" them
6065
cmd := args[0]
6166
cmdArgs := args[1:]
6267

63-
err = godotenv.Exec(envFilenames, cmd, cmdArgs)
68+
err = execv(cmd, cmdArgs)
6469
if err != nil {
6570
log.Fatal(err)
6671
}

cmd/godotenv/exec.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//go:build !windows
2+
//+build !windows
3+
4+
package main
5+
6+
import (
7+
"os"
8+
"os/exec"
9+
"syscall"
10+
)
11+
12+
func execv(cmd string, cmdArgs []string) error {
13+
prog, err := exec.LookPath(cmd)
14+
if err != nil {
15+
return err
16+
}
17+
args := append([]string{cmd}, cmdArgs...)
18+
19+
return syscall.Exec(prog, args, os.Environ())
20+
}

cmd/godotenv/exec_windows.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"os/exec"
6+
)
7+
8+
func execv(cmd string, cmdArgs []string) error {
9+
command := exec.Command(cmd, cmdArgs...)
10+
command.Stdin = os.Stdin
11+
command.Stdout = os.Stdout
12+
command.Stderr = os.Stderr
13+
return command.Run()
14+
}

godotenv.go

-20
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"fmt"
1919
"io"
2020
"os"
21-
"os/exec"
2221
"sort"
2322
"strconv"
2423
"strings"
@@ -124,25 +123,6 @@ func Unmarshal(str string) (envMap map[string]string, err error) {
124123
return Parse(strings.NewReader(str))
125124
}
126125

127-
// Exec loads env vars from the specified filenames (empty map falls back to default)
128-
// then executes the cmd specified.
129-
//
130-
// Simply hooks up os.Stdin/err/out to the command and calls Run()
131-
//
132-
// If you want more fine grained control over your command it's recommended
133-
// that you use `Load()` or `Read()` and the `os/exec` package yourself.
134-
func Exec(filenames []string, cmd string, cmdArgs []string) error {
135-
if err := Load(filenames...); err != nil {
136-
return err
137-
}
138-
139-
command := exec.Command(cmd, cmdArgs...)
140-
command.Stdin = os.Stdin
141-
command.Stdout = os.Stdout
142-
command.Stderr = os.Stderr
143-
return command.Run()
144-
}
145-
146126
// Write serializes the given environment and writes it to a file
147127
func Write(envMap map[string]string, filename string) error {
148128
content, err := Marshal(envMap)

0 commit comments

Comments
 (0)