Skip to content

Commit b651adc

Browse files
authored
feat!: use godotenv and --unescape flag (#2)
1 parent c9afdcb commit b651adc

File tree

13 files changed

+115
-107
lines changed

13 files changed

+115
-107
lines changed

README.md

+30-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11

2-
# ennbu
2+
# ennbu
33

4+
![ennbu logo](./docs/ennbu-logo.png)
45

5-
<img src="./docs/ennbu-logo.png" alt="logo" />
6-
7-
**.env utility CLI**
6+
## .env utility CLI
87

98
`ennbu` is a command-line interface (CLI) tool for managing .env files in your projects, written in Go. It allows you to easily set, replace, list, and get values of keys within your .env files.
109

@@ -60,7 +59,7 @@ jobs:
6059
- name: go mod download
6160
run: go mod download
6261
- name: replace APP_ENV
63-
uses: u-yas/[email protected].1
62+
uses: u-yas/[email protected].4
6463
with:
6564
envPath: .env
6665
commands: |
@@ -78,37 +77,58 @@ jobs:
7877
To get the value of a specific key in a .env file, use the `get` command:
7978

8079
```bash
81-
ennbu get -k KEY_NAME -e .env
80+
ennbu get KEY_NAME -f .env
81+
```
82+
83+
`--unescape` or `-u`
84+
85+
```text
86+
# .env
87+
KEY_NAME="aa\nbbb\n\tccc"
88+
```
89+
90+
```bash
91+
# normally
92+
ennbu get KEY_NAME
93+
# aa\nbbb\n\tccc
94+
95+
# unescape
96+
ennbu get KEY_NAME -u
97+
#aa
98+
#bb
99+
# cc
82100
```
83101

84102
#### List
85103

86104
To list all key-value pairs in a .env file, use the `list` command:
87105

88106
```bash
89-
ennbu list -e .env
107+
ennbu list -f .env
90108
```
91109

92110
To list the key-value pairs in JSON format, use the `--json` flag:
93111

94112
```bash
95-
ennbu list --json -e .env
113+
ennbu list --json -f .env
96114
```
97115

116+
![ennbu list --json output](./docs/list-json.png)
117+
98118
#### Set
99119

100120
To set a new value for a key in a .env file, use the `set` command:
101121

102122
```bash
103-
ennbu set -e .env -k KEY_NAME VALUE
123+
ennbu set -f .env -k KEY_NAME VALUE
104124
```
105125

106126
#### Replace
107127

108128
To replace a value for an existing key in a .env file, use the `replace` command:
109129

110130
```bash
111-
echo NEW_VALUE | ennbu replace -e .env -k KEY_NAME
131+
echo NEW_VALUE | ennbu replace -f .env -k KEY_NAME
112132
```
113133

114134
## Contributing

cmd/get.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ var getCmd = &cobra.Command{
1515
Use: "get",
1616
Short: "Get the value of a specified key in .env file",
1717
Example: heredoc.Doc(`
18-
$ ennbu get KEY
19-
$ ennbu get -e .env.development
18+
$ ennbu get KEY
19+
$ ennbu get -e .env.development
2020
`),
2121
RunE: get.Run,
2222
}
2323

2424
func init() {
2525
_ = getCmd.MarkFlagRequired(flags.FlagKey)
26-
26+
getCmd.Flags().BoolP(get.FlagUnescape, "u", false, "Unescape special characters")
2727
rootCmd.AddCommand(getCmd)
2828
}

docs/list-json.png

46.5 KB
Loading

env/value.go env/escape.go

File renamed without changes.

env/read.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package env
2+
3+
import (
4+
"github.com/joho/godotenv"
5+
)
6+
7+
func ReadEnv(envFilePath string) (map[string]string, error) {
8+
env, err := godotenv.Read(envFilePath)
9+
if err != nil {
10+
return nil, err
11+
}
12+
13+
return env, nil
14+
}

env/write.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package env
2+
3+
import (
4+
"github.com/joho/godotenv"
5+
)
6+
7+
func WriteEnv(content map[string]string, envFilePath string) error {
8+
err := godotenv.Write(content, envFilePath)
9+
if err != nil {
10+
return err
11+
}
12+
13+
return nil
14+
}

get/flag.go

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package get
2+
3+
const (
4+
FlagUnescape string = "unescape"
5+
)

get/run.go

+13-23
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,37 @@
11
package get
22

33
import (
4-
"bufio"
54
"fmt"
6-
"os"
7-
"path/filepath"
5+
"strconv"
86
"strings"
97

108
"github.com/spf13/cobra"
9+
"github.com/u-yas/ennbu/env"
1110
"github.com/u-yas/ennbu/flags"
1211
)
1312

1413
func Run(cmd *cobra.Command, args []string) error {
1514
key := args[0]
1615
envFilePath, _ := cmd.Flags().GetString(flags.FlagEnvFile)
17-
18-
envFile, err := os.Open(envFilePath)
19-
envFileName := filepath.Base(envFilePath)
16+
unescapeFlag, _ := cmd.Flags().GetBool(FlagUnescape)
17+
e, err := env.ReadEnv(envFilePath)
2018
if err != nil {
21-
return fmt.Errorf("error opening %s file: %w", envFileName, err)
19+
return fmt.Errorf("failed to read env file: %w", err)
2220
}
23-
defer envFile.Close()
24-
25-
scanner := bufio.NewScanner(envFile)
26-
found := false
2721

28-
for scanner.Scan() {
29-
line := scanner.Text()
30-
if strings.HasPrefix(line, key+"=") {
31-
value := strings.TrimPrefix(line, key+"=")
32-
fmt.Println(value)
33-
found = true
34-
break
35-
}
22+
if _, ok := e[key]; !ok {
23+
return fmt.Errorf("key not found: %s", key)
3624
}
3725

38-
if err := scanner.Err(); err != nil {
39-
return fmt.Errorf("error reading %s file: %w", envFileName, err)
26+
value := e[key]
27+
if !unescapeFlag {
28+
value = strconv.Quote(value)
4029
}
4130

42-
if !found {
43-
return fmt.Errorf("key not found in %s file", envFileName)
31+
if strings.HasPrefix(value, "\"") && strings.HasSuffix(value, "\"") {
32+
value = strings.TrimSuffix(strings.TrimPrefix(value, "\""), "\"")
4433
}
4534

35+
fmt.Println(value)
4636
return nil
4737
}

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ require (
1010

1111
require (
1212
github.com/inconshreveable/mousetrap v1.0.1 // indirect
13+
github.com/joho/godotenv v1.5.1 // indirect
1314
github.com/spf13/pflag v1.0.5 // indirect
1415
)

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ github.com/MakeNowJust/heredoc/v2 v2.0.1/go.mod h1:6/2Abh5s+hc3g9nbWLe9ObDIOhaRr
33
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
44
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
55
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
6+
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
7+
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
68
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
79
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
810
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=

list/run.go

+19-21
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,48 @@
11
package list
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
6-
"os"
7-
"path/filepath"
8-
"strings"
97

8+
"github.com/joho/godotenv"
109
"github.com/spf13/cobra"
1110
"github.com/tidwall/pretty"
11+
"github.com/u-yas/ennbu/env"
1212
"github.com/u-yas/ennbu/flags"
1313
)
1414

1515
func Run(cmd *cobra.Command, args []string) error {
1616
envFilePath, _ := cmd.Flags().GetString(flags.FlagEnvFile)
1717
jsonOutput, _ := cmd.Flags().GetBool(FlagJson)
1818

19-
envfileName := filepath.Base(envFilePath)
20-
envContent, err := os.ReadFile(envFilePath)
19+
e, err := env.ReadEnv(envFilePath)
2120
if err != nil {
22-
return fmt.Errorf("error reading %s file: %w", envfileName, err)
21+
return fmt.Errorf("failed to read env file: %w", err)
2322
}
2423

25-
lines := strings.Split(string(envContent), "\n")
26-
envMap := make(map[string]string)
24+
if jsonOutput {
25+
var buffer bytes.Buffer
26+
enc := json.NewEncoder(&buffer)
27+
enc.SetEscapeHTML(false)
28+
enc.SetIndent("", " ")
2729

28-
for _, line := range lines {
29-
if strings.TrimSpace(line) == "" || strings.HasPrefix(line, "#") {
30-
continue
31-
}
32-
kv := strings.SplitN(line, "=", 2)
33-
if len(kv) == 2 {
34-
envMap[kv[0]] = kv[1]
30+
if err := enc.Encode(e); err != nil {
31+
return fmt.Errorf("error generating JSON output: %w", err)
3532
}
36-
}
3733

38-
if jsonOutput {
39-
jsonData, err := json.MarshalIndent(envMap, "", " ")
34+
jVal := buffer.Bytes()
4035
if err != nil {
4136
return fmt.Errorf("error generating JSON output: %w", err)
4237
}
43-
fmt.Println(string(pretty.Color(jsonData, nil)))
38+
39+
fmt.Println(string(pretty.Color(jVal, nil)))
4440
} else {
45-
for key, value := range envMap {
46-
fmt.Printf("%s=%s\n", key, value)
41+
rawEnv, err := godotenv.Marshal(e)
42+
if err != nil {
43+
return fmt.Errorf("error generating raw output: %w", err)
4744
}
45+
fmt.Println(rawEnv)
4846
}
4947

5048
return nil

replace/run.go

+8-25
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ package replace
22

33
import (
44
"fmt"
5-
"os"
6-
"path/filepath"
7-
"strings"
85

96
"github.com/spf13/cobra"
107
"github.com/u-yas/ennbu/env"
@@ -21,36 +18,22 @@ func Run(cmd *cobra.Command, args []string) error {
2118
value = env.EscapeSpecialChars(value)
2219
}
2320

24-
// Check if the value contains newline characters and wrap it with double quotes if necessary
25-
if strings.Contains(value, "\n") {
26-
value = fmt.Sprintf("\"%s\"", value)
27-
}
21+
e, err := env.ReadEnv(envFilePath)
2822

29-
fileName := filepath.Base(envFilePath)
30-
envContent, err := os.ReadFile(envFilePath)
3123
if err != nil {
32-
return fmt.Errorf("error reading %s: %w", fileName, err)
24+
return fmt.Errorf("failed to read env file: %w", err)
3325
}
3426

35-
lines := strings.Split(string(envContent), "\n")
36-
found := false
37-
38-
for i, line := range lines {
39-
if strings.HasPrefix(line, key+"=") {
40-
lines[i] = key + "=" + value
41-
found = true
42-
break
43-
}
27+
// replace cmd should not add new key
28+
if _, ok := e[key]; !ok {
29+
return fmt.Errorf("key not found: %s", key)
4430
}
4531

46-
if !found {
47-
return fmt.Errorf("key %s not found in %s", key, fileName)
48-
}
32+
e[key] = value
4933

50-
newContent := strings.Join(lines, "\n")
51-
err = os.WriteFile(envFilePath, []byte(newContent), 0644)
34+
err = env.WriteEnv(e, envFilePath)
5235
if err != nil {
53-
return fmt.Errorf("error writing %s: %w", fileName, err)
36+
return fmt.Errorf("failed to write env file: %w", err)
5437
}
5538
return nil
5639
}

set/run.go

+6-25
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package set
22

33
import (
44
"fmt"
5-
"os"
6-
"strings"
75

86
"github.com/spf13/cobra"
97
"github.com/u-yas/ennbu/env"
@@ -19,35 +17,18 @@ func Run(cmd *cobra.Command, args []string) error {
1917
if escapeFlag {
2018
value = env.EscapeSpecialChars(value)
2119
}
22-
// Check if the value contains newline characters and wrap it with double quotes if necessary
23-
if strings.Contains(value, "\n") {
24-
value = fmt.Sprintf("\"%s\"", value)
25-
}
26-
27-
envContent, err := os.ReadFile(envFilePath)
28-
if err != nil {
29-
return fmt.Errorf("error reading %s: %w", envFilePath, err)
30-
}
3120

32-
lines := strings.Split(string(envContent), "\n")
33-
found := false
21+
e, err := env.ReadEnv(envFilePath)
3422

35-
for i, line := range lines {
36-
if strings.HasPrefix(line, key+"=") {
37-
lines[i] = key + "=" + value
38-
found = true
39-
break
40-
}
23+
if err != nil {
24+
return fmt.Errorf("failed to read env file: %w", err)
4125
}
4226

43-
if !found {
44-
lines = append(lines, key+"="+value)
45-
}
27+
e[key] = value
4628

47-
newContent := strings.Join(lines, "\n")
48-
err = os.WriteFile(envFilePath, []byte(newContent), 0644)
29+
err = env.WriteEnv(e, envFilePath)
4930
if err != nil {
50-
return fmt.Errorf("error writing %s: %w", envFilePath, err)
31+
return fmt.Errorf("failed to write env file: %w", err)
5132
}
5233

5334
return nil

0 commit comments

Comments
 (0)