Skip to content

Commit 8671555

Browse files
authored
🐛 [environment] Fix environment variable parsing (#336)
<!-- Copyright (C) 2020-2022 Arm Limited or its affiliates and Contributors. All rights reserved. SPDX-License-Identifier: Apache-2.0 --> ### Description - Fix the bug happening when parsing environment variables - exposed some of the underlying function ### Test Coverage <!-- Please put an `x` in the correct box e.g. `[x]` to indicate the testing coverage of this change. --> - [x] This change is covered by existing or additional automated tests. - [ ] Manual testing has been performed (and evidence provided) as automated testing was not feasible. - [ ] Additional tests are not required for this change (e.g. documentation update).
1 parent 7c8e0cf commit 8671555

File tree

5 files changed

+55
-20
lines changed

5 files changed

+55
-20
lines changed

changes/20231013160208.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:sparkles: `[environment]` Expose utilities for parsing and finding environment variables

changes/20231013160247.bugfix

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:bug: `[environment]` Fix environment variables parsing when an entry is incorrect

utils/environment/current.go

+2-17
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
package environment
22

33
import (
4-
"fmt"
54
"os"
65
"os/user"
76

87
"github.com/joho/godotenv"
98
"github.com/mitchellh/go-homedir"
109

11-
"github.com/ARM-software/golang-utils/utils/commonerrors"
1210
"github.com/ARM-software/golang-utils/utils/filesystem"
1311
)
1412

@@ -35,14 +33,7 @@ func (c *currentEnv) GetEnvironmentVariables(dotEnvFiles ...string) (variables [
3533
_ = godotenv.Load(dotEnvFiles...) // ignore error (specifically on loading .env) consistent with config.LoadFromEnvironment
3634
}
3735

38-
curentEnv := os.Environ()
39-
for i := range curentEnv {
40-
envvar, err := ParseEnvironmentVariable(curentEnv[i])
41-
if err != nil {
42-
return
43-
}
44-
variables = append(variables, envvar)
45-
}
36+
variables = ParseEnvironmentVariables(os.Environ()...)
4637
return
4738
}
4839

@@ -52,13 +43,7 @@ func (c *currentEnv) GetFilesystem() filesystem.FS {
5243

5344
// GetEnvironmentVariable searches the current environment (and optionally dotEnvFiles) for a specific environment variable `envvar`.
5445
func (c *currentEnv) GetEnvironmentVariable(envvar string, dotEnvFiles ...string) (value IEnvironmentVariable, err error) {
55-
envvars := c.GetEnvironmentVariables(dotEnvFiles...)
56-
for i := range envvars {
57-
if envvars[i].GetKey() == envvar {
58-
return envvars[i], nil
59-
}
60-
}
61-
return nil, fmt.Errorf("%w: environment variable '%v' not set", commonerrors.ErrNotFound, envvar)
46+
return FindEnvironmentVariable(envvar, c.GetEnvironmentVariables(dotEnvFiles...)...)
6247
}
6348

6449
// NewCurrentEnvironment returns system current environment.

utils/environment/envvar.go

+34-3
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,18 @@ func isEnvVarKey(value string) bool {
8282
// ParseEnvironmentVariable parses an environment variable definition, in the form "key=value".
8383
func ParseEnvironmentVariable(variable string) (IEnvironmentVariable, error) {
8484
elements := strings.Split(strings.TrimSpace(variable), "=")
85-
if len(elements) != 2 {
86-
return nil, fmt.Errorf("%w: invalid environment variable entry", commonerrors.ErrInvalid)
85+
if len(elements) < 2 {
86+
return nil, fmt.Errorf("%w: invalid environment variable entry as not following key=value", commonerrors.ErrInvalid)
8787
}
88-
envvar := NewEnvironmentVariable(elements[0], elements[1])
88+
value := elements[1]
89+
if len(elements) > 2 {
90+
var valueElems []string
91+
for i := 1; i < len(elements); i++ {
92+
valueElems = append(valueElems, elements[i])
93+
}
94+
value = strings.Join(valueElems, "=")
95+
}
96+
envvar := NewEnvironmentVariable(elements[0], value)
8997
return envvar, envvar.Validate()
9098
}
9199

@@ -114,3 +122,26 @@ func ValidateEnvironmentVariables(vars ...IEnvironmentVariable) error {
114122
}
115123
return nil
116124
}
125+
126+
// ParseEnvironmentVariables parses a list of key=value entries such as os.Environ() and returns a list of the corresponding environment variables.
127+
// Any entry failing parsing will be ignored.
128+
func ParseEnvironmentVariables(variables ...string) (envVars []IEnvironmentVariable) {
129+
for i := range variables {
130+
envvar, err := ParseEnvironmentVariable(variables[i])
131+
if err != nil {
132+
continue
133+
}
134+
envVars = append(envVars, envvar)
135+
}
136+
return
137+
}
138+
139+
// FindEnvironmentVariable looks for an environment variable in a list. if no environment variable matches, an error is returned
140+
func FindEnvironmentVariable(envvar string, envvars ...IEnvironmentVariable) (IEnvironmentVariable, error) {
141+
for i := range envvars {
142+
if envvars[i].GetKey() == envvar {
143+
return envvars[i], nil
144+
}
145+
}
146+
return nil, fmt.Errorf("%w: environment variable '%v' not set", commonerrors.ErrNotFound, envvar)
147+
}

utils/environment/envvar_test.go

+17
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@ func TestParseEnvironmentVariable(t *testing.T) {
128128
errortest.AssertError(t, err, commonerrors.ErrInvalid)
129129
_, err = ParseEnvironmentVariable(faker.Word() + "=" + faker.Word())
130130
require.NoError(t, err)
131+
_, err = ParseEnvironmentVariable(faker.Word() + "=" + faker.Word() + "=")
132+
require.NoError(t, err)
133+
_, err = ParseEnvironmentVariable(faker.Word() + "=" + faker.Word() + "=" + faker.Sentence())
134+
require.NoError(t, err)
131135
key := strings.ReplaceAll(strings.ReplaceAll(faker.Sentence(), " ", "_"), ".", "")
132136
value := faker.Sentence()
133137
envTest := NewEnvironmentVariable(key, value)
@@ -144,3 +148,16 @@ func TestParseEnvironmentVariable(t *testing.T) {
144148
require.NoError(t, env.UnmarshalText(txt))
145149
assert.True(t, envTest.Equal(env))
146150
}
151+
152+
func TestEnvVar_ParseEnvironmentVariables(t *testing.T) {
153+
username := faker.Username()
154+
entries := []string{"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65357/bus", "HOME=/home/josjen01", faker.UUIDHyphenated(), "EDITOR=hx", "LOGNAME=josjen01", "DISPLAY=:0", "SSH_AUTH_SOCK=/tmp/ssh-eBrdhiWnaFYp/agent.4969", "KRB5CCNAME=FILE:/tmp/krb5cc_65357_XLwjEE", "GPG_AGENT_INFO=/run/user/65357/gnupg/S.gpg-agent:0:1", "LANGUAGE=en_US:", "USER=" + username, "XDG_RUNTIME_DIR=/run/user/65357", "WINDOWID=54525966", "KITTY_PID=151539", "CMSIS_PACK_ROOT=/home/josjen01/.cache/arm/packs", "XDG_SESSION_ID=4", "XDG_CONFIG_DIRS=/etc/xdg/xdg-i3:/etc/xdg", faker.Name(), "GDMSESSION=i3", "WINDOWPATH=2", "SHLVL=1", "DESKTOP_SESSION=i3", "GTK_MODULES=gail:atk-bridge", "LANG=en_US.UTF-8", "FZF_DEFAULT_OPTS=--color dark,hl:#d65d08,hl+:#d65d08,fg+:#282828,bg+:#282828,fg+:#b58900,info:#ebdbb2,prompt:#268bd2,pointer:#2aa198,marker:#d33682,spinner:#268bd2 -m", "XDG_SESSION_DESKTOP=i3", "XDG_SESSION_TYPE=x11", "KITTY_PUBLIC_KEY=1:^1R-7)Aw|}io+D^KqaYVJF0R&a!f&dpX}gSSEIH&", "XDG_SEAT=seat0", "TERM=xterm-kitty", "XDG_DATA_DIRS=/usr/share/i3:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop", "DESKTOP_STARTUP_ID=i3/kitty/4969-5-e126332_TIME31895328", "SHELL=/bin/bash", "KITTY_WINDOW_ID=6", "QT_ACCESSIBILITY=1", "COLORTERM=truecolor", "TERMINFO=/home/josjen01/.local/kitty.app/lib/kitty/terminfo", "SSH_AGENT_PID=5033", "XDG_SESSION_CLASS=user", "KITTY_INSTALLATION_DIR=/home/josjen01/.local/kitty.app/lib/kitty", "XDG_CURRENT_DESKTOP=i3", "MANPATH=:/home/josjen01/.local/kitty.app/share/man::/opt/puppetlabs/puppet/share/man", "XAUTHORITY=/run/user/65357/gdm/Xauthority", "CMSIS_COMPILER_ROOT=/etc/cmsis-build", "XDG_VTNR=2", "I3SOCK=/run/user/65357/i3/ipc-socket.4969", "USERNAME=josjen01", "PATH=/usr/local/go/bin:/bin:/home/josjen01/.local/bin:/home/josjen01/go/bin:/home/josjen01/.cargo/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/usr/games:/usr/local/games:/snap/bin:/opt/puppetlabs/bin", "PWD=/home/josjen01/Git/golang-utils/utils/environment", "GOCOVERDIR=/tmp/go-build1026478377/b001/gocoverdir", "test1=Accusantium voluptatem aut sit perferendis consequatur", "test2=Perferendis aut accusantium voluptatem sit consequatur.", faker.Word()}
155+
environmentVariables := ParseEnvironmentVariables(entries...)
156+
assert.NotEmpty(t, environmentVariables)
157+
assert.Len(t, environmentVariables, len(entries)-3)
158+
env, err := FindEnvironmentVariable("USER", environmentVariables...)
159+
require.NoError(t, err)
160+
assert.Equal(t, username, env.GetValue())
161+
_, err = FindEnvironmentVariable("TEST1", environmentVariables...)
162+
errortest.AssertError(t, err, commonerrors.ErrNotFound)
163+
}

0 commit comments

Comments
 (0)