1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-28 16:20:57 -05:00

Add remove(), removeAll().

and removeSync(), removeAllSync().
This commit is contained in:
Kevin (Kun) "Kassimo" Qian 2018-09-10 20:40:03 -07:00 committed by Ryan Dahl
parent 7c50c11f40
commit 1ffae65165
8 changed files with 441 additions and 7 deletions

View file

@ -47,6 +47,7 @@ main_extern = [
"$rust_build:rand",
"$rust_build:tokio",
"$rust_build:url",
"$rust_build:remove_dir_all",
"//build_extra/flatbuffers/rust:flatbuffers",
":msg_rs",
]
@ -198,6 +199,7 @@ run_node("gen_declarations") {
"js/mkdir.ts",
"js/os.ts",
"js/read_file.ts",
"js/remove.ts",
"js/stat.ts",
"js/text_encoding.ts",
"js/timers.ts",
@ -205,6 +207,7 @@ run_node("gen_declarations") {
"js/types.ts",
"js/util.ts",
"js/v8_source_maps.ts",
"js/write_file.ts",
]
outputs = [
"$out_dir/types/globals.d.ts",
@ -239,12 +242,14 @@ run_node("bundle") {
"js/os.ts",
"js/plugins.d.ts",
"js/read_file.ts",
"js/remove.ts",
"js/stat.ts",
"js/text_encoding.ts",
"js/timers.ts",
"js/types.ts",
"js/util.ts",
"js/v8_source_maps.ts",
"js/write_file.ts",
"rollup.config.js",
"src/msg.fbs",
"tsconfig.json",

View file

@ -1,13 +1,9 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
// Public deno module.
/// <amd-module name="deno"/>
export {
env,
exit,
makeTempDirSync,
renameSync,
} from "./os";
export { env, exit, makeTempDirSync, renameSync } from "./os";
export { mkdirSync, mkdir } from "./mkdir";
export { removeSync, remove, removeAllSync, removeAll } from "./remove";
export { readFileSync, readFile } from "./read_file";
export { FileInfo, statSync, lstatSync, stat, lstat } from "./stat";
export { writeFileSync, writeFile } from "./write_file";

63
js/remove.ts Normal file
View file

@ -0,0 +1,63 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import * as fbs from "gen/msg_generated";
import { flatbuffers } from "flatbuffers";
import * as dispatch from "./dispatch";
/**
* Removes the named file or (empty) directory synchronously.
* Would throw error if permission denied, not found, or
* directory not empty.
*
* import { removeSync } from "deno";
* removeSync("/path/to/empty_dir/or/file");
*/
export function removeSync(path: string): void {
dispatch.sendSync(...req(path, false));
}
/**
* Removes the named file or (empty) directory.
* Would throw error if permission denied, not found, or
* directory not empty.
*
* import { remove } from "deno";
* await remove("/path/to/empty_dir/or/file");
*/
export async function remove(path: string): Promise<void> {
await dispatch.sendAsync(...req(path, false));
}
/**
* Recursively removes the named file or directory synchronously.
* Would throw error if permission denied or not found
*
* import { removeAllSync } from "deno";
* removeAllSync("/path/to/dir/or/file");
*/
export function removeAllSync(path: string): void {
dispatch.sendSync(...req(path, true));
}
/**
* Recursively removes the named file or directory.
* Would throw error if permission denied or not found
*
* import { removeAll } from "deno";
* await removeAll("/path/to/dir/or/file");
*/
export async function removeAll(path: string): Promise<void> {
await dispatch.sendAsync(...req(path, true));
}
function req(
path: string,
recursive: boolean
): [flatbuffers.Builder, fbs.Any, flatbuffers.Offset] {
const builder = new flatbuffers.Builder();
const path_ = builder.createString(path);
fbs.Remove.startRemove(builder);
fbs.Remove.addPath(builder, path_);
fbs.Remove.addRecursive(builder, recursive);
const msg = fbs.Remove.endRemove(builder);
return [builder, fbs.Any.Remove, msg];
}

336
js/remove_test.ts Normal file
View file

@ -0,0 +1,336 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
import { testPerm, assert, assertEqual } from "./test_util.ts";
import * as deno from "deno";
// SYNC
testPerm({ write: true }, function removeSyncDirSuccess() {
// REMOVE EMPTY DIRECTORY
const path = deno.makeTempDirSync() + "/dir/subdir";
deno.mkdirSync(path);
const pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
deno.removeSync(path); // remove
// We then check again after remove
let err;
try {
deno.statSync(path);
} catch (e) {
err = e;
}
// Directory is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, function removeSyncFileSuccess() {
// REMOVE FILE
const enc = new TextEncoder();
const data = enc.encode("Hello");
const filename = deno.makeTempDirSync() + "/test.txt";
deno.writeFileSync(filename, data, 0o666);
const fileInfo = deno.statSync(filename);
assert(fileInfo.isFile()); // check exist first
deno.removeSync(filename); // remove
// We then check again after remove
let err;
try {
deno.statSync(filename);
} catch (e) {
err = e;
}
// File is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, function removeSyncFail() {
// NON-EMPTY DIRECTORY
const path = deno.makeTempDirSync() + "/dir/subdir";
const subPath = path + "/subsubdir";
deno.mkdirSync(path);
deno.mkdirSync(subPath);
const pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
const subPathInfo = deno.statSync(subPath);
assert(subPathInfo.isDirectory()); // check exist first
let err;
try {
// Should not be able to recursively remove
deno.removeSync(path);
} catch (e) {
err = e;
}
// TODO(ry) Is Other really the error we should get here? What would Go do?
assertEqual(err.kind, deno.ErrorKind.Other);
assertEqual(err.name, "Other");
// NON-EXISTENT DIRECTORY/FILE
try {
// Non-existent
deno.removeSync("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: false }, function removeSyncPerm() {
let err;
try {
deno.removeSync("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
assertEqual(err.name, "PermissionDenied");
});
testPerm({ write: true }, function removeAllSyncDirSuccess() {
// REMOVE EMPTY DIRECTORY
let path = deno.makeTempDirSync() + "/dir/subdir";
deno.mkdirSync(path);
let pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
deno.removeAllSync(path); // remove
// We then check again after remove
let err;
try {
deno.statSync(path);
} catch (e) {
err = e;
}
// Directory is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
// REMOVE NON-EMPTY DIRECTORY
path = deno.makeTempDirSync() + "/dir/subdir";
const subPath = path + "/subsubdir";
deno.mkdirSync(path);
deno.mkdirSync(subPath);
pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
const subPathInfo = deno.statSync(subPath);
assert(subPathInfo.isDirectory()); // check exist first
deno.removeAllSync(path); // remove
// We then check parent directory again after remove
try {
deno.statSync(path);
} catch (e) {
err = e;
}
// Directory is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, function removeAllSyncFileSuccess() {
// REMOVE FILE
const enc = new TextEncoder();
const data = enc.encode("Hello");
const filename = deno.makeTempDirSync() + "/test.txt";
deno.writeFileSync(filename, data, 0o666);
const fileInfo = deno.statSync(filename);
assert(fileInfo.isFile()); // check exist first
deno.removeAllSync(filename); // remove
// We then check again after remove
let err;
try {
deno.statSync(filename);
} catch (e) {
err = e;
}
// File is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, function removeAllSyncFail() {
// NON-EXISTENT DIRECTORY/FILE
let err;
try {
// Non-existent
deno.removeAllSync("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: false }, function removeAllSyncPerm() {
let err;
try {
deno.removeAllSync("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
assertEqual(err.name, "PermissionDenied");
});
// ASYNC
testPerm({ write: true }, async function removeDirSuccess() {
// REMOVE EMPTY DIRECTORY
const path = deno.makeTempDirSync() + "/dir/subdir";
deno.mkdirSync(path);
const pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
await deno.remove(path); // remove
// We then check again after remove
let err;
try {
deno.statSync(path);
} catch (e) {
err = e;
}
// Directory is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, async function removeFileSuccess() {
// REMOVE FILE
const enc = new TextEncoder();
const data = enc.encode("Hello");
const filename = deno.makeTempDirSync() + "/test.txt";
deno.writeFileSync(filename, data, 0o666);
const fileInfo = deno.statSync(filename);
assert(fileInfo.isFile()); // check exist first
await deno.remove(filename); // remove
// We then check again after remove
let err;
try {
deno.statSync(filename);
} catch (e) {
err = e;
}
// File is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, async function removeFail() {
// NON-EMPTY DIRECTORY
const path = deno.makeTempDirSync() + "/dir/subdir";
const subPath = path + "/subsubdir";
deno.mkdirSync(path);
deno.mkdirSync(subPath);
const pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
const subPathInfo = deno.statSync(subPath);
assert(subPathInfo.isDirectory()); // check exist first
let err;
try {
// Should not be able to recursively remove
await deno.remove(path);
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.Other);
assertEqual(err.name, "Other");
// NON-EXISTENT DIRECTORY/FILE
try {
// Non-existent
await deno.remove("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: false }, async function removePerm() {
let err;
try {
await deno.remove("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
assertEqual(err.name, "PermissionDenied");
});
testPerm({ write: true }, async function removeAllDirSuccess() {
// REMOVE EMPTY DIRECTORY
let path = deno.makeTempDirSync() + "/dir/subdir";
deno.mkdirSync(path);
let pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
await deno.removeAll(path); // remove
// We then check again after remove
let err;
try {
deno.statSync(path);
} catch (e) {
err = e;
}
// Directory is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
// REMOVE NON-EMPTY DIRECTORY
path = deno.makeTempDirSync() + "/dir/subdir";
const subPath = path + "/subsubdir";
deno.mkdirSync(path);
deno.mkdirSync(subPath);
pathInfo = deno.statSync(path);
assert(pathInfo.isDirectory()); // check exist first
const subPathInfo = deno.statSync(subPath);
assert(subPathInfo.isDirectory()); // check exist first
await deno.removeAll(path); // remove
// We then check parent directory again after remove
try {
deno.statSync(path);
} catch (e) {
err = e;
}
// Directory is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, async function removeAllFileSuccess() {
// REMOVE FILE
const enc = new TextEncoder();
const data = enc.encode("Hello");
const filename = deno.makeTempDirSync() + "/test.txt";
deno.writeFileSync(filename, data, 0o666);
const fileInfo = deno.statSync(filename);
assert(fileInfo.isFile()); // check exist first
await deno.removeAll(filename); // remove
// We then check again after remove
let err;
try {
deno.statSync(filename);
} catch (e) {
err = e;
}
// File is gone
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: true }, async function removeAllFail() {
// NON-EXISTENT DIRECTORY/FILE
let err;
try {
// Non-existent
await deno.removeAll("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.NotFound);
assertEqual(err.name, "NotFound");
});
testPerm({ write: false }, async function removeAllPerm() {
let err;
try {
await deno.removeAll("/baddir");
} catch (e) {
err = e;
}
assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
assertEqual(err.name, "PermissionDenied");
});

View file

@ -123,4 +123,3 @@ test(async function lstatNotFound() {
assert(caughtError);
assertEqual(badInfo, undefined);
});

View file

@ -12,6 +12,7 @@ use hyper::Client;
use libdeno;
use libdeno::{deno_buf, DenoC};
use msg;
use remove_dir_all::remove_dir_all;
use std;
use std::fs;
use std::path::Path;
@ -50,6 +51,7 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) {
msg::Any::TimerClear => handle_timer_clear,
msg::Any::MakeTempDir => handle_make_temp_dir,
msg::Any::Mkdir => handle_mkdir,
msg::Any::Remove => handle_remove,
msg::Any::ReadFile => handle_read_file,
msg::Any::RenameSync => handle_rename_sync,
msg::Any::SetEnv => handle_set_env,
@ -435,6 +437,32 @@ fn handle_mkdir(d: *const DenoC, base: &msg::Base) -> Box<Op> {
}()))
}
fn handle_remove(d: *const DenoC, base: &msg::Base) -> Box<Op> {
let msg = base.msg_as_remove().unwrap();
let path = msg.path().unwrap();
let recursive = msg.recursive();
let deno = from_c(d);
if !deno.flags.allow_write {
return odd_future(permission_denied());
}
// TODO Use tokio_threadpool.
Box::new(futures::future::result(|| -> OpResult {
debug!("handle_remove {}", path);
let path_ = Path::new(&path);
let metadata = fs::metadata(&path_)?;
if metadata.is_file() {
fs::remove_file(&path_)?;
} else {
if recursive {
remove_dir_all(&path_)?;
} else {
fs::remove_dir(&path_)?;
}
}
Ok(None)
}()))
}
// Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184
fn handle_read_file(_d: *const DenoC, base: &msg::Base) -> Box<Op> {
let msg = base.msg_as_read_file().unwrap();

View file

@ -10,6 +10,7 @@ extern crate url;
#[macro_use]
extern crate log;
extern crate hyper_rustls;
extern crate remove_dir_all;
extern crate ring;
mod deno_dir;

View file

@ -15,6 +15,7 @@ union Any {
MakeTempDir,
MakeTempDirRes,
Mkdir,
Remove,
ReadFile,
ReadFileRes,
WriteFile,
@ -173,6 +174,11 @@ table Mkdir {
// mode specified by https://godoc.org/os#FileMode
}
table Remove {
path: string;
recursive: bool;
}
table ReadFile {
filename: string;
}