mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
Implement makeTempDirSync()
This commit is contained in:
parent
a836c493f3
commit
ceaf822682
9 changed files with 188 additions and 25 deletions
1
BUILD.gn
1
BUILD.gn
|
@ -43,6 +43,7 @@ main_extern = [
|
|||
"$rust_build:log",
|
||||
"$rust_build:sha1",
|
||||
"$rust_build:tempfile",
|
||||
"$rust_build:rand",
|
||||
"$rust_build:tokio",
|
||||
"$rust_build:tokio_current_thread",
|
||||
"$rust_build:url",
|
||||
|
|
|
@ -11,6 +11,7 @@ version = "0.0.0"
|
|||
url = "1.7.1"
|
||||
libc = "0.2.42"
|
||||
log = "0.4.3"
|
||||
rand = "0.5.4"
|
||||
sha1 = "0.6.0"
|
||||
tempfile = "3"
|
||||
tokio = {git = "https://github.com/tokio-rs/tokio.git", rev = "5d0d2a2e1214f856993df6965825c89bfcaa879e"}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
|
||||
// Public deno module.
|
||||
export { exit, readFileSync, writeFileSync } from "./os";
|
||||
export { exit, makeTempDirSync, readFileSync, writeFileSync } from "./os";
|
||||
export { libdeno } from "./libdeno";
|
||||
export const argv: string[] = [];
|
||||
|
|
51
js/os.ts
51
js/os.ts
|
@ -85,6 +85,57 @@ export function codeCache(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* makeTempDirSync creates a new temporary directory in the directory `dir`, its
|
||||
* name beginning with `prefix` and ending with `suffix`.
|
||||
* It returns the full path to the newly created directory.
|
||||
* If `dir` is unspecified, tempDir uses the default directory for temporary
|
||||
* files. Multiple programs calling tempDir simultaneously will not choose the
|
||||
* same directory. It is the caller's responsibility to remove the directory
|
||||
* when no longer needed.
|
||||
*/
|
||||
export interface MakeTempDirOptions {
|
||||
dir?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
}
|
||||
export function makeTempDirSync({
|
||||
dir,
|
||||
prefix,
|
||||
suffix
|
||||
}: MakeTempDirOptions = {}): string {
|
||||
const builder = new flatbuffers.Builder();
|
||||
const fbDir = dir == null ? -1 : builder.createString(dir);
|
||||
const fbPrefix = prefix == null ? -1 : builder.createString(prefix);
|
||||
const fbSuffix = suffix == null ? -1 : builder.createString(suffix);
|
||||
fbs.MakeTempDir.startMakeTempDir(builder);
|
||||
if (dir != null) {
|
||||
fbs.MakeTempDir.addDir(builder, fbDir);
|
||||
}
|
||||
if (prefix != null) {
|
||||
fbs.MakeTempDir.addPrefix(builder, fbPrefix);
|
||||
}
|
||||
if (suffix != null) {
|
||||
fbs.MakeTempDir.addSuffix(builder, fbSuffix);
|
||||
}
|
||||
const msg = fbs.MakeTempDir.endMakeTempDir(builder);
|
||||
fbs.Base.startBase(builder);
|
||||
fbs.Base.addMsg(builder, msg);
|
||||
fbs.Base.addMsgType(builder, fbs.Any.MakeTempDir);
|
||||
builder.finish(fbs.Base.endBase(builder));
|
||||
const resBuf = libdeno.send(builder.asUint8Array());
|
||||
assert(resBuf != null);
|
||||
const bb = new flatbuffers.ByteBuffer(new Uint8Array(resBuf!));
|
||||
const baseRes = fbs.Base.getRootAsBase(bb);
|
||||
maybeThrowError(baseRes);
|
||||
assert(fbs.Any.MakeTempDirRes === baseRes.msgType());
|
||||
const res = new fbs.MakeTempDirRes();
|
||||
assert(baseRes.msg(res) != null);
|
||||
const path = res.path();
|
||||
assert(path != null);
|
||||
return path!;
|
||||
}
|
||||
|
||||
export function readFileSync(filename: string): Uint8Array {
|
||||
/* Ideally we could write
|
||||
const res = send({
|
||||
|
|
|
@ -41,16 +41,16 @@ test(function tests_readFileSync_NotFound() {
|
|||
});
|
||||
*/
|
||||
|
||||
/* TODO(ry) Add this once we can create a tmpDir to write the file into.
|
||||
test(function writeFileSyncSuccess() {
|
||||
testPerm({ write: true }, function writeFileSync() {
|
||||
const enc = new TextEncoder();
|
||||
const dataWritten = enc.encode("Hello");
|
||||
const filename = "TEMPDIR/test.txt";
|
||||
deno.writeFileSync(filename, dataWritten, 0o666);
|
||||
const data = enc.encode("Hello");
|
||||
const filename = deno.makeTempDirSync() + "/test.txt";
|
||||
deno.writeFileSync(filename, data, 0o666);
|
||||
const dataRead = deno.readFileSync(filename);
|
||||
assertEqual(dataRead, dataWritten);
|
||||
const dec = new TextDecoder("utf-8");
|
||||
const actual = dec.decode(dataRead);
|
||||
assertEqual("Hello", actual);
|
||||
});
|
||||
*/
|
||||
|
||||
// For this test to pass we need --allow-write permission.
|
||||
// Otherwise it will fail with deno.PermissionDenied instead of deno.NotFound.
|
||||
|
@ -70,23 +70,48 @@ testPerm({ write: true }, function writeFileSyncFail() {
|
|||
assert(caughtError);
|
||||
});
|
||||
|
||||
testPerm({ write: true }, function makeTempDirSync() {
|
||||
const dir1 = deno.makeTempDirSync({ prefix: "hello", suffix: "world" });
|
||||
const dir2 = deno.makeTempDirSync({ prefix: "hello", suffix: "world" });
|
||||
// Check that both dirs are different.
|
||||
assert(dir1 != dir2);
|
||||
for (const dir of [dir1, dir2]) {
|
||||
// Check that the prefix and suffix are applied.
|
||||
const lastPart = dir.replace(/^.*[\\\/]/, "");
|
||||
assert(lastPart.startsWith("hello"));
|
||||
assert(lastPart.endsWith("world"));
|
||||
}
|
||||
// Check that the `dir` option works.
|
||||
const dir3 = deno.makeTempDirSync({ dir: dir1 });
|
||||
assert(dir3.startsWith(dir1));
|
||||
assert(/^[\\\/]/.test(dir3.slice(dir1.length)));
|
||||
// Check that creating a temp dir inside a nonexisting directory fails.
|
||||
let err;
|
||||
try {
|
||||
deno.makeTempDirSync({ dir: "/baddir" });
|
||||
} catch (err_) {
|
||||
err = err_;
|
||||
}
|
||||
// TODO assert(err instanceof deno.NotFound).
|
||||
assert(err);
|
||||
assertEqual(err.name, "deno.NotFound");
|
||||
});
|
||||
|
||||
test(function makeTempDirSyncPerm() {
|
||||
// makeTempDirSync should require write permissions (for now).
|
||||
let err;
|
||||
try {
|
||||
deno.makeTempDirSync({ dir: "/baddir" });
|
||||
} catch (err_) {
|
||||
err = err_;
|
||||
}
|
||||
// TODO assert(err instanceof deno.PermissionDenied).
|
||||
assert(err);
|
||||
assertEqual(err.name, "deno.PermissionDenied");
|
||||
});
|
||||
|
||||
testPerm({ net: true }, async function tests_fetch() {
|
||||
const response = await fetch("http://localhost:4545/package.json");
|
||||
const json = await response.json();
|
||||
assertEqual(json.name, "deno");
|
||||
});
|
||||
|
||||
/*
|
||||
test(async function tests_writeFileSync() {
|
||||
const enc = new TextEncoder();
|
||||
const data = enc.encode("Hello");
|
||||
// TODO need ability to get tmp dir.
|
||||
const fn = "/tmp/test.txt";
|
||||
writeFileSync("/tmp/test.txt", data, 0o666);
|
||||
const dataRead = deno.readFileSync("/tmp/test.txt");
|
||||
const dec = new TextDecoder("utf-8");
|
||||
const actual = dec.decode(dataRead);
|
||||
assertEqual("Hello", actual);
|
||||
});
|
||||
|
||||
*/
|
||||
|
|
32
src/fs.rs
32
src/fs.rs
|
@ -1,13 +1,41 @@
|
|||
use std;
|
||||
use std::fs::File;
|
||||
use std::fs::{create_dir, File};
|
||||
use std::io::ErrorKind;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rand;
|
||||
use rand::RngCore;
|
||||
|
||||
pub fn write_file_sync(path: &Path, content: &[u8]) -> std::io::Result<()> {
|
||||
let mut f = File::create(path)?;
|
||||
f.write_all(content)
|
||||
}
|
||||
|
||||
pub fn make_temp_dir(
|
||||
dir: Option<&Path>,
|
||||
prefix: Option<&str>,
|
||||
suffix: Option<&str>,
|
||||
) -> std::io::Result<PathBuf> {
|
||||
let prefix_ = prefix.unwrap_or("");
|
||||
let suffix_ = suffix.unwrap_or("");
|
||||
let mut buf: PathBuf = match dir {
|
||||
Some(ref p) => p.to_path_buf(),
|
||||
None => std::env::temp_dir(),
|
||||
}.join("_");
|
||||
loop {
|
||||
let unique = rand::thread_rng().next_u32();
|
||||
buf.set_file_name(format!("{}{:08x}{}", prefix_, unique, suffix_));
|
||||
// TODO: on posix, set mode flags to 0o700.
|
||||
let r = create_dir(buf.as_path());
|
||||
match r {
|
||||
Err(ref e) if e.kind() == ErrorKind::AlreadyExists => continue,
|
||||
Ok(_) => return Ok(buf),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mkdir(path: &Path) -> std::io::Result<()> {
|
||||
debug!("mkdir -p {}", path.display());
|
||||
assert!(path.has_root(), "non-has_root not yet implemented");
|
||||
|
|
|
@ -65,6 +65,13 @@ pub extern "C" fn msg_from_js(d: *const DenoC, buf: deno_buf) {
|
|||
let msg = msg::Exit::init_from_table(base.msg().unwrap());
|
||||
std::process::exit(msg.code())
|
||||
}
|
||||
msg::Any::MakeTempDir => {
|
||||
let msg = msg::MakeTempDir::init_from_table(base.msg().unwrap());
|
||||
let dir = msg.dir();
|
||||
let prefix = msg.prefix();
|
||||
let suffix = msg.suffix();
|
||||
handle_make_temp_dir(d, &mut builder, dir, prefix, suffix)
|
||||
}
|
||||
msg::Any::ReadFileSync => {
|
||||
// TODO base.msg_as_ReadFileSync();
|
||||
let msg = msg::ReadFileSync::init_from_table(base.msg().unwrap());
|
||||
|
@ -395,6 +402,43 @@ fn send_timer_ready(d: *const DenoC, timer_id: u32, done: bool) {
|
|||
);
|
||||
}
|
||||
|
||||
fn handle_make_temp_dir(
|
||||
d: *const DenoC,
|
||||
builder: &mut FlatBufferBuilder,
|
||||
dir: Option<&str>,
|
||||
prefix: Option<&str>,
|
||||
suffix: Option<&str>,
|
||||
) -> HandlerResult {
|
||||
let deno = from_c(d);
|
||||
if !deno.flags.allow_write {
|
||||
let err = std::io::Error::new(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
"allow_write is off.",
|
||||
);
|
||||
return Err(err.into());
|
||||
}
|
||||
// TODO(piscisaureus): use byte vector for paths, not a string.
|
||||
// See https://github.com/denoland/deno/issues/627.
|
||||
// We can't assume that paths are always valid utf8 strings.
|
||||
let path = deno_fs::make_temp_dir(dir.map(Path::new), prefix, suffix)?;
|
||||
let path_off = builder.create_string(path.to_str().unwrap());
|
||||
let msg = msg::MakeTempDirRes::create(
|
||||
builder,
|
||||
&msg::MakeTempDirResArgs {
|
||||
path: Some(path_off),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
Ok(create_msg(
|
||||
builder,
|
||||
&msg::BaseArgs {
|
||||
msg: Some(flatbuffers::Offset::new(msg.value())),
|
||||
msg_type: msg::Any::MakeTempDirRes,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
// Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184
|
||||
fn handle_read_file_sync(
|
||||
_d: *const DenoC,
|
||||
|
|
|
@ -3,6 +3,7 @@ extern crate futures;
|
|||
extern crate hyper;
|
||||
extern crate libc;
|
||||
extern crate msg_rs as msg_generated;
|
||||
extern crate rand;
|
||||
extern crate sha1;
|
||||
extern crate tempfile;
|
||||
extern crate tokio;
|
||||
|
|
12
src/msg.fbs
12
src/msg.fbs
|
@ -12,6 +12,8 @@ union Any {
|
|||
TimerClear,
|
||||
FetchReq,
|
||||
FetchRes,
|
||||
MakeTempDir,
|
||||
MakeTempDirRes,
|
||||
ReadFileSync,
|
||||
ReadFileSyncRes,
|
||||
WriteFileSync,
|
||||
|
@ -133,6 +135,16 @@ table FetchRes {
|
|||
body: [ubyte];
|
||||
}
|
||||
|
||||
table MakeTempDir {
|
||||
dir: string;
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
}
|
||||
|
||||
table MakeTempDirRes {
|
||||
path: string;
|
||||
}
|
||||
|
||||
table ReadFileSync {
|
||||
filename: string;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue