First commit.

This commit is contained in:
Naoriel Sa' Rocí 2024-05-10 22:01:12 +02:00
commit e9fbe5535a
11 changed files with 347 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.log
.vscode/

8
CHANGELOG.md Normal file
View File

@ -0,0 +1,8 @@
# git.sa-roci.de/oss/go_environment Release notes
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## v. 0.0.1
- Initial Release.

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2024 Sa Rocí Solutions
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# git.sa-roci.de/oss/go_environment
A package for extended environment variable usage.

45
envString.go Normal file
View File

@ -0,0 +1,45 @@
package go_environment
import (
"encoding/json"
"os"
)
// EnvironmentString describes a (readonly) string which is
// defined as an environment variable.
type EnvironmentString struct {
Variable string
}
// MarshalJSON returns the JSON encoding of es.
func (es EnvironmentString) MarshalJSON() ([]byte, error) {
return json.Marshal(es.Variable)
}
// UnmarshalJSON parses the JSON-encoded data and stores the
// result in es.
func (es *EnvironmentString) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &es.Variable)
}
// String returns the string representation of es.
func (es EnvironmentString) String() (value string) {
return os.Getenv(es.Variable)
}
// Key returns the key of the underlying environment
// variable of es.
func (es EnvironmentString) Key() (value string) {
return es.Variable
}
// String determines the validity of the underlying
// environment variable of es.
func (es EnvironmentString) Valid() (valid bool) {
if es.Variable == "" {
return false
}
var value string
value, valid = os.LookupEnv(es.Variable)
return valid && (value != "")
}

69
envString_test.go Normal file
View File

@ -0,0 +1,69 @@
package go_environment
import (
"os"
"testing"
)
const (
envKey = "ENV_STRING_TEST_VAR"
testValue = "dummy"
testJSON = `"` + envKey + `"`
)
func TestEnvString(t *testing.T) {
os.Setenv(envKey, "")
test := EnvironmentString{
Variable: envKey,
}
if test.Key() != envKey {
t.Errorf("unexpected environment variable key")
}
if test.Valid() {
t.Errorf("unexpectedly valid environment variable")
}
if test.String() != "" {
t.Errorf("unexpectedly valid environment variable")
}
os.Setenv(envKey, testValue)
if !test.Valid() {
t.Errorf("unexpectedly invalid environment variable")
}
if test.String() != testValue {
t.Errorf("unexpectedly valid environment variable")
}
os.Unsetenv(envKey)
}
func TestEnvStringMarshalling(t *testing.T) {
test := EnvironmentString{}
if test.UnmarshalJSON([]byte(testJSON)) != nil {
t.Errorf("failed to unmarshal")
}
if test.Key() != envKey {
t.Errorf("unexpected environment variable key")
}
if binary, err := test.MarshalJSON(); err != nil {
t.Errorf("failed to marshal")
} else if string(binary) != testJSON {
t.Errorf("unexpected JSON")
}
}
func TestValid(t *testing.T) {
os.Setenv(envKey, testValue)
test := EnvironmentString{
Variable: "",
}
if test.Valid() {
t.Errorf("TestValid: test case 1: unexpectedly valid environment variable")
}
test.Variable = envKey
if !test.Valid() {
t.Errorf("TestValid: test case 2: unexpectedly invalid environment variable")
}
os.Unsetenv(envKey)
if test.Valid() {
t.Errorf("TestValid: test case 3: unexpectedly valid environment variable")
}
}

83
environment.go Normal file
View File

