-
Notifications
You must be signed in to change notification settings - Fork 950
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Lang Chi <21860405@zju.edu.cn>
- Loading branch information
Showing
9 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"os" | ||
"strings" | ||
) | ||
|
||
// reads a file of line terminated key=value pairs, and overrides any keys | ||
// present in the file with additional pairs specified in the override parameter | ||
func readKVStrings(files []string, override []string) ([]string, error) { | ||
envVariables := []string{} | ||
for _, ef := range files { | ||
parsedVars, err := parseEnvFile(ef) | ||
if err != nil { | ||
return nil, err | ||
} | ||
envVariables = append(envVariables, parsedVars...) | ||
} | ||
// parse the '-e' and '--env' after, to allow override | ||
envVariables = append(envVariables, override...) | ||
|
||
return envVariables, nil | ||
} | ||
|
||
// parseEnvFile reads a file with environment variables enumerated by lines | ||
func parseEnvFile(filename string) ([]string, error) { | ||
fh, err := os.Open(filename) | ||
if err != nil { | ||
return []string{}, err | ||
} | ||
defer fh.Close() | ||
|
||
lines := []string{} | ||
scanner := bufio.NewScanner(fh) | ||
for scanner.Scan() { | ||
// trim the line from all leading whitespace first | ||
line := strings.TrimLeft(scanner.Text(), whiteSpaces) | ||
// line is not empty, and not starting with '#' | ||
if len(line) > 0 && !strings.HasPrefix(line, "#") { | ||
data := strings.SplitN(line, "=", 2) | ||
|
||
// trim the front of a variable, but nothing else | ||
variable := strings.TrimLeft(data[0], whiteSpaces) | ||
if strings.ContainsAny(variable, whiteSpaces) { | ||
return []string{}, ErrBadEnvVariable{fmt.Sprintf("variable '%s' has white spaces", variable)} | ||
} | ||
|
||
if len(data) > 1 { | ||
|
||
// pass the value through, no trimming | ||
lines = append(lines, fmt.Sprintf("%s=%s", variable, data[1])) | ||
} else { | ||
// if only a pass-through variable is given, clean it up. | ||
lines = append(lines, fmt.Sprintf("%s=%s", strings.TrimSpace(line), os.Getenv(line))) | ||
} | ||
} | ||
} | ||
return lines, scanner.Err() | ||
} | ||
|
||
const whiteSpaces = " \t" | ||
|
||
// ErrBadEnvVariable typed error for bad environment variable | ||
type ErrBadEnvVariable struct { | ||
msg string | ||
} | ||
|
||
// Error implements error interface. | ||
func (e ErrBadEnvVariable) Error() string { | ||
return fmt.Sprintf("poorly formatted environment: %s", e.msg) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package main | ||
|
||
import ( | ||
"bufio" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"reflect" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func tmpFileWithContent(content string, t *testing.T) string { | ||
tmpFile, err := ioutil.TempFile("", "envfile-test") | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
defer tmpFile.Close() | ||
|
||
tmpFile.WriteString(content) | ||
return tmpFile.Name() | ||
} | ||
|
||
// Test ParseEnvFile for a file with a few well formatted lines | ||
func TestParseEnvFileGoodFile(t *testing.T) { | ||
content := `foo=bar | ||
baz=quux | ||
# comment | ||
_foobar=foobaz | ||
with.dots=working | ||
and_underscore=working too | ||
` | ||
// Adding a newline + a line with pure whitespace. | ||
// This is being done like this instead of the block above | ||
// because it's common for editors to trim trailing whitespace | ||
// from lines, which becomes annoying since that's the | ||
// exact thing we need to test. | ||
content += "\n \t " | ||
tmpFile := tmpFileWithContent(content, t) | ||
defer os.Remove(tmpFile) | ||
|
||
lines, err := parseEnvFile(tmpFile) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
expectedLines := []string{ | ||
"foo=bar", | ||
"baz=quux", | ||
"_foobar=foobaz", | ||
"with.dots=working", | ||
"and_underscore=working too", | ||
} | ||
|
||
if !reflect.DeepEqual(lines, expectedLines) { | ||
t.Fatal("lines not equal to expected_lines") | ||
} | ||
} | ||
|
||
// Test ParseEnvFile for an empty file | ||
func TestParseEnvFileEmptyFile(t *testing.T) { | ||
tmpFile := tmpFileWithContent("", t) | ||
defer os.Remove(tmpFile) | ||
|
||
lines, err := parseEnvFile(tmpFile) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if len(lines) != 0 { | ||
t.Fatal("lines not empty; expected empty") | ||
} | ||
} | ||
|
||
// Test ParseEnvFile for a non existent file | ||
func TestParseEnvFileNonExistentFile(t *testing.T) { | ||
_, err := parseEnvFile("foo_bar_baz") | ||
if err == nil { | ||
t.Fatal("ParseEnvFile succeeded; expected failure") | ||
} | ||
if _, ok := err.(*os.PathError); !ok { | ||
t.Fatalf("Expected a PathError, got [%v]", err) | ||
} | ||
} | ||
|
||
// Test ParseEnvFile for a badly formatted file | ||
func TestParseEnvFileBadlyFormattedFile(t *testing.T) { | ||
content := `foo=bar | ||
f =quux | ||
` | ||
|
||
tmpFile := tmpFileWithContent(content, t) | ||
defer os.Remove(tmpFile) | ||
|
||
_, err := parseEnvFile(tmpFile) | ||
if err == nil { | ||
t.Fatalf("Expected an ErrBadEnvVariable, got nothing") | ||
} | ||
if _, ok := err.(ErrBadEnvVariable); !ok { | ||
t.Fatalf("Expected an ErrBadEnvVariable, got [%v]", err) | ||
} | ||
expectedMessage := "poorly formatted environment: variable 'f ' has white spaces" | ||
if err.Error() != expectedMessage { | ||
t.Fatalf("Expected [%v], got [%v]", expectedMessage, err.Error()) | ||
} | ||
} | ||
|
||
// Test ParseEnvFile for a file with a line exceeding bufio.MaxScanTokenSize | ||
func TestParseEnvFileLineTooLongFile(t *testing.T) { | ||
content := strings.Repeat("a", bufio.MaxScanTokenSize+42) | ||
content = fmt.Sprint("foo=", content) | ||
|
||
tmpFile := tmpFileWithContent(content, t) | ||
defer os.Remove(tmpFile) | ||
|
||
_, err := parseEnvFile(tmpFile) | ||
if err == nil { | ||
t.Fatal("ParseEnvFile succeeded; expected failure") | ||
} | ||
} | ||
|
||
// ParseEnvFile with a random file, pass through | ||
func TestParseEnvFileRandomFile(t *testing.T) { | ||
content := `first line | ||
another invalid line` | ||
tmpFile := tmpFileWithContent(content, t) | ||
defer os.Remove(tmpFile) | ||
|
||
_, err := parseEnvFile(tmpFile) | ||
|
||
if err == nil { | ||
t.Fatalf("Expected an ErrBadEnvVariable, got nothing") | ||
} | ||
if _, ok := err.(ErrBadEnvVariable); !ok { | ||
t.Fatalf("Expected an ErrBadEnvvariable, got [%v]", err) | ||
} | ||
expectedMessage := "poorly formatted environment: variable 'first line' has white spaces" | ||
if err.Error() != expectedMessage { | ||
t.Fatalf("Expected [%v], got [%v]", expectedMessage, err.Error()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
TEST1=value1 | ||
|