diff --git a/BUILD.gn b/BUILD.gn index 839e904bec..180519d6e6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -199,6 +199,7 @@ run_node("gen_declarations") { "js/mkdir.ts", "js/os.ts", "js/read_file.ts", + "js/rename.ts", "js/remove.ts", "js/stat.ts", "js/text_encoding.ts", @@ -242,6 +243,7 @@ run_node("bundle") { "js/os.ts", "js/plugins.d.ts", "js/read_file.ts", + "js/rename.ts", "js/remove.ts", "js/stat.ts", "js/text_encoding.ts", diff --git a/js/deno.ts b/js/deno.ts index 3d0352a809..6f71ee4991 100644 --- a/js/deno.ts +++ b/js/deno.ts @@ -1,10 +1,15 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. // Public deno module. /// -export { env, exit, makeTempDirSync, renameSync } from "./os"; +export { + env, + exit, + makeTempDirSync +} from "./os"; export { mkdirSync, mkdir } from "./mkdir"; export { removeSync, remove, removeAllSync, removeAll } from "./remove"; export { readFileSync, readFile } from "./read_file"; +export { renameSync, rename } from "./rename"; export { FileInfo, statSync, lstatSync, stat, lstat } from "./stat"; export { writeFileSync, writeFile } from "./write_file"; export { ErrorKind, DenoError } from "./errors"; diff --git a/js/os.ts b/js/os.ts index 264cdcbaff..d73865c065 100644 --- a/js/os.ts +++ b/js/os.ts @@ -164,22 +164,3 @@ export function env(): { [index: string]: string } { // TypeScript cannot track assertion above, therefore not null assertion return createEnv(res); } - -/** - * Renames (moves) oldpath to newpath. - * import { renameSync } from "deno"; - * const oldpath = 'from/path'; - * const newpath = 'to/path'; - * - * renameSync(oldpath, newpath); - */ -export function renameSync(oldpath: string, newpath: string): void { - const builder = new flatbuffers.Builder(); - const _oldpath = builder.createString(oldpath); - const _newpath = builder.createString(newpath); - fbs.RenameSync.startRenameSync(builder); - fbs.RenameSync.addOldpath(builder, _oldpath); - fbs.RenameSync.addNewpath(builder, _newpath); - const msg = fbs.RenameSync.endRenameSync(builder); - sendSync(builder, fbs.Any.RenameSync, msg); -} diff --git a/js/os_test.ts b/js/os_test.ts index c0198095cd..61227a3b10 100644 --- a/js/os_test.ts +++ b/js/os_test.ts @@ -60,40 +60,3 @@ test(function makeTempDirSyncPerm() { assertEqual(err.kind, deno.ErrorKind.PermissionDenied); assertEqual(err.name, "PermissionDenied"); }); - -testPerm({ write: true }, function renameSync() { - const testDir = deno.makeTempDirSync() + "/test-rename"; - const oldpath = testDir + "/oldpath"; - const newpath = testDir + "/newpath"; - deno.mkdirSync(oldpath); - deno.renameSync(oldpath, newpath); - const newPathInfo = deno.statSync(newpath); - assert(newPathInfo.isDirectory()); - - let caughtErr = false; - let oldPathInfo; - - try { - oldPathInfo = deno.statSync(oldpath); - } catch (err) { - caughtErr = true; - assertEqual(err.kind, deno.ErrorKind.NotFound); - assertEqual(err.name, "NotFound"); - } - - assert(caughtErr); - assertEqual(oldPathInfo, undefined); -}); - -test(function renameSyncPerm() { - let err; - try { - const oldpath = "/oldbaddir"; - const newpath = "/newbaddir"; - deno.renameSync(oldpath, newpath); - } catch (err_) { - err = err_; - } - assertEqual(err.kind, deno.ErrorKind.PermissionDenied); - assertEqual(err.name, "PermissionDenied"); -}); diff --git a/js/rename.ts b/js/rename.ts new file mode 100644 index 0000000000..241e274908 --- /dev/null +++ b/js/rename.ts @@ -0,0 +1,42 @@ +// 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"; + +/** + * Synchronously renames (moves) oldpath to newpath. If newpath already exists + * and is not a directory, Rename replaces it. OS-specific restrictions may + * apply when oldpath and newpath are in different directories. + * + * import { renameSync } from "deno"; + * renameSync("old/path", "new/path"); + */ +export function renameSync(oldpath: string, newpath: string): void { + dispatch.sendSync(...req(oldpath, newpath)); +} + +/** + * Renames (moves) oldpath to newpath. If newpath already exists + * and is not a directory, Rename replaces it. OS-specific restrictions may + * apply when oldpath and newpath are in different directories. + * + * import { rename } from "deno"; + * await rename("old/path", "new/path"); + */ +export async function rename(oldpath: string, newpath: string): Promise { + await dispatch.sendAsync(...req(oldpath, newpath)); +} + +function req( + oldpath: string, + newpath: string +): [flatbuffers.Builder, fbs.Any, flatbuffers.Offset] { + const builder = new flatbuffers.Builder(); + const oldpath_ = builder.createString(oldpath); + const newpath_ = builder.createString(newpath); + fbs.Rename.startRename(builder); + fbs.Rename.addOldpath(builder, oldpath_); + fbs.Rename.addNewpath(builder, newpath_); + const msg = fbs.Rename.endRename(builder); + return [builder, fbs.Any.Rename, msg]; +} diff --git a/js/rename_test.ts b/js/rename_test.ts new file mode 100644 index 0000000000..450760dae6 --- /dev/null +++ b/js/rename_test.ts @@ -0,0 +1,60 @@ +// Copyright 2018 the Deno authors. All rights reserved. MIT license. +import { test, testPerm, assert, assertEqual } from "./test_util.ts"; +import * as deno from "deno"; + +testPerm({ write: true }, function renameSyncSuccess() { + const testDir = deno.makeTempDirSync() + "/test-rename-sync"; + const oldpath = testDir + "/oldpath"; + const newpath = testDir + "/newpath"; + deno.mkdirSync(oldpath); + deno.renameSync(oldpath, newpath); + const newPathInfo = deno.statSync(newpath); + assert(newPathInfo.isDirectory()); + + let caughtErr = false; + let oldPathInfo; + + try { + oldPathInfo = deno.statSync(oldpath); + } catch (e) { + caughtErr = true; + assertEqual(e.kind, deno.ErrorKind.NotFound); + } + assert(caughtErr); + assertEqual(oldPathInfo, undefined); +}); + +testPerm({ write: false }, function renameSyncPerm() { + let err; + try { + const oldpath = "/oldbaddir"; + const newpath = "/newbaddir"; + deno.renameSync(oldpath, newpath); + } catch (e) { + err = e; + } + assertEqual(err.kind, deno.ErrorKind.PermissionDenied); + assertEqual(err.name, "PermissionDenied"); +}); + +testPerm({ write: true }, async function renameSuccess() { + const testDir = deno.makeTempDirSync() + "/test-rename"; + const oldpath = testDir + "/oldpath"; + const newpath = testDir + "/newpath"; + deno.mkdirSync(oldpath); + await deno.rename(oldpath, newpath); + const newPathInfo = deno.statSync(newpath); + assert(newPathInfo.isDirectory()); + + let caughtErr = false; + let oldPathInfo; + + try { + oldPathInfo = deno.statSync(oldpath); + } catch (e) { + caughtErr = true; + assertEqual(e.kind, deno.ErrorKind.NotFound); + } + assert(caughtErr); + assertEqual(oldPathInfo, undefined); +}); diff --git a/js/unit_tests.ts b/js/unit_tests.ts index 88e6fb9d94..b406b63d08 100644 --- a/js/unit_tests.ts +++ b/js/unit_tests.ts @@ -9,3 +9,4 @@ import "./read_file_test.ts"; import "./write_file_test.ts"; import "./mkdir_test.ts"; import "./stat_test.ts"; +import "./rename_test.ts"; diff --git a/src/handlers.rs b/src/handlers.rs index 681f18812b..09b4e299a8 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -55,7 +55,7 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) { msg::Any::Mkdir => handle_mkdir, msg::Any::Remove => handle_remove, msg::Any::ReadFile => handle_read_file, - msg::Any::RenameSync => handle_rename_sync, + msg::Any::Rename => handle_rename, msg::Any::SetEnv => handle_set_env, msg::Any::Stat => handle_stat, msg::Any::WriteFile => handle_write_file, @@ -633,15 +633,14 @@ fn handle_timer_clear(d: *const DenoC, base: &msg::Base) -> Box { ok_future(None) } -fn handle_rename_sync(d: *const DenoC, base: &msg::Base) -> Box { +fn handle_rename(d: *const DenoC, base: &msg::Base) -> Box { let deno = from_c(d); if !deno.flags.allow_write { - return Box::new(futures::future::err(permission_denied())); - }; - let msg = base.msg_as_rename_sync().unwrap(); + return odd_future(permission_denied()); + } + let msg = base.msg_as_rename().unwrap(); let oldpath = String::from(msg.oldpath().unwrap()); let newpath = String::from(msg.newpath().unwrap()); - // TODO use blocking() Box::new(futures::future::result(|| -> OpResult { debug!("handle_rename {} {}", oldpath, newpath); fs::rename(Path::new(&oldpath), Path::new(&newpath))?; diff --git a/src/msg.fbs b/src/msg.fbs index 458f5f437b..c630fec9d9 100644 --- a/src/msg.fbs +++ b/src/msg.fbs @@ -19,7 +19,7 @@ union Any { ReadFile, ReadFileRes, WriteFile, - RenameSync, + Rename, Stat, StatRes, SetEnv, @@ -194,7 +194,7 @@ table WriteFile { // perm specified by https://godoc.org/os#FileMode } -table RenameSync { +table Rename { oldpath: string; newpath: string; }