Improve file/directory utils (#84)
This commit is contained in:
parent
4acf7b395d
commit
8227330eb6
@ -10,6 +10,8 @@
|
||||
#include "timer.wren.inc"
|
||||
|
||||
extern void directoryList(WrenVM* vm);
|
||||
extern void directoryCreate(WrenVM* vm);
|
||||
extern void directoryDelete(WrenVM* vm);
|
||||
extern void fileAllocate(WrenVM* vm);
|
||||
extern void fileFinalize(void* data);
|
||||
extern void fileDelete(WrenVM* vm);
|
||||
@ -121,6 +123,8 @@ static ModuleRegistry modules[] =
|
||||
{
|
||||
MODULE(io)
|
||||
CLASS(Directory)
|
||||
STATIC_METHOD("create_(_,_)", directoryCreate)
|
||||
STATIC_METHOD("delete_(_,_)", directoryDelete)
|
||||
STATIC_METHOD("list_(_,_)", directoryList)
|
||||
END_CLASS
|
||||
CLASS(File)
|
||||
|
||||
@ -139,10 +139,31 @@ static void directoryListCallback(uv_fs_t* request)
|
||||
void directoryList(WrenVM* vm)
|
||||
{
|
||||
const char* path = wrenGetSlotString(vm, 1);
|
||||
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||
WrenHandle* fiber = wrenGetSlotHandle(vm, 2);
|
||||
uv_fs_t* request = createRequest(fiber);
|
||||
|
||||
// TODO: Check return.
|
||||
uv_fs_scandir(getLoop(), request, path, 0, directoryListCallback);
|
||||
int error = uv_fs_scandir(getLoop(), request, path, 0, directoryListCallback);
|
||||
if (error != 0 ) schedulerResumeError(fiber, uv_strerror(error));
|
||||
}
|
||||
|
||||
void fileDirectoryCallback(uv_fs_t* request) {
|
||||
if (handleRequestError(request)) return;
|
||||
|
||||
schedulerResume(freeRequest(request), false);
|
||||
}
|
||||
|
||||
void directoryCreate(WrenVM* vm)
|
||||
{
|
||||
const char* path = wrenGetSlotString(vm, 1);
|
||||
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||
uv_fs_mkdir(getLoop(), request, path, 0, fileDirectoryCallback);
|
||||
}
|
||||
|
||||
void directoryDelete(WrenVM* vm)
|
||||
{
|
||||
const char* path = wrenGetSlotString(vm, 1);
|
||||
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||
uv_fs_rmdir(getLoop(), request, path, fileDirectoryCallback);
|
||||
}
|
||||
|
||||
void fileAllocate(WrenVM* vm)
|
||||
@ -174,10 +195,11 @@ static void fileDeleteCallback(uv_fs_t* request)
|
||||
void fileDelete(WrenVM* vm)
|
||||
{
|
||||
const char* path = wrenGetSlotString(vm, 1);
|
||||
uv_fs_t* request = createRequest(wrenGetSlotHandle(vm, 2));
|
||||
WrenHandle* fiber = wrenGetSlotHandle(vm, 2);
|
||||
uv_fs_t* request = createRequest(fiber);
|
||||
|
||||
// TODO: Check return.
|
||||
uv_fs_unlink(getLoop(), request, path, fileDeleteCallback);
|
||||
int error = uv_fs_unlink(getLoop(), request, path, fileDeleteCallback);
|
||||
if (error != 0 ) schedulerResumeError(fiber, uv_strerror(error));
|
||||
}
|
||||
|
||||
static void fileOpenCallback(uv_fs_t* request)
|
||||
|
||||
54
src/module/io.wren
vendored
54
src/module/io.wren
vendored
@ -2,12 +2,22 @@ import "scheduler" for Scheduler
|
||||
|
||||
class Directory {
|
||||
// TODO: Copied from File. Figure out good way to share this.
|
||||
static ensurePath_(path) {
|
||||
static ensureString_(path) {
|
||||
if (!(path is String)) Fiber.abort("Path must be a string.")
|
||||
}
|
||||
|
||||
static create(path) {
|
||||
ensureString_(path)
|
||||
return Scheduler.await_ { create_(path, Fiber.current) }
|
||||
}
|
||||
|
||||
static delete(path) {
|
||||
ensureString_(path)
|
||||
return Scheduler.await_ { delete_(path, Fiber.current) }
|
||||
}
|
||||
|
||||
static exists(path) {
|
||||
ensurePath_(path)
|
||||
ensureString_(path)
|
||||
var stat
|
||||
Fiber.new {
|
||||
stat = Stat.path(path)
|
||||
@ -19,11 +29,12 @@ class Directory {
|
||||
}
|
||||
|
||||
static list(path) {
|
||||
ensurePath_(path)
|
||||
list_(path, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
ensureString_(path)
|
||||
return Scheduler.await_ { list_(path, Fiber.current) }
|
||||
}
|
||||
|
||||
foreign static create_(path, fiber)
|
||||
foreign static delete_(path, fiber)
|
||||
foreign static list_(path, fiber)
|
||||
}
|
||||
|
||||
@ -43,13 +54,12 @@ foreign class File {
|
||||
}
|
||||
|
||||
static delete(path) {
|
||||
ensurePath_(path)
|
||||
delete_(path, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
ensureString_(path)
|
||||
Scheduler.await_ { delete_(path, Fiber.current) }
|
||||
}
|
||||
|
||||
static exists(path) {
|
||||
ensurePath_(path)
|
||||
ensureString_(path)
|
||||
var stat
|
||||
Fiber.new {
|
||||
stat = Stat.path(path)
|
||||
@ -67,7 +77,7 @@ foreign class File {
|
||||
// TODO: Add named parameters and then call this "open(_,flags:_)"?
|
||||
// TODO: Test.
|
||||
static openWithFlags(path, flags) {
|
||||
ensurePath_(path)
|
||||
ensureString_(path)
|
||||
ensureInt_(flags, "Flags")
|
||||
open_(path, flags, Fiber.current)
|
||||
var fd = Scheduler.runNextScheduled_()
|
||||
@ -94,15 +104,13 @@ foreign class File {
|
||||
// TODO: This works for directories too, so putting it on File is kind of
|
||||
// lame. Consider reorganizing these classes some.
|
||||
static realPath(path) {
|
||||
ensurePath_(path)
|
||||
realPath_(path, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
ensureString_(path)
|
||||
return Scheduler.await_ { realPath_(path, Fiber.current) }
|
||||
}
|
||||
|
||||
static size(path) {
|
||||
ensurePath_(path)
|
||||
sizePath_(path, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
ensureString_(path)
|
||||
return Scheduler.await_ { sizePath_(path, Fiber.current) }
|
||||
}
|
||||
|
||||
construct new_(fd) {}
|
||||
@ -118,14 +126,12 @@ foreign class File {
|
||||
|
||||
size {
|
||||
ensureOpen_()
|
||||
size_(Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
return Scheduler.await_ { size_(Fiber.current) }
|
||||
}
|
||||
|
||||
stat {
|
||||
ensureOpen_()
|
||||
stat_(Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
return Scheduler.await_ { stat_(Fiber.current) }
|
||||
}
|
||||
|
||||
readBytes(count) { readBytes(count, 0) }
|
||||
@ -135,8 +141,7 @@ foreign class File {
|
||||
File.ensureInt_(count, "Count")
|
||||
File.ensureInt_(offset, "Offset")
|
||||
|
||||
readBytes_(count, offset, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
return Scheduler.await_ { readBytes_(count, offset, Fiber.current) }
|
||||
}
|
||||
|
||||
writeBytes(bytes) { writeBytes(bytes, size) }
|
||||
@ -146,15 +151,14 @@ foreign class File {
|
||||
if (!(bytes is String)) Fiber.abort("Bytes must be a string.")
|
||||
File.ensureInt_(offset, "Offset")
|
||||
|
||||
writeBytes_(bytes, offset, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
return Scheduler.await_ { writeBytes_(bytes, offset, Fiber.current) }
|
||||
}
|
||||
|
||||
ensureOpen_() {
|
||||
if (!isOpen) Fiber.abort("File is not open.")
|
||||
}
|
||||
|
||||
static ensurePath_(path) {
|
||||
static ensureString_(path) {
|
||||
if (!(path is String)) Fiber.abort("Path must be a string.")
|
||||
}
|
||||
|
||||
|
||||
@ -6,12 +6,22 @@ static const char* ioModuleSource =
|
||||
"\n"
|
||||
"class Directory {\n"
|
||||
" // TODO: Copied from File. Figure out good way to share this.\n"
|
||||
" static ensurePath_(path) {\n"
|
||||
" static ensureString_(path) {\n"
|
||||
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static create(path) {\n"
|
||||
" ensureString_(path)\n"
|
||||
" return Scheduler.await_ { create_(path, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static delete(path) {\n"
|
||||
" ensureString_(path)\n"
|
||||
" return Scheduler.await_ { delete_(path, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static exists(path) {\n"
|
||||
" ensurePath_(path)\n"
|
||||
" ensureString_(path)\n"
|
||||
" var stat\n"
|
||||
" Fiber.new {\n"
|
||||
" stat = Stat.path(path)\n"
|
||||
@ -23,11 +33,12 @@ static const char* ioModuleSource =
|
||||
" }\n"
|
||||
"\n"
|
||||
" static list(path) {\n"
|
||||
" ensurePath_(path)\n"
|
||||
" list_(path, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" ensureString_(path)\n"
|
||||
" return Scheduler.await_ { list_(path, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static create_(path, fiber)\n"
|
||||
" foreign static delete_(path, fiber)\n"
|
||||
" foreign static list_(path, fiber)\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
@ -47,13 +58,12 @@ static const char* ioModuleSource =
|
||||
" }\n"
|
||||
"\n"
|
||||
" static delete(path) {\n"
|
||||
" ensurePath_(path)\n"
|
||||
" delete_(path, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" ensureString_(path)\n"
|
||||
" Scheduler.await_ { delete_(path, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static exists(path) {\n"
|
||||
" ensurePath_(path)\n"
|
||||
" ensureString_(path)\n"
|
||||
" var stat\n"
|
||||
" Fiber.new {\n"
|
||||
" stat = Stat.path(path)\n"
|
||||
@ -71,7 +81,7 @@ static const char* ioModuleSource =
|
||||
" // TODO: Add named parameters and then call this \"open(_,flags:_)\"?\n"
|
||||
" // TODO: Test.\n"
|
||||
" static openWithFlags(path, flags) {\n"
|
||||
" ensurePath_(path)\n"
|
||||
" ensureString_(path)\n"
|
||||
" ensureInt_(flags, \"Flags\")\n"
|
||||
" open_(path, flags, Fiber.current)\n"
|
||||
" var fd = Scheduler.runNextScheduled_()\n"
|
||||
@ -98,15 +108,13 @@ static const char* ioModuleSource =
|
||||
" // TODO: This works for directories too, so putting it on File is kind of\n"
|
||||
" // lame. Consider reorganizing these classes some.\n"
|
||||
" static realPath(path) {\n"
|
||||
" ensurePath_(path)\n"
|
||||
" realPath_(path, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" ensureString_(path)\n"
|
||||
" return Scheduler.await_ { realPath_(path, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static size(path) {\n"
|
||||
" ensurePath_(path)\n"
|
||||
" sizePath_(path, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" ensureString_(path)\n"
|
||||
" return Scheduler.await_ { sizePath_(path, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" construct new_(fd) {}\n"
|
||||
@ -122,14 +130,12 @@ static const char* ioModuleSource =
|
||||
"\n"
|
||||
" size {\n"
|
||||
" ensureOpen_()\n"
|
||||
" size_(Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" return Scheduler.await_ { size_(Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" stat {\n"
|
||||
" ensureOpen_()\n"
|
||||
" stat_(Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" return Scheduler.await_ { stat_(Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" readBytes(count) { readBytes(count, 0) }\n"
|
||||
@ -139,8 +145,7 @@ static const char* ioModuleSource =
|
||||
" File.ensureInt_(count, \"Count\")\n"
|
||||
" File.ensureInt_(offset, \"Offset\")\n"
|
||||
"\n"
|
||||
" readBytes_(count, offset, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" return Scheduler.await_ { readBytes_(count, offset, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" writeBytes(bytes) { writeBytes(bytes, size) }\n"
|
||||
@ -150,15 +155,14 @@ static const char* ioModuleSource =
|
||||
" if (!(bytes is String)) Fiber.abort(\"Bytes must be a string.\")\n"
|
||||
" File.ensureInt_(offset, \"Offset\")\n"
|
||||
"\n"
|
||||
" writeBytes_(bytes, offset, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" return Scheduler.await_ { writeBytes_(bytes, offset, Fiber.current) }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" ensureOpen_() {\n"
|
||||
" if (!isOpen) Fiber.abort(\"File is not open.\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static ensurePath_(path) {\n"
|
||||
" static ensureString_(path) {\n"
|
||||
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
|
||||
6
src/module/scheduler.wren
vendored
6
src/module/scheduler.wren
vendored
@ -13,6 +13,12 @@ class Scheduler {
|
||||
static resume_(fiber, arg) { fiber.transfer(arg) }
|
||||
static resumeError_(fiber, error) { fiber.transferError(error) }
|
||||
|
||||
// wait for a method to finish that has a callback on the C side
|
||||
static await_(fn) {
|
||||
fn.call()
|
||||
return Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
static runNextScheduled_() {
|
||||
if (__scheduled == null || __scheduled.isEmpty) {
|
||||
return Fiber.suspend()
|
||||
|
||||
@ -17,6 +17,12 @@ static const char* schedulerModuleSource =
|
||||
" static resume_(fiber, arg) { fiber.transfer(arg) }\n"
|
||||
" static resumeError_(fiber, error) { fiber.transferError(error) }\n"
|
||||
"\n"
|
||||
" // wait for a method to finish that has a callback on the C side\n"
|
||||
" static await_(fn) {\n"
|
||||
" fn.call()\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static runNextScheduled_() {\n"
|
||||
" if (__scheduled == null || __scheduled.isEmpty) {\n"
|
||||
" return Fiber.suspend()\n"
|
||||
|
||||
23
test/io/directory/create_delete.wren
vendored
Normal file
23
test/io/directory/create_delete.wren
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
import "io" for Directory, Stat
|
||||
import "os" for Platform
|
||||
|
||||
if (Directory.exists("tmp")) {
|
||||
Directory.delete("tmp")
|
||||
}
|
||||
|
||||
System.print(Directory.exists("tmp")) // expect: false
|
||||
Directory.create("tmp")
|
||||
System.print(Directory.exists("tmp")) // expect: true
|
||||
|
||||
// Windows does not support mode
|
||||
if (Platform.isPosix) {
|
||||
var stat = Stat.path("tmp")
|
||||
// 511 is 0755
|
||||
System.print(stat.mode && 0x1ff) // expect: 511
|
||||
}
|
||||
|
||||
Directory.delete("tmp")
|
||||
System.print(Directory.exists("tmp")) // expect: false
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user