@ -0,0 +1,83 @@
package go_environment
import (
"fmt"
"os"
"regexp"
"strings"
)
var (
// variableExpression is a regular expression for environment variables
//
// A match will look like
// - %<variableName>% (Windows-Notation)
//
// or
// - $(<variableName>) (Unix-Notation)
variableExpression = regexp.MustCompile(`(%([\w]+)%)|(\$\(([\w]+)\))`)
)
// ReplaceEnvironmentVariablesExt replaces all available
// environment variables (defined as %<variableName>%) within
// a string possibly also returning an error if necessary.
func ReplaceEnvironmentVariablesExt(value string) (string, error) {
analysable := value
subStrings := variableExpression.FindStringSubmatch(analysable)
usedVariables := make(map[string]string)
missingVariables := make([]string, 0)
var err error
if len(subStrings) == 5 {
for {
if subStrings[2] != "" {
variableKey := subStrings[2]
variableValue, found := os.LookupEnv(variableKey)
if found {
usedVariables[variableKey] = variableValue
analysable = strings.ReplaceAll(analysable, "%"+variableKey+"%", variableValue)
} else {
missingVariables = append(missingVariables, variableKey)
analysable = strings.ReplaceAll(analysable, "%"+variableKey+"%", variableKey)
}
}
if subStrings[4] != "" {
variableKey := subStrings[4]
variableValue, found := os.LookupEnv(variableKey)
if found {
usedVariables[variableKey] = variableValue
analysable = strings.ReplaceAll(analysable, "$("+variableKey+")", variableValue)
} else {
missingVariables = append(missingVariables, variableKey)
analysable = strings.ReplaceAll(analysable, "$("+variableKey+")", variableKey)
}
}
subStrings = variableExpression.FindStringSubmatch(analysable)
if len(subStrings) != 5 {
break
}
}
}
result := value
for key, value := range usedVariables {
result = strings.ReplaceAll(result, "%"+key+"%", value)
result = strings.ReplaceAll(result, "$("+key+")", value)
}
if len(missingVariables) > 0 {
if len(missingVariables) == 1 {
err = fmt.Errorf("missing environment variable: %s", missingVariables[0])
} else {
err = fmt.Errorf("missing environment variables: %s", strings.Join(missingVariables, ", "))
}
}
return result, err
}
// ReplaceEnvironmentVariablesExt replaces all available
// environment variables (defined as %<variableName>%) within
// a string.
func ReplaceEnvironmentVariables(directoryPath string) string {
path, _ := ReplaceEnvironmentVariablesExt(directoryPath)
return path
}

111
environment_test.go Normal file
View File

@ -0,0 +1,111 @@
package go_environment
import (
"os"
"testing"
)
func TestReplaceEnvironmentVariables(t *testing.T) {
testCases := []struct {
input string
environment map[string]string
expected string
}{
{},
{
input: "a",
environment: map[string]string{},
expected: "a",
},
{
input: "%testVar1%",
environment: map[string]string{},
expected: "%testVar1%",
},
{
input: "%testVar1%",
environment: map[string]string{
"testVar1": "b",
},
expected: "b",
},
{
input: "%testVar1%&%testVar1%",
environment: map[string]string{
"testVar1": "b",
},
expected: "b&b",
},
{
input: "%testVar1%&%testVar2%",
environment: map[string]string{},
expected: "%testVar1%&%testVar2%",
},
{
input: "%testVar1%&%testVar2%",
environment: map[string]string{
"testVar1": "b",
},
expected: "b&%testVar2%",
},
{
input: "%testVar2%&%testVar1%",
environment: map[string]string{
"testVar1": "b",
},
expected: "%testVar2%&b",
},
{
input: "$(testVar1)",
environment: map[string]string{},
expected: "$(testVar1)",
},
{
input: "$(testVar1)",
environment: map[string]string{
"testVar1": "b",
},
expected: "b",
},
{
input: "$(testVar1)&$(testVar1)",
environment: map[string]string{
"testVar1": "b",
},
expected: "b&b",
},
{
input: "$(testVar1)&$(testVar2)",
environment: map[string]string{},
expected: "$(testVar1)&$(testVar2)",
},
{
input: "$(testVar1)&$(testVar2)",
environment: map[string]string{
"testVar1": "b",
},
expected: "b&$(testVar2)",
},
{
input: "$(testVar2)&$(testVar1)",
environment: map[string]string{
"testVar1": "b",
},
expected: "$(testVar2)&b",
},
}
for i, testCase := range testCases {
for key, value := range testCase.environment {
os.Setenv(key, value)
}
if result := ReplaceEnvironmentVariables(testCase.input); result != testCase.expected {
t.Errorf("TestReplaceEnvironmentVariables: test case %d: expected '%s' but got '%s'", i+1, testCase.expected, result)
}
for key := range testCase.environment {
os.Unsetenv(key)
}
}
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.sa-roci.de/oss/go_environment
go 1.18

5
go.work Normal file
View File

@ -0,0 +1,5 @@
go 1.18
use (
.
)

View File

@ -0,0 +1,9 @@
{
"folders": [
{
"name": "git.sa-roci.de/oss/go_environment",
"path": "."
}
],
"settings": {}
}