mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
Implement deno.symlink() (#742)
This commit is contained in:
parent
d19268b2bf
commit
017ef096df
7 changed files with 166 additions and 1 deletions
1
BUILD.gn
1
BUILD.gn
|
@ -76,6 +76,7 @@ ts_sources = [
|
||||||
"js/remove.ts",
|
"js/remove.ts",
|
||||||
"js/rename.ts",
|
"js/rename.ts",
|
||||||
"js/stat.ts",
|
"js/stat.ts",
|
||||||
|
"js/symlink.ts",
|
||||||
"js/text_encoding.ts",
|
"js/text_encoding.ts",
|
||||||
"js/timers.ts",
|
"js/timers.ts",
|
||||||
"js/types.ts",
|
"js/types.ts",
|
||||||
|
|
|
@ -8,6 +8,7 @@ export { removeSync, remove, removeAllSync, removeAll } from "./remove";
|
||||||
export { readFileSync, readFile } from "./read_file";
|
export { readFileSync, readFile } from "./read_file";
|
||||||
export { renameSync, rename } from "./rename";
|
export { renameSync, rename } from "./rename";
|
||||||
export { FileInfo, statSync, lstatSync, stat, lstat } from "./stat";
|
export { FileInfo, statSync, lstatSync, stat, lstat } from "./stat";
|
||||||
|
export { symlinkSync, symlink } from "./symlink";
|
||||||
export { writeFileSync, writeFile } from "./write_file";
|
export { writeFileSync, writeFile } from "./write_file";
|
||||||
export { ErrorKind, DenoError } from "./errors";
|
export { ErrorKind, DenoError } from "./errors";
|
||||||
export { libdeno } from "./libdeno";
|
export { libdeno } from "./libdeno";
|
||||||
|
|
56
js/symlink.ts
Normal file
56
js/symlink.ts
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// 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";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously creates newname as a symbolic link to oldname.
|
||||||
|
* The type argument can be set to 'dir' or 'file' and is only
|
||||||
|
* available on Windows (ignored on other platforms).
|
||||||
|
*
|
||||||
|
* import { symlinkSync } from "deno";
|
||||||
|
* symlinkSync("old/name", "new/name");
|
||||||
|
*/
|
||||||
|
export function symlinkSync(
|
||||||
|
oldname: string,
|
||||||
|
newname: string,
|
||||||
|
type?: string
|
||||||
|
): void {
|
||||||
|
dispatch.sendSync(...req(oldname, newname, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates newname as a symbolic link to oldname.
|
||||||
|
* The type argument can be set to 'dir' or 'file' and is only
|
||||||
|
* available on Windows (ignored on other platforms).
|
||||||
|
*
|
||||||
|
* import { symlink } from "deno";
|
||||||
|
* await symlink("old/name", "new/name");
|
||||||
|
*/
|
||||||
|
export async function symlink(
|
||||||
|
oldname: string,
|
||||||
|
newname: string,
|
||||||
|
type?: string
|
||||||
|
): Promise<void> {
|
||||||
|
await dispatch.sendAsync(...req(oldname, newname, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
function req(
|
||||||
|
oldname: string,
|
||||||
|
newname: string,
|
||||||
|
type?: string
|
||||||
|
): [flatbuffers.Builder, fbs.Any, flatbuffers.Offset] {
|
||||||
|
// TODO Use type for Windows.
|
||||||
|
if (type) {
|
||||||
|
return util.notImplemented();
|
||||||
|
}
|
||||||
|
const builder = new flatbuffers.Builder();
|
||||||
|
const oldname_ = builder.createString(oldname);
|
||||||
|
const newname_ = builder.createString(newname);
|
||||||
|
fbs.Symlink.startSymlink(builder);
|
||||||
|
fbs.Symlink.addOldname(builder, oldname_);
|
||||||
|
fbs.Symlink.addNewname(builder, newname_);
|
||||||
|
const msg = fbs.Symlink.endSymlink(builder);
|
||||||
|
return [builder, fbs.Any.Symlink, msg];
|
||||||
|
}
|
71
js/symlink_test.ts
Normal file
71
js/symlink_test.ts
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// 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 symlinkSyncSuccess() {
|
||||||
|
const testDir = deno.makeTempDirSync() + "/test-symlink-sync";
|
||||||
|
const oldname = testDir + "/oldname";
|
||||||
|
const newname = testDir + "/newname";
|
||||||
|
deno.mkdirSync(oldname);
|
||||||
|
let errOnWindows;
|
||||||
|
// Just for now, until we implement symlink for Windows.
|
||||||
|
try {
|
||||||
|
deno.symlinkSync(oldname, newname);
|
||||||
|
} catch (e) {
|
||||||
|
errOnWindows = e;
|
||||||
|
}
|
||||||
|
if (errOnWindows) {
|
||||||
|
assertEqual(errOnWindows.kind, deno.ErrorKind.Other);
|
||||||
|
assertEqual(errOnWindows.message, "Not implemented");
|
||||||
|
} else {
|
||||||
|
const newNameInfoLStat = deno.lstatSync(newname);
|
||||||
|
const newNameInfoStat = deno.statSync(newname);
|
||||||
|
assert(newNameInfoLStat.isSymlink());
|
||||||
|
assert(newNameInfoStat.isDirectory());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
testPerm({ write: false }, function symlinkSyncPerm() {
|
||||||
|
let err;
|
||||||
|
try {
|
||||||
|
deno.symlinkSync("oldbaddir", "newbaddir");
|
||||||
|
} catch (e) {
|
||||||
|
err = e;
|
||||||
|
}
|
||||||
|
assertEqual(err.kind, deno.ErrorKind.PermissionDenied);
|
||||||
|
assertEqual(err.name, "PermissionDenied");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Just for now, until we implement symlink for Windows.
|
||||||
|
testPerm({ write: true }, function symlinkSyncNotImplemented() {
|
||||||
|
let err;
|
||||||
|
try {
|
||||||
|
deno.symlinkSync("oldname", "newname", "dir");
|
||||||
|
} catch (e) {
|
||||||
|
err = e;
|
||||||
|
}
|
||||||
|
assertEqual(err.message, "Not implemented");
|
||||||
|
});
|
||||||
|
|
||||||
|
testPerm({ write: true }, async function symlinkSuccess() {
|
||||||
|
const testDir = deno.makeTempDirSync() + "/test-symlink";
|
||||||
|
const oldname = testDir + "/oldname";
|
||||||
|
const newname = testDir + "/newname";
|
||||||
|
deno.mkdirSync(oldname);
|
||||||
|
let errOnWindows;
|
||||||
|
// Just for now, until we implement symlink for Windows.
|
||||||
|
try {
|
||||||
|
await deno.symlink(oldname, newname);
|
||||||
|
} catch (e) {
|
||||||
|
errOnWindows = e;
|
||||||
|
}
|
||||||
|
if (errOnWindows) {
|
||||||
|
assertEqual(errOnWindows.kind, deno.ErrorKind.Other);
|
||||||
|
assertEqual(errOnWindows.message, "Not implemented");
|
||||||
|
} else {
|
||||||
|
const newNameInfoLStat = deno.lstatSync(newname);
|
||||||
|
const newNameInfoStat = deno.statSync(newname);
|
||||||
|
assert(newNameInfoLStat.isSymlink());
|
||||||
|
assert(newNameInfoStat.isDirectory());
|
||||||
|
}
|
||||||
|
});
|
|
@ -13,3 +13,4 @@ import "./stat_test.ts";
|
||||||
import "./rename_test.ts";
|
import "./rename_test.ts";
|
||||||
import "./blob_test.ts";
|
import "./blob_test.ts";
|
||||||
import "./timers_test.ts";
|
import "./timers_test.ts";
|
||||||
|
import "./symlink_test.ts";
|
||||||
|
|
|
@ -56,6 +56,7 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) {
|
||||||
msg::Any::Remove => handle_remove,
|
msg::Any::Remove => handle_remove,
|
||||||
msg::Any::ReadFile => handle_read_file,
|
msg::Any::ReadFile => handle_read_file,
|
||||||
msg::Any::Rename => handle_rename,
|
msg::Any::Rename => handle_rename,
|
||||||
|
msg::Any::Symlink => handle_symlink,
|
||||||
msg::Any::SetEnv => handle_set_env,
|
msg::Any::SetEnv => handle_set_env,
|
||||||
msg::Any::Stat => handle_stat,
|
msg::Any::Stat => handle_stat,
|
||||||
msg::Any::WriteFile => handle_write_file,
|
msg::Any::WriteFile => handle_write_file,
|
||||||
|
@ -142,6 +143,13 @@ fn permission_denied() -> DenoError {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn not_implemented() -> DenoError {
|
||||||
|
DenoError::from(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
"Not implemented"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_exit(_d: *const DenoC, base: &msg::Base) -> Box<Op> {
|
fn handle_exit(_d: *const DenoC, base: &msg::Base) -> Box<Op> {
|
||||||
let msg = base.msg_as_exit().unwrap();
|
let msg = base.msg_as_exit().unwrap();
|
||||||
std::process::exit(msg.code())
|
std::process::exit(msg.code())
|
||||||
|
@ -663,7 +671,7 @@ fn handle_rename(d: *const DenoC, base: &msg::Base) -> Box<Op> {
|
||||||
let isolate = from_c(d);
|
let isolate = from_c(d);
|
||||||
if !isolate.flags.allow_write {
|
if !isolate.flags.allow_write {
|
||||||
return odd_future(permission_denied());
|
return odd_future(permission_denied());
|
||||||
};
|
}
|
||||||
let msg = base.msg_as_rename().unwrap();
|
let msg = base.msg_as_rename().unwrap();
|
||||||
let oldpath = String::from(msg.oldpath().unwrap());
|
let oldpath = String::from(msg.oldpath().unwrap());
|
||||||
let newpath = String::from(msg.newpath().unwrap());
|
let newpath = String::from(msg.newpath().unwrap());
|
||||||
|
@ -673,3 +681,24 @@ fn handle_rename(d: *const DenoC, base: &msg::Base) -> Box<Op> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}()))
|
}()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_symlink(d: *const DenoC, base: &msg::Base) -> Box<Op> {
|
||||||
|
let deno = from_c(d);
|
||||||
|
if !deno.flags.allow_write {
|
||||||
|
return odd_future(permission_denied());
|
||||||
|
}
|
||||||
|
// TODO Use type for Windows.
|
||||||
|
if cfg!(windows) {
|
||||||
|
return odd_future(not_implemented());
|
||||||
|
} else {
|
||||||
|
let msg = base.msg_as_symlink().unwrap();
|
||||||
|
let oldname = String::from(msg.oldname().unwrap());
|
||||||
|
let newname = String::from(msg.newname().unwrap());
|
||||||
|
Box::new(futures::future::result(|| -> OpResult {
|
||||||
|
debug!("handle_symlink {} {}", oldname, newname);
|
||||||
|
#[cfg(any(unix))]
|
||||||
|
std::os::unix::fs::symlink(Path::new(&oldname), Path::new(&newname))?;
|
||||||
|
Ok(None)
|
||||||
|
}()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ union Any {
|
||||||
ReadFileRes,
|
ReadFileRes,
|
||||||
WriteFile,
|
WriteFile,
|
||||||
Rename,
|
Rename,
|
||||||
|
Symlink,
|
||||||
Stat,
|
Stat,
|
||||||
StatRes,
|
StatRes,
|
||||||
SetEnv,
|
SetEnv,
|
||||||
|
@ -200,6 +201,11 @@ table Rename {
|
||||||
newpath: string;
|
newpath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table Symlink {
|
||||||
|
oldname: string;
|
||||||
|
newname: string;
|
||||||
|
}
|
||||||
|
|
||||||
table Stat {
|
table Stat {
|
||||||
filename: string;
|
filename: string;
|
||||||
lstat: bool;
|
lstat: bool;
|
||||||
|
|
Loading…
Reference in a new issue