More file system checking functions:
- Stat#isFile - Stat#isDirectory - Directory.exists() - File.exists()
This commit is contained in:
parent
c6148f8941
commit
60162575ee
@ -4,6 +4,11 @@ A directory on the file system.
|
|||||||
|
|
||||||
## Static Methods
|
## Static Methods
|
||||||
|
|
||||||
|
### Directory.**exists**(path)
|
||||||
|
|
||||||
|
Whether a directory exists at `path`. This returns `false` for files or other
|
||||||
|
special file system entities.
|
||||||
|
|
||||||
### Directory.**list**(path)
|
### Directory.**list**(path)
|
||||||
|
|
||||||
Lists the contents of the directory at `path`. Returns a sorted list of path
|
Lists the contents of the directory at `path`. Returns a sorted list of path
|
||||||
|
|||||||
@ -25,6 +25,11 @@ automatically closed.
|
|||||||
|
|
||||||
Deletes the file at `path`.
|
Deletes the file at `path`.
|
||||||
|
|
||||||
|
### File.**exists**(path)
|
||||||
|
|
||||||
|
Whether a regular file exists at `path`. This returns `false` for directories
|
||||||
|
or other special file system entities.
|
||||||
|
|
||||||
### File.**open**(path, fn)
|
### File.**open**(path, fn)
|
||||||
|
|
||||||
Opens the file at `path` for reading and passes it to `fn`. After the function
|
Opens the file at `path` for reading and passes it to `fn`. After the function
|
||||||
|
|||||||
@ -10,45 +10,54 @@ A data structure describing the low-level details of a file system entry.
|
|||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
### **blockCount**
|
||||||
|
|
||||||
|
The number of system blocks allocated on disk for the file.
|
||||||
|
|
||||||
|
### **blockSize**
|
||||||
|
|
||||||
|
The preferred block size in bytes for interacting with the file. It may vary
|
||||||
|
from file to file.
|
||||||
|
|
||||||
### **device**
|
### **device**
|
||||||
|
|
||||||
The ID of the device containing the entry.
|
The ID of the device containing the entry.
|
||||||
|
|
||||||
|
### **group**
|
||||||
|
|
||||||
|
Numeric group ID of the file's owner.
|
||||||
|
|
||||||
### **inode**
|
### **inode**
|
||||||
|
|
||||||
The [inode][] number of the entry.
|
The [inode][] number of the entry.
|
||||||
|
|
||||||
[inode]: https://en.wikipedia.org/wiki/Inode
|
[inode]: https://en.wikipedia.org/wiki/Inode
|
||||||
|
|
||||||
### **mode**
|
### **isDirectory**
|
||||||
|
|
||||||
A bit field describing the entry's type and protection flags.
|
Whether the file system entity is a directory.
|
||||||
|
|
||||||
|
### **isFile**
|
||||||
|
|
||||||
|
Whether the file system entity is a regular file, as opposed to a directory or
|
||||||
|
other special entity.
|
||||||
|
|
||||||
### **linkCount**
|
### **linkCount**
|
||||||
|
|
||||||
The number of hard links to the entry.
|
The number of hard links to the entry.
|
||||||
|
|
||||||
### **user**
|
### **mode**
|
||||||
|
|
||||||
Numeric user ID of the file's owner.
|
A bit field describing the entry's type and protection flags.
|
||||||
|
|
||||||
### **group**
|
|
||||||
|
|
||||||
Numeric group ID of the file's owner.
|
|
||||||
|
|
||||||
### **specialDevice**
|
|
||||||
|
|
||||||
The device ID for the entry, if it's a special file.
|
|
||||||
|
|
||||||
### **size**
|
### **size**
|
||||||
|
|
||||||
The size of the entry in bytes.
|
The size of the entry in bytes.
|
||||||
|
|
||||||
### **blockSize**
|
### **specialDevice**
|
||||||
|
|
||||||
The preferred block size in bytes for interacting with the file. It may vary
|
The device ID for the entry, if it's a special file.
|
||||||
from file to file.
|
|
||||||
|
|
||||||
### **blockCount**
|
### **user**
|
||||||
|
|
||||||
The number of system blocks allocated on disk for the file.
|
Numeric user ID of the file's owner.
|
||||||
|
|||||||
@ -32,6 +32,8 @@ extern void statMode(WrenVM* vm);
|
|||||||
extern void statSize(WrenVM* vm);
|
extern void statSize(WrenVM* vm);
|
||||||
extern void statSpecialDevice(WrenVM* vm);
|
extern void statSpecialDevice(WrenVM* vm);
|
||||||
extern void statUser(WrenVM* vm);
|
extern void statUser(WrenVM* vm);
|
||||||
|
extern void statIsDirectory(WrenVM* vm);
|
||||||
|
extern void statIsFile(WrenVM* vm);
|
||||||
extern void stdinReadStart(WrenVM* vm);
|
extern void stdinReadStart(WrenVM* vm);
|
||||||
extern void stdinReadStop(WrenVM* vm);
|
extern void stdinReadStop(WrenVM* vm);
|
||||||
extern void schedulerCaptureMethods(WrenVM* vm);
|
extern void schedulerCaptureMethods(WrenVM* vm);
|
||||||
@ -45,7 +47,7 @@ extern void timerStartTimer(WrenVM* vm);
|
|||||||
// If you add a new method to the longest class below, make sure to bump this.
|
// If you add a new method to the longest class below, make sure to bump this.
|
||||||
// Note that it also includes an extra slot for the sentinel value indicating
|
// Note that it also includes an extra slot for the sentinel value indicating
|
||||||
// the end of the list.
|
// the end of the list.
|
||||||
#define MAX_METHODS_PER_CLASS 12
|
#define MAX_METHODS_PER_CLASS 14
|
||||||
|
|
||||||
// The maximum number of foreign classes a single built-in module defines.
|
// The maximum number of foreign classes a single built-in module defines.
|
||||||
//
|
//
|
||||||
@ -133,6 +135,8 @@ static ModuleRegistry modules[] =
|
|||||||
METHOD("size", statSize)
|
METHOD("size", statSize)
|
||||||
METHOD("specialDevice", statSpecialDevice)
|
METHOD("specialDevice", statSpecialDevice)
|
||||||
METHOD("user", statUser)
|
METHOD("user", statUser)
|
||||||
|
METHOD("isDirectory", statIsDirectory)
|
||||||
|
METHOD("isFile", statIsFile)
|
||||||
END_CLASS
|
END_CLASS
|
||||||
CLASS(Stdin)
|
CLASS(Stdin)
|
||||||
STATIC_METHOD("readStart_()", stdinReadStart)
|
STATIC_METHOD("readStart_()", stdinReadStart)
|
||||||
|
|||||||
@ -442,6 +442,18 @@ void statUser(WrenVM* vm)
|
|||||||
wrenSetSlotDouble(vm, 0, (double)stat->st_uid);
|
wrenSetSlotDouble(vm, 0, (double)stat->st_uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void statIsDirectory(WrenVM* vm)
|
||||||
|
{
|
||||||
|
uv_stat_t* stat = (uv_stat_t*)wrenGetSlotForeign(vm, 0);
|
||||||
|
wrenSetSlotBool(vm, 0, S_ISDIR(stat->st_mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void statIsFile(WrenVM* vm)
|
||||||
|
{
|
||||||
|
uv_stat_t* stat = (uv_stat_t*)wrenGetSlotForeign(vm, 0);
|
||||||
|
wrenSetSlotBool(vm, 0, S_ISREG(stat->st_mode));
|
||||||
|
}
|
||||||
|
|
||||||
static void allocCallback(uv_handle_t* handle, size_t suggestedSize,
|
static void allocCallback(uv_handle_t* handle, size_t suggestedSize,
|
||||||
uv_buf_t* buf)
|
uv_buf_t* buf)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,6 +6,18 @@ class Directory {
|
|||||||
if (!(path is String)) Fiber.abort("Path must be a string.")
|
if (!(path is String)) Fiber.abort("Path must be a string.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static exists(path) {
|
||||||
|
ensurePath_(path)
|
||||||
|
var stat
|
||||||
|
Fiber.new {
|
||||||
|
stat = Stat.path(path)
|
||||||
|
}.try()
|
||||||
|
|
||||||
|
// If we can't stat it, there's nothing there.
|
||||||
|
if (stat == null) return false
|
||||||
|
return stat.isDirectory
|
||||||
|
}
|
||||||
|
|
||||||
static list(path) {
|
static list(path) {
|
||||||
ensurePath_(path)
|
ensurePath_(path)
|
||||||
list_(path, Fiber.current)
|
list_(path, Fiber.current)
|
||||||
@ -31,11 +43,23 @@ foreign class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static delete(path) {
|
static delete(path) {
|
||||||
File.ensurePath_(path)
|
ensurePath_(path)
|
||||||
delete_(path, Fiber.current)
|
delete_(path, Fiber.current)
|
||||||
return Scheduler.runNextScheduled_()
|
return Scheduler.runNextScheduled_()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static exists(path) {
|
||||||
|
ensurePath_(path)
|
||||||
|
var stat
|
||||||
|
Fiber.new {
|
||||||
|
stat = Stat.path(path)
|
||||||
|
}.try()
|
||||||
|
|
||||||
|
// If we can't stat it, there's nothing there.
|
||||||
|
if (stat == null) return false
|
||||||
|
return stat.isFile
|
||||||
|
}
|
||||||
|
|
||||||
static open(path) { openWithFlags(path, FileFlags.readOnly) }
|
static open(path) { openWithFlags(path, FileFlags.readOnly) }
|
||||||
|
|
||||||
static open(path, fn) { openWithFlags(path, FileFlags.readOnly, fn) }
|
static open(path, fn) { openWithFlags(path, FileFlags.readOnly, fn) }
|
||||||
@ -43,8 +67,8 @@ foreign class File {
|
|||||||
// TODO: Add named parameters and then call this "open(_,flags:_)"?
|
// TODO: Add named parameters and then call this "open(_,flags:_)"?
|
||||||
// TODO: Test.
|
// TODO: Test.
|
||||||
static openWithFlags(path, flags) {
|
static openWithFlags(path, flags) {
|
||||||
File.ensurePath_(path)
|
ensurePath_(path)
|
||||||
File.ensureInt_(flags, "Flags")
|
ensureInt_(flags, "Flags")
|
||||||
open_(path, flags, Fiber.current)
|
open_(path, flags, Fiber.current)
|
||||||
var fd = Scheduler.runNextScheduled_()
|
var fd = Scheduler.runNextScheduled_()
|
||||||
return new_(fd)
|
return new_(fd)
|
||||||
@ -68,7 +92,7 @@ foreign class File {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static size(path) {
|
static size(path) {
|
||||||
File.ensurePath_(path)
|
ensurePath_(path)
|
||||||
sizePath_(path, Fiber.current)
|
sizePath_(path, Fiber.current)
|
||||||
return Scheduler.runNextScheduled_()
|
return Scheduler.runNextScheduled_()
|
||||||
}
|
}
|
||||||
@ -175,6 +199,10 @@ foreign class Stat {
|
|||||||
foreign size
|
foreign size
|
||||||
foreign specialDevice
|
foreign specialDevice
|
||||||
foreign user
|
foreign user
|
||||||
|
|
||||||
|
foreign isFile
|
||||||
|
foreign isDirectory
|
||||||
|
// TODO: Other mode checks.
|
||||||
}
|
}
|
||||||
|
|
||||||
class Stdin {
|
class Stdin {
|
||||||
|
|||||||
@ -8,6 +8,18 @@ static const char* ioModuleSource =
|
|||||||
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" static exists(path) {\n"
|
||||||
|
" ensurePath_(path)\n"
|
||||||
|
" var stat\n"
|
||||||
|
" Fiber.new {\n"
|
||||||
|
" stat = Stat.path(path)\n"
|
||||||
|
" }.try()\n"
|
||||||
|
"\n"
|
||||||
|
" // If we can't stat it, there's nothing there.\n"
|
||||||
|
" if (stat == null) return false\n"
|
||||||
|
" return stat.isDirectory\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
" static list(path) {\n"
|
" static list(path) {\n"
|
||||||
" ensurePath_(path)\n"
|
" ensurePath_(path)\n"
|
||||||
" list_(path, Fiber.current)\n"
|
" list_(path, Fiber.current)\n"
|
||||||
@ -33,11 +45,23 @@ static const char* ioModuleSource =
|
|||||||
" }\n"
|
" }\n"
|
||||||
"\n"
|
"\n"
|
||||||
" static delete(path) {\n"
|
" static delete(path) {\n"
|
||||||
" File.ensurePath_(path)\n"
|
" ensurePath_(path)\n"
|
||||||
" delete_(path, Fiber.current)\n"
|
" delete_(path, Fiber.current)\n"
|
||||||
" return Scheduler.runNextScheduled_()\n"
|
" return Scheduler.runNextScheduled_()\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
" static exists(path) {\n"
|
||||||
|
" ensurePath_(path)\n"
|
||||||
|
" var stat\n"
|
||||||
|
" Fiber.new {\n"
|
||||||
|
" stat = Stat.path(path)\n"
|
||||||
|
" }.try()\n"
|
||||||
|
"\n"
|
||||||
|
" // If we can't stat it, there's nothing there.\n"
|
||||||
|
" if (stat == null) return false\n"
|
||||||
|
" return stat.isFile\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
" static open(path) { openWithFlags(path, FileFlags.readOnly) }\n"
|
" static open(path) { openWithFlags(path, FileFlags.readOnly) }\n"
|
||||||
"\n"
|
"\n"
|
||||||
" static open(path, fn) { openWithFlags(path, FileFlags.readOnly, fn) }\n"
|
" static open(path, fn) { openWithFlags(path, FileFlags.readOnly, fn) }\n"
|
||||||
@ -45,8 +69,8 @@ static const char* ioModuleSource =
|
|||||||
" // TODO: Add named parameters and then call this \"open(_,flags:_)\"?\n"
|
" // TODO: Add named parameters and then call this \"open(_,flags:_)\"?\n"
|
||||||
" // TODO: Test.\n"
|
" // TODO: Test.\n"
|
||||||
" static openWithFlags(path, flags) {\n"
|
" static openWithFlags(path, flags) {\n"
|
||||||
" File.ensurePath_(path)\n"
|
" ensurePath_(path)\n"
|
||||||
" File.ensureInt_(flags, \"Flags\")\n"
|
" ensureInt_(flags, \"Flags\")\n"
|
||||||
" open_(path, flags, Fiber.current)\n"
|
" open_(path, flags, Fiber.current)\n"
|
||||||
" var fd = Scheduler.runNextScheduled_()\n"
|
" var fd = Scheduler.runNextScheduled_()\n"
|
||||||
" return new_(fd)\n"
|
" return new_(fd)\n"
|
||||||
@ -70,7 +94,7 @@ static const char* ioModuleSource =
|
|||||||
" }\n"
|
" }\n"
|
||||||
"\n"
|
"\n"
|
||||||
" static size(path) {\n"
|
" static size(path) {\n"
|
||||||
" File.ensurePath_(path)\n"
|
" ensurePath_(path)\n"
|
||||||
" sizePath_(path, Fiber.current)\n"
|
" sizePath_(path, Fiber.current)\n"
|
||||||
" return Scheduler.runNextScheduled_()\n"
|
" return Scheduler.runNextScheduled_()\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
@ -177,6 +201,10 @@ static const char* ioModuleSource =
|
|||||||
" foreign size\n"
|
" foreign size\n"
|
||||||
" foreign specialDevice\n"
|
" foreign specialDevice\n"
|
||||||
" foreign user\n"
|
" foreign user\n"
|
||||||
|
"\n"
|
||||||
|
" foreign isFile\n"
|
||||||
|
" foreign isDirectory\n"
|
||||||
|
" // TODO: Other mode checks.\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"class Stdin {\n"
|
"class Stdin {\n"
|
||||||
|
|||||||
9
test/io/directory/exists.wren
Normal file
9
test/io/directory/exists.wren
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import "io" for Directory
|
||||||
|
|
||||||
|
System.print(Directory.exists("test/io/file")) // expect: true
|
||||||
|
System.print(Directory.exists("nonexistent")) // expect: false
|
||||||
|
|
||||||
|
// Files are not directories.
|
||||||
|
System.print(Directory.exists("test/io/file/file.txt")) // expect: false
|
||||||
|
|
||||||
|
// TODO: Symlinks.
|
||||||
3
test/io/directory/exists_path_not_string.wren
Normal file
3
test/io/directory/exists_path_not_string.wren
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import "io" for Directory
|
||||||
|
|
||||||
|
Directory.exists(123) // expect runtime error: Path must be a string.
|
||||||
9
test/io/file/exists.wren
Normal file
9
test/io/file/exists.wren
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import "io" for File
|
||||||
|
|
||||||
|
System.print(File.exists("test/io/file/file.txt")) // expect: true
|
||||||
|
System.print(File.exists("nonexistent")) // expect: false
|
||||||
|
|
||||||
|
// Directories are not files.
|
||||||
|
System.print(File.exists("test/io/file")) // expect: false
|
||||||
|
|
||||||
|
// TODO: Symlinks.
|
||||||
3
test/io/file/exists_path_not_string.wren
Normal file
3
test/io/file/exists_path_not_string.wren
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import "io" for File
|
||||||
|
|
||||||
|
File.exists(123) // expect runtime error: Path must be a string.
|
||||||
4
test/io/stat/is_directory.wren
Normal file
4
test/io/stat/is_directory.wren
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import "io" for Stat
|
||||||
|
|
||||||
|
System.print(Stat.path("test/io/file/file.txt").isDirectory) // expect: false
|
||||||
|
System.print(Stat.path("test").isDirectory) // expect: true
|
||||||
4
test/io/stat/is_file.wren
Normal file
4
test/io/stat/is_file.wren
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import "io" for Stat
|
||||||
|
|
||||||
|
System.print(Stat.path("test/io/file/file.txt").isFile) // expect: true
|
||||||
|
System.print(Stat.path("test").isFile) // expect: false
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import "io" for Stat
|
import "io" for Stat
|
||||||
import "scheduler" for Scheduler
|
|
||||||
|
|
||||||
var stat = Stat.path("test/io/file/file.txt")
|
var stat = Stat.path("test/io/file/file.txt")
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import "io" for Stat
|
import "io" for Stat
|
||||||
import "scheduler" for Scheduler
|
|
||||||
|
|
||||||
var stat = Stat.path("test/io/directory/dir")
|
var stat = Stat.path("test/io/directory/dir")
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user