1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-26 16:09:27 -05:00

fix permission errors are swallowed by fs.emptyDir (#3501)

This commit is contained in:
Axetroy 2019-12-18 18:12:36 +08:00 committed by Ry Dahl
parent 3115781e43
commit bb24fb74ff
4 changed files with 172 additions and 23 deletions

View file

@ -1,25 +1,39 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { join } from "../path/mod.ts";
const {
readDir,
readDirSync,
mkdir,
mkdirSync,
remove,
removeSync,
ErrorKind
} = Deno;
/** /**
* Ensures that a directory is empty. * Ensures that a directory is empty.
* Deletes directory contents if the directory is not empty. * Deletes directory contents if the directory is not empty.
* If the directory does not exist, it is created. * If the directory does not exist, it is created.
* The directory itself is not deleted. * The directory itself is not deleted.
* Requires the `--allow-read` and `--alow-write` flag.
*/ */
export async function emptyDir(dir: string): Promise<void> { export async function emptyDir(dir: string): Promise<void> {
let items: Deno.FileInfo[] = [];
try { try {
items = await Deno.readDir(dir); const items = await readDir(dir);
} catch {
// if not exist. then create it while (items.length) {
await Deno.mkdir(dir, true); const item = items.shift();
return; if (item && item.name) {
} const filepath = join(dir, item.name);
while (items.length) { await remove(filepath, { recursive: true });
const item = items.shift(); }
if (item && item.name) {
const fn = dir + "/" + item.name;
await Deno.remove(fn, { recursive: true });
} }
} catch (err) {
if ((err as Deno.DenoError<Deno.ErrorKind>).kind !== ErrorKind.NotFound) {
throw err;
}
// if not exist. then create it
await mkdir(dir, true);
} }
} }
@ -28,21 +42,26 @@ export async function emptyDir(dir: string): Promise<void> {
* Deletes directory contents if the directory is not empty. * Deletes directory contents if the directory is not empty.
* If the directory does not exist, it is created. * If the directory does not exist, it is created.
* The directory itself is not deleted. * The directory itself is not deleted.
* Requires the `--allow-read` and `--alow-write` flag.
*/ */
export function emptyDirSync(dir: string): void { export function emptyDirSync(dir: string): void {
let items: Deno.FileInfo[] = [];
try { try {
items = Deno.readDirSync(dir); const items = readDirSync(dir);
} catch {
// if directory already exist. then remove it's child item.
while (items.length) {
const item = items.shift();
if (item && item.name) {
const filepath = join(dir, item.name);
removeSync(filepath, { recursive: true });
}
}
} catch (err) {
if ((err as Deno.DenoError<Deno.ErrorKind>).kind !== ErrorKind.NotFound) {
throw err;
}
// if not exist. then create it // if not exist. then create it
Deno.mkdirSync(dir, true); mkdirSync(dir, true);
return; return;
} }
while (items.length) {
const item = items.shift();
if (item && item.name) {
const fn = dir + "/" + item.name;
Deno.removeSync(fn, { recursive: true });
}
}
} }

View file

@ -123,3 +123,116 @@ test(function emptyDirSyncIfItExist(): void {
Deno.removeSync(testDir, { recursive: true }); Deno.removeSync(testDir, { recursive: true });
} }
}); });
test(async function emptyDirPermission(): Promise<void> {
interface Scenes {
read: boolean; // --allow-read
write: boolean; // --allow-write
async: boolean;
output: string;
}
const testfolder = path.join(testdataDir, "testfolder");
await Deno.mkdir(testfolder);
await Deno.writeFile(
path.join(testfolder, "child.txt"),
new TextEncoder().encode("hello world")
);
const scenes: Scenes[] = [
// 1
{
read: false,
write: false,
async: true,
output: "run again with the --allow-read flag"
},
{
read: false,
write: false,
async: false,
output: "run again with the --allow-read flag"
},
// 2
{
read: true,
write: false,
async: true,
output: "run again with the --allow-write flag"
},
{
read: true,
write: false,
async: false,
output: "run again with the --allow-write flag"
},
// 3
{
read: false,
write: true,
async: true,
output: "run again with the --allow-read flag"
},
{
read: false,
write: true,
async: false,
output: "run again with the --allow-read flag"
},
// 4
{
read: true,
write: true,
async: true,
output: "success"
},
{
read: true,
write: true,
async: false,
output: "success"
}
];
try {
for (const s of scenes) {
console.log(
`test ${s.async ? "emptyDir" : "emptyDirSync"}("testdata/testfolder") ${
s.read ? "with" : "without"
} --allow-read & ${s.write ? "with" : "without"} --allow-write`
);
const args = [Deno.execPath(), "run"];
if (s.read) {
args.push("--allow-read");
}
if (s.write) {
args.push("--allow-write");
}
args.push(
path.join(testdataDir, s.async ? "empty_dir.ts" : "empty_dir_sync.ts")
);
args.push("testfolder");
const { stdout } = Deno.run({
stdout: "piped",
cwd: testdataDir,
args: args
});
const output = await Deno.readAll(stdout);
assertEquals(new TextDecoder().decode(output), s.output);
}
} catch (err) {
await Deno.remove(testfolder, { recursive: true });
throw err;
}
// done
});

9
std/fs/testdata/empty_dir.ts vendored Normal file
View file

@ -0,0 +1,9 @@
import { emptyDir } from "../empty_dir.ts";
emptyDir(Deno.args[1])
.then(() => {
Deno.stdout.write(new TextEncoder().encode("success"))
})
.catch((err) => {
Deno.stdout.write(new TextEncoder().encode(err.message))
})

8
std/fs/testdata/empty_dir_sync.ts vendored Normal file
View file

@ -0,0 +1,8 @@
import { emptyDirSync } from "../empty_dir.ts";
try {
emptyDirSync(Deno.args[1])
Deno.stdout.write(new TextEncoder().encode("success"))
} catch (err) {
Deno.stdout.write(new TextEncoder().encode(err.message))
}