mirror of
https://github.com/denoland/deno.git
synced 2024-12-26 17:19:06 -05:00
Add remove(), removeAll().
and removeSync(), removeAllSync().
This commit is contained in:
parent
7c50c11f40
commit
1ffae65165
8 changed files with 441 additions and 7 deletions
5
BUILD.gn
5
BUILD.gn
|
@ -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",
|
||||
|
|
|
@ -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
63
js/remove.ts
Normal 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
336
js/remove_test.ts
Normal 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");
|
||||
});
|
|
@ -123,4 +123,3 @@ test(async function lstatNotFound() {
|
|||
assert(caughtError);
|
||||
assertEqual(badInfo, undefined);
|
||||
});
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue