Skip to content

Commit 7571a94

Browse files
committed
chore: quick update fix/version at 2025-09-24 23:16:29
1 parent c9256fc commit 7571a94

File tree

7 files changed

+178
-81
lines changed

7 files changed

+178
-81
lines changed

config/envs.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type EnvSpec struct {
2020

2121
func initEnv(envMap EnvSpecMap) {
2222
for name, cfg := range envMap {
23+
cfg.Name = name
24+
2325
envData := strings.TrimSpace(strutil.FirstNotEmpty(env.Get(name), cfg.Value, cfg.Default))
2426
if cfg.Required && envData == "" {
2527
panic("env " + cfg.Name + " is required")

env/env.go

Lines changed: 63 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,25 @@ import (
99

1010
"github.com/a8m/envsubst"
1111
"github.com/joho/godotenv"
12+
"github.com/rs/zerolog"
1213
"github.com/samber/lo"
1314

1415
"github.com/pubgo/funk/assert"
16+
"github.com/pubgo/funk/log/logfields"
1517
"github.com/pubgo/funk/pathutil"
1618
"github.com/pubgo/funk/v2/result"
1719
)
1820

1921
func Set(key, value string) result.Error {
20-
return result.ErrOf(os.Setenv(KeyHandler(key), value))
22+
return result.ErrOf(os.Setenv(keyHandler(key), value)).Log(func(e *zerolog.Event) {
23+
e.Str("key", key)
24+
e.Str("value", value)
25+
e.Str(logfields.Msg, "env_set_error")
26+
})
2127
}
2228

29+
func MustSet(key, value string) { Set(key, value).Must() }
30+
2331
func GetDefault(name string, defaultVal string) string {
2432
val := Get(name)
2533
return lo.If(val != "", val).Else(defaultVal)
@@ -28,29 +36,29 @@ func GetDefault(name string, defaultVal string) string {
2836
func Get(names ...string) string {
2937
var val string
3038
GetVal(&val, names...)
31-
return trim(val)
39+
return val
3240
}
3341

3442
func MustGet(names ...string) string {
3543
var val string
3644
GetVal(&val, names...)
3745
assert.If(val == "", "env not found, names=%q", names)
38-
return trim(val)
46+
return val
3947
}
4048

4149
func GetVal(val *string, names ...string) {
4250
for _, name := range names {
4351
env, ok := Lookup(name)
4452
env = trim(env)
4553
if ok && env != "" {
46-
*val = trim(env)
54+
*val = env
4755
break
4856
}
4957
}
5058
}
5159

5260
func GetBoolVal(val *bool, names ...string) {
53-
dt := trim(Get(names...))
61+
dt := Get(names...)
5462
if dt == "" {
5563
return
5664
}
@@ -65,7 +73,7 @@ func GetBoolVal(val *bool, names ...string) {
6573
}
6674

6775
func GetIntVal(val *int, names ...string) {
68-
dt := trim(Get(names...))
76+
dt := Get(names...)
6977
if dt == "" {
7078
return
7179
}
@@ -80,7 +88,7 @@ func GetIntVal(val *int, names ...string) {
8088
}
8189

8290
func GetFloatVal(val *float64, names ...string) {
83-
dt := trim(Get(names...))
91+
dt := Get(names...)
8492
if dt == "" {
8593
return
8694
}
@@ -94,37 +102,77 @@ func GetFloatVal(val *float64, names ...string) {
94102
*val = v
95103
}
96104

97-
func Lookup(key string) (string, bool) {
98-
return os.LookupEnv(Key(key))
99-
}
105+
func Lookup(key string) (string, bool) { return os.LookupEnv(keyHandler(key)) }
100106

101107
func Delete(key string) result.Error {
102-
return result.ErrOf(os.Unsetenv(Key(key)))
108+
return result.ErrOf(os.Unsetenv(keyHandler(key))).Log(func(e *zerolog.Event) {
109+
e.Str("key", key)
110+
e.Str(logfields.Msg, "env_delete_error")
111+
})
103112
}
104113

105114
func Expand(value string) result.Result[string] {
106-
return result.Wrap(envsubst.String(value))
115+
return result.Wrap(envsubst.String(value)).Log(func(e *zerolog.Event) {
116+
e.Str("value", value)
117+
e.Str(logfields.Msg, "env_expand_error")
118+
})
107119
}
108120

109121
func Map() map[string]string {
110122
data := make(map[string]string, len(os.Environ()))
111123
for _, env := range os.Environ() {
112124
envs := strings.SplitN(env, "=", 2)
113-
data[envs[0]] = envs[1]
125+
if len(envs) != 2 {
126+
continue
127+
}
128+
129+
data[keyHandler(envs[0])] = envs[1]
114130
}
115131
return data
116132
}
117133

118134
func Key(key string) string {
119-
return KeyHandler(key)
135+
return keyHandler(key)
120136
}
121137

122138
func LoadFiles(files ...string) (r result.Error) {
123139
files = lo.Filter(files, func(item string, index int) bool { return pathutil.IsExist(item) })
124-
if result.Catch(&r, godotenv.Overload(files...)) {
140+
if len(files) == 0 {
125141
return
126142
}
127143

144+
for _, file := range files {
145+
data := result.Wrap(os.ReadFile(file)).Unwrap(&r)
146+
if r.IsErr() {
147+
return
148+
}
149+
150+
dataMap := result.Wrap(godotenv.UnmarshalBytes(data)).Unwrap(&r)
151+
if r.IsErr() {
152+
return
153+
}
154+
155+
for k, v := range dataMap {
156+
if k == "" || v == "" {
157+
continue
158+
}
159+
160+
if Set(k, v).Catch(&r) {
161+
return
162+
}
163+
}
164+
}
165+
128166
loadEnv()
129167
return
130168
}
169+
170+
// Normalize a-b=>a_b, a.b=>a_b, a/b=>a_b
171+
func Normalize(key string) (string, bool) {
172+
key = trim(key)
173+
if key == "" || strings.HasPrefix(key, "_") || strings.HasPrefix(key, "=") {
174+
return key, false
175+
}
176+
177+
return keyHandler(key), true
178+
}

env/reload.go

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"os"
77
"strings"
88

9+
"github.com/pubgo/funk/assert"
910
"github.com/pubgo/funk/log/logfields"
1011
)
1112

@@ -22,41 +23,29 @@ func Init() {
2223
// 环境变量处理, key转大写, 同时把`-./`转换为`_`
2324
// a-b=>a_b, a.b=>a_b, a/b=>a_b
2425
func loadEnv() {
25-
envPrefix := getEnvPrefix()
26-
27-
logger := slog.With(
28-
slog.String(logfields.Module, "env"),
29-
slog.String(logfields.Operation, "reload_env"),
30-
)
31-
logger.Info("reload env", slog.Any("env_prefix", map[string]any{"key": PrefixKey, "value": envPrefix}))
26+
logger := slog.With(slog.String(logfields.Module, "env"), slog.String(logfields.Operation, "reload_env"))
27+
logger.Info("reload env")
3228

3329
for _, env := range os.Environ() {
3430
kvs := strings.SplitN(env, "=", 2)
3531
if len(kvs) != 2 {
36-
logger.Error("split env error")
37-
continue
38-
}
39-
40-
rawEnvKey := trim(kvs[0])
41-
if rawEnvKey == "" ||
42-
strings.HasPrefix(rawEnvKey, "_") ||
43-
strings.HasPrefix(rawEnvKey, "=") ||
44-
!hasEnvPrefix(rawEnvKey, envPrefix) {
45-
logger.Warn(fmt.Sprintf("unset env, key=%s", rawEnvKey))
46-
_ = os.Unsetenv(rawEnvKey)
32+
logger.Error("split env error", slog.String("env", env))
4733
continue
4834
}
4935

50-
key, ok := Normalize(rawEnvKey)
36+
oldKey := trim(kvs[0])
37+
newKey, ok := Normalize(oldKey)
5138
if ok {
52-
if key == rawEnvKey {
39+
if newKey == oldKey {
5340
continue
5441
}
5542

56-
setOk := os.Setenv(key, kvs[1]) == nil
57-
logger.Info(fmt.Sprintf("reset env, old_key=%s new_key=%s set_ok=%v", rawEnvKey, key, setOk))
43+
assert.Exit(os.Unsetenv(oldKey))
44+
assert.Exit(os.Setenv(newKey, kvs[1]))
45+
logger.Info(fmt.Sprintf("reset env, old_key=%s new_key=%s", oldKey, newKey))
5846
} else {
59-
_ = os.Unsetenv(rawEnvKey)
47+
logger.Warn(fmt.Sprintf("unset env, key=%s", oldKey))
48+
assert.Exit(os.Unsetenv(oldKey))
6049
}
6150
}
6251
}

env/util.go

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
11
package env
22

33
import (
4-
"os"
54
"strings"
65

76
"github.com/ettle/strcase"
87
)
98

10-
const PrefixKey = "ENV_PREFIX"
11-
12-
func hasEnvPrefix(key string, prefix string) bool {
13-
return strings.HasPrefix(strings.ToUpper(key), strings.ToUpper(prefix))
14-
}
15-
16-
func getEnvPrefix() string {
17-
prefix := strings.TrimSpace(os.Getenv(PrefixKey))
18-
if prefix != "" {
19-
prefix = strings.ReplaceAll(prefix+"_", "__", "_")
20-
}
21-
return strings.ToUpper(prefix)
22-
}
23-
249
var trim = strings.TrimSpace
2510
var replacer = strcase.NewCaser(
2611
true,
@@ -32,21 +17,7 @@ var replacer = strcase.NewCaser(
3217
strcase.PreserveNumberFormatting,
3318
))
3419

35-
func KeyHandler(key string) string {
36-
key = strings.ToUpper(replacer.ToSNAKE(key))
37-
envPrefix := getEnvPrefix()
38-
if envPrefix != "" {
39-
key = envPrefix + "_" + strings.TrimPrefix(key, envPrefix)
40-
}
41-
return strings.ToUpper(trim(strings.ReplaceAll(key, "__", "_")))
42-
}
43-
44-
// Normalize a-b=>a_b, a.b=>a_b, a/b=>a_b
45-
func Normalize(key string) (string, bool) {
46-
key = trim(key)
47-
if key == "" || strings.HasPrefix(key, "_") || strings.HasPrefix(key, "=") {
48-
return key, false
49-
}
50-
51-
return KeyHandler(key), true
20+
func keyHandler(key string) string {
21+
key = strings.ReplaceAll(replacer.ToSNAKE(key), "__", "_")
22+
return strings.ToUpper(trim(key))
5223
}

env/util_test.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@ import (
55
"os"
66
"testing"
77

8+
"github.com/stretchr/testify/assert"
9+
810
"github.com/pubgo/funk/env"
911
"github.com/pubgo/funk/log"
10-
"github.com/pubgo/funk/pretty"
11-
"github.com/samber/lo"
12-
"github.com/stretchr/testify/assert"
1312
)
1413

14+
func init() {
15+
slog.SetDefault(slog.New(log.NewSlog(log.GetLogger(""))))
16+
}
17+
1518
func TestResetEnv(t *testing.T) {
1619
assert.NoError(t, os.Setenv("abc", "1"))
1720
assert.Equal(t, os.Getenv("abc"), "1")
@@ -26,16 +29,11 @@ func TestNormalize(t *testing.T) {
2629
}
2730

2831
func TestEnvPrefix(t *testing.T) {
29-
slog.SetDefault(slog.New(log.NewSlog(log.GetLogger(""))))
30-
3132
env.Reload()
32-
pretty.Println("env_keys", lo.Keys(env.Map()))
3333

34-
env.Set(env.PrefixKey, "test").Must()
35-
env.Set("test_hello", "world").Must()
34+
env.MustSet("test_hello", "world")
3635
env.Reload()
3736

3837
envMap := env.Map()
3938
assert.Equal(t, envMap["TEST_HELLO"], "world")
40-
pretty.Println(os.Environ())
4139
}

v2/result/future.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package result
2+
3+
import (
4+
"context"
5+
6+
"github.com/pubgo/funk/assert"
7+
"github.com/samber/lo"
8+
)
9+
10+
func AsyncErr(fn func() Error) ErrFuture {
11+
assert.If(fn == nil, "[fn] is nil")
12+
13+
var future = newErrFuture()
14+
go func() { defer future.close(); future.setErr(try(func() error { return fn().getErr() })) }()
15+
return future
16+
}
17+
18+
func Async[T any](fn func() Result[T]) *Future[T] {
19+
assert.If(fn == nil, "[fn] is nil")
20+
21+
var future = newFuture[T]()
22+
go func() { defer future.close(); future.setVal(tryResult(fn)) }()
23+
return future
24+
}
25+
26+
func newFuture[T any]() *Future[T] {
27+
return &Future[T]{done: make(chan struct{})}
28+
}
29+
30+
type Future[T any] struct {
31+
v Result[T]
32+
done chan struct{}
33+
}
34+
35+
func (f *Future[T]) close() { close(f.done) }
36+
func (f *Future[T]) setVal(val Result[T]) { f.v = val }
37+
38+
func (f *Future[T]) Await(ctxL ...context.Context) Result[T] {
39+
ctx := lo.FirstOr(ctxL, context.Background())
40+
select {
41+
case <-f.done:
42+
return f.v
43+
case <-ctx.Done():
44+
return f.v.WithErr(ctx.Err())
45+
}
46+
}
47+
48+
func newErrFuture() ErrFuture {
49+
return ErrFuture{done: make(chan struct{})}
50+
}
51+
52+
type ErrFuture struct {
53+
e error
54+
done chan struct{}
55+
}
56+
57+
func (f *ErrFuture) close() { close(f.done) }
58+
func (f *ErrFuture) setErr(err error) { f.e = err }
59+
60+
func (f *ErrFuture) Await(ctxL ...context.Context) Error {
61+
ctx := lo.FirstOr(ctxL, context.Background())
62+
select {
63+
case <-f.done:
64+
return ErrOf(f.e)
65+
case <-ctx.Done():
66+
return ErrOf(ctx.Err())
67+
}
68+
}

0 commit comments

Comments
 (0)