Skip to content

Commit

Permalink
Merge pull request #496 from dictu-lang/feature/env_read_file
Browse files Browse the repository at this point in the history
Env.readFile()
  • Loading branch information
Jason2605 committed Dec 28, 2021
2 parents 9315dfe + 90f6f12 commit d3d30fc
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ dictu.ilk
dictu.pdb
test1.du
.vscode/
/.env
21 changes: 21 additions & 0 deletions docs/docs/standard-lib/env.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,24 @@ Env.set("key", "test");
Env.set("key", nil); // Remove env var
Env.set("key", 10); // set() arguments must be a string or nil.
```

### Env.readFile(string: path -> optional)

To read environment variables from a file this helper method is provided.
By default it will attempt to read `.env` unless a different path is supplied.
Returns a Result type and on success will unwrap to nil.

Note: You are able to have comments in the `.env` file via the use of `#` (both in-line and first character).

```env
# This is a comment
TEST=10
TESTING=100 # In-line comment
```

```cs
Env.readFile(); // <Result Suc>
print(Env.get("TEST")); // 10
print(Env.get("TESTING")); // 100
```
3 changes: 2 additions & 1 deletion scripts/generate.du
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ var files = [
'src/vm/datatypes/lists/list',
'src/vm/datatypes/dicts/dict',
'src/vm/datatypes/result/result',
'src/optionals/unittest/unittest'
'src/optionals/unittest/unittest',
'src/optionals/env/env'
];

for (var i = 0; i < files.len(); i += 1) {
Expand Down
32 changes: 32 additions & 0 deletions src/optionals/env/env-source.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#define DICTU_ENV_SOURCE "import Env;\n" \
"\n" \
"def readFile(path='.env') {\n" \
" const SPLIT_DELIMITER = '=';\n" \
" const COMMENT = '#';\n" \
"\n" \
" with(path, 'r') {\n" \
" var line;\n" \
" var lineCount = 0;\n" \
" // When you reach the end of the file, nil is returned\n" \
" while((line = file.readLine()) != nil) {\n" \
" lineCount = lineCount + 1;\n" \
" if (not line or line.startsWith(COMMENT))\n" \
" continue;\n" \
"\n" \
" if (not line.contains('='))\n" \
" return Error('Malformed entry on line {}'.format(lineCount));\n" \
"\n" \
" const [variable, rawValue] = line.split(SPLIT_DELIMITER, 1);\n" \
" // Strip out any in-line comments\n" \
" const value = rawValue.split(COMMENT, 1);\n" \
" const result = Env.set(variable.strip(), value[0].strip());\n" \
"\n" \
" if (not result.success()) {\n" \
" return result;\n" \
" }\n" \
" }\n" \
" }\n" \
"\n" \
" return Success(nil);\n" \
"}\n" \

22 changes: 13 additions & 9 deletions src/optionals/env.c → src/optionals/env/env.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "env.h"

#include "env-source.h"

#ifdef _WIN32
#define unsetenv(NAME) _putenv_s(NAME, "")
int setenv(const char *name, const char *value, int overwrite) {
Expand All @@ -25,7 +27,7 @@ static Value get(DictuVM *vm, int argCount, Value *args) {
runtimeError(vm, "get() arguments must be a string.");
return EMPTY_VAL;
}

char *value = getenv(AS_CSTRING(args[0]));

if (argCount == 2) {
Expand Down Expand Up @@ -77,19 +79,21 @@ static Value set(DictuVM *vm, int argCount, Value *args) {
}

Value createEnvModule(DictuVM *vm) {
ObjString *name = copyString(vm, "Env", 3);
push(vm, OBJ_VAL(name));
ObjModule *module = newModule(vm, name);
push(vm, OBJ_VAL(module));
ObjClosure *closure = compileModuleToClosure(vm, "Env", DICTU_ENV_SOURCE);

if (closure == NULL) {
return EMPTY_VAL;
}

push(vm, OBJ_VAL(closure));

/**
* Define Env methods
*/
defineNative(vm, &module->values, "get", get);
defineNative(vm, &module->values, "set", set);
defineNative(vm, &closure->function->module->values, "get", get);
defineNative(vm, &closure->function->module->values, "set", set);

pop(vm);
pop(vm);

return OBJ_VAL(module);
return OBJ_VAL(closure);
}
31 changes: 31 additions & 0 deletions src/optionals/env/env.du
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Env;

def readFile(path='.env') {
const SPLIT_DELIMITER = '=';
const COMMENT = '#';

with(path, 'r') {
var line;
var lineCount = 0;
// When you reach the end of the file, nil is returned
while((line = file.readLine()) != nil) {
lineCount = lineCount + 1;
if (not line or line.startsWith(COMMENT))
continue;

if (not line.contains('='))
return Error('Malformed entry on line {}'.format(lineCount));

const [variable, rawValue] = line.split(SPLIT_DELIMITER, 1);
// Strip out any in-line comments
const value = rawValue.split(COMMENT, 1);
const result = Env.set(variable.strip(), value[0].strip());

if (not result.success()) {
return result;
}
}
}

return Success(nil);
}
4 changes: 2 additions & 2 deletions src/optionals/env.h → src/optionals/env/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#include <stdlib.h>
#include <string.h>

#include "optionals.h"
#include "../vm/vm.h"
#include "../optionals.h"
#include "../../vm/vm.h"

Value createEnvModule(DictuVM *vm);

Expand Down
2 changes: 1 addition & 1 deletion src/optionals/optionals.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

BuiltinModules modules[] = {
{"Math", &createMathsModule, false},
{"Env", &createEnvModule, false},
{"Env", &createEnvModule, true},
{"JSON", &createJSONModule, false},
{"Log", &createLogModule, false},
{"Path", &createPathModule, false},
Expand Down
2 changes: 1 addition & 1 deletion src/optionals/optionals.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include "../vm/util.h"
#include "math.h"
#include "env.h"
#include "env/env.h"
#include "system.h"
#include "json.h"
#include "log.h"
Expand Down
2 changes: 2 additions & 0 deletions src/vm/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1475,6 +1475,7 @@ static DictuInterpretResult run(DictuVM *vm) {

// If we have imported this module already, skip.
if (tableGet(&vm->modules, fileName, &moduleVal)) {
vm->lastModule = AS_MODULE(moduleVal);
push(vm, moduleVal);
DISPATCH();
}
Expand All @@ -1494,6 +1495,7 @@ static DictuInterpretResult run(DictuVM *vm) {
ip = frame->ip;

tableGet(&vm->modules, fileName, &module);
vm->lastModule = AS_MODULE(module);
}

DISPATCH();
Expand Down
5 changes: 5 additions & 0 deletions tests/env/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
TEST=10
INLINE=100 # in-line comment
# IGNORE=1000
SPACES = 30
MALFORMED
13 changes: 12 additions & 1 deletion tests/env/env.du
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* end.du
*
* Testing the Env functions:
* - get(), set()
* - get(), set(), readFile()
*
*/
import Env;
Expand All @@ -15,3 +15,14 @@ assert(Env.set("test", "test").success() == true);
assert(Env.get("test") == "test");
assert(Env.set("test", nil).success() == true);
assert(Env.get("test") == nil);

import Path;

const result = Env.readFile(Path.dirname(__file__) + '/.env');
assert(Env.get("TEST") == "10");
assert(Env.get("INLINE") == "100");
assert(Env.get("IGNORE") == nil);
assert(Env.get("MALFORMED") == nil);

assert(not result.success());
assert(result.unwrapError() == "Malformed entry on line 5");

0 comments on commit d3d30fc

Please sign in to comment.