Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mkdirTemp to System module #536

Merged
merged 12 commits into from
Oct 6, 2022
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/docs/standard-lib/system.md
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,14 @@ Note: This is not available on Windows systems.

```cs
System.uname();
```

### System.mkdirTemp(string)

Makes a temporary directory. If an empty string is given, the temporary directory's name will be a random string created in the current working directory. If a string is passed in, the temporary directory will be created with that name in the current working directory.

Note: This is not available on Windows systems.

```cs
System.mkdirTemp("");
```
8 changes: 8 additions & 0 deletions examples/mkdirTemp.du
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Env;
import System;

const tmpDir = Env.get("TMPDIR") + "XXXXXX";

var res = System.mkdirTemp(tmpDir);

print(res);
31 changes: 31 additions & 0 deletions src/optionals/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,36 @@ static Value unameNative(DictuVM *vm, int argCount, Value *args) {

return OBJ_VAL(unameDict);
}

static Value mkdirTempNative(DictuVM *vm, int argCount, Value *args) {
if (argCount == 0) {
runtimeError(vm, "mkdirTemp() takes 1 argument (%d given)", argCount);
return EMPTY_VAL;
}

if (!IS_STRING(args[0])) {
runtimeError(vm, "mkdirTemp() first argument must be a string");
return EMPTY_VAL;
}

char *template = AS_CSTRING(args[0]);
char *tmpl = {0};

if (template[0] != '\0') {
tmpl = ALLOCATE(vm, char, strlen(template));
strcpy(tmpl, template);
} else {
tmpl = ALLOCATE(vm, char, PATH_MAX);
strcpy(tmpl, "XXXXXX");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to allocate for the terminating char too. My thinking here also is that if no template is passed the directory would be made via the 6 digits of XXXXXX template right? Doesn't that mean we only need to allocate for these 6 + \0?

Suggested change
if (template[0] != '\0') {
tmpl = ALLOCATE(vm, char, strlen(template));
strcpy(tmpl, template);
} else {
tmpl = ALLOCATE(vm, char, PATH_MAX);
strcpy(tmpl, "XXXXXX");
}
if (template[0] != '\0') {
tmpl = ALLOCATE(vm, char, strlen(template) + 1);
strcpy(tmpl, template);
} else {
tmpl = ALLOCATE(vm, char, 7);
strcpy(tmpl, "XXXXXX");
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also probably keep reference to the length rather than calculating again via strlen in the takeString call


char *tmpDir = mkdtemp(tmpl);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth using the Result type here as mkdtemp can fail. In those situations it would be good to give some indication as to why it failed, we can do that by unwrapping a Result type

if (!tmpDir) {
ERROR_RESULT;
}

return newResultSuccess(vm, OBJ_VAL(takeString(vm, tmpDir, strlen(tmpDir))));
}
#endif

static Value rmdirNative(DictuVM *vm, int argCount, Value *args) {
Expand Down Expand Up @@ -477,6 +507,7 @@ Value createSystemModule(DictuVM *vm) {
defineNative(vm, &module->values, "getpid", getpidNative);
defineNative(vm, &module->values, "chown", chownNative);
defineNative(vm, &module->values, "uname", unameNative);
defineNative(vm, &module->values, "mkdirTemp", mkdirTempNative);
#endif
defineNative(vm, &module->values, "rmdir", rmdirNative);
defineNative(vm, &module->values, "mkdir", mkdirNative);
Expand Down
1 change: 1 addition & 0 deletions tests/system/import.du
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ import "constants.du";
import "chmod.du";
import "chown.du";
import "uname.du";
import "mkdirTemp.du";
35 changes: 35 additions & 0 deletions tests/system/mkdirTemp.du
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* mkdirTemp.du
*
* Testing the System.mkdirTemp function
*
* mkdirTemp makes a temporary directory.
*/
from UnitTest import UnitTest;

import Path;
import System;

class TestSystemMkdirTest < UnitTest {
testSystemMkdirTest() {
if (System.platform != "windows") {
const tempDirName = "test_mkdir_temp";

if (Path.exists(tempDirName)) {
this.assertTruthy(System.rmdir(tempDirName).success());
}

var res = System.mkdirTemp(tempDirName).match(
def (result) => {
this.assertEquals(result, tempDirName);
this.assertTruthy(System.rmdir(tempDirName).success());
},
def (error) => {
this.assertEquals(error, "Invalid argument");
}
);
}
}
}

TestSystemMkdirTest().run();