Skip to content

Commit f2ba2f6

Browse files
committed
feat: Integer environment variables
1 parent a343067 commit f2ba2f6

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

lc-lib/config/parser.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"math"
2222
"os"
2323
"reflect"
24+
"strconv"
2425
"strings"
2526
"time"
2627

@@ -391,15 +392,23 @@ func (p *Parser) populateEntry(vField reflect.Value, vRawConfig reflect.Value, c
391392
return
392393
}
393394

394-
if vMapIndex.Type().AssignableTo(vField.Type()) {
395-
// If a string, check for %ENV(VAR)% and replace with environment variable
396-
if vMapIndex.Kind() == reflect.String {
397-
vMapIndexStr := vMapIndex.String()
398-
if strings.Contains(vMapIndexStr, "%ENV(") {
399-
vMapIndex = reflect.ValueOf(p.replaceEnvVars(vMapIndexStr))
395+
// If a string, check for %ENV(VAR)% and replace with environment variable
396+
if vMapIndex.Kind() == reflect.String {
397+
vMapIndexStr := vMapIndex.String()
398+
if strings.HasPrefix(vMapIndexStr, "%INTENV(") && strings.HasSuffix(vMapIndexStr, ")%") {
399+
value, envErr := p.intEnvVar(vMapIndexStr)
400+
if envErr != nil {
401+
err = fmt.Errorf("Option %s%s could not process integer environment variable: %s", configPath, tag, envErr)
402+
return
400403
}
404+
vMapIndex = reflect.ValueOf(value)
405+
}
406+
if strings.Contains(vMapIndexStr, "%ENV(") {
407+
vMapIndex = reflect.ValueOf(p.replaceEnvVars(vMapIndexStr))
401408
}
409+
}
402410

411+
if vMapIndex.Type().AssignableTo(vField.Type()) {
403412
log.Debugf("populateEntry value: %v (%s%s)", vMapIndex.String(), configPath, tag)
404413
retValue = vMapIndex
405414
return
@@ -543,6 +552,22 @@ func (p *Parser) populateEntry(vField reflect.Value, vRawConfig reflect.Value, c
543552
panic(fmt.Sprintf("Unrecognised configuration structure encountered: %s (Kind: %s)", vField.Type().Name(), vField.Kind().String()))
544553
}
545554

555+
// intEnvVar processes an %INTENV(VAR)% entry and returns the integer value of the
556+
// environment variable VAR, or 0 if not set or not an integer
557+
func (p *Parser) intEnvVar(input string) (int, error) {
558+
envVarValue, exists := os.LookupEnv(input[8 : len(input)-2])
559+
if !exists {
560+
return 0, nil
561+
}
562+
563+
intValue, err := strconv.Atoi(envVarValue)
564+
if err != nil {
565+
return 0, err
566+
}
567+
568+
return intValue, nil
569+
}
570+
546571
// replaceEnvVars replaces any %ENV(VAR)% entries in the given string with
547572
// the value of the environment variable VAR
548573
func (p *Parser) replaceEnvVars(input string) string {

lc-lib/config/parser_env_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package config
2+
3+
import (
4+
"os"
5+
"testing"
6+
)
7+
8+
func TestIntEnvVar(t *testing.T) {
9+
p := &Parser{}
10+
11+
// Case 1: Missing env var
12+
os.Unsetenv("TEST_INT_ENV")
13+
if val, err := p.intEnvVar("%INTENV(TEST_INT_ENV)%"); val != 0 || err != nil {
14+
t.Errorf("Expected 0 for missing env, got %d (error: %v)", val, err)
15+
}
16+
17+
// Case 2: Valid integer env var
18+
os.Setenv("TEST_INT_ENV", "42")
19+
if val, err := p.intEnvVar("%INTENV(TEST_INT_ENV)%"); val != 42 || err != nil {
20+
t.Errorf("Expected 42 for valid env, got %d (error: %v)", val, err)
21+
}
22+
23+
// Case 3: Mixed number text (should error and return 0)
24+
os.Setenv("TEST_INT_ENV", "42abc")
25+
if val, err := p.intEnvVar("%INTENV(TEST_INT_ENV)%"); val != 0 || err == nil {
26+
t.Errorf("Expected 0 for mixed env, got %d (error: %v)", val, err)
27+
}
28+
29+
os.Unsetenv("TEST_INT_ENV")
30+
}

0 commit comments

Comments
 (0)