mirror of
https://github.com/denoland/deno.git
synced 2024-11-23 15:16:54 -05:00
fix permission errors are swallowed by fs.emptyDir (#3501)
This commit is contained in:
parent
3115781e43
commit
bb24fb74ff
4 changed files with 172 additions and 23 deletions
|
@ -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 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
9
std/fs/testdata/empty_dir.ts
vendored
Normal 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
8
std/fs/testdata/empty_dir_sync.ts
vendored
Normal 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))
|
||||||
|
}
|
Loading…
Reference in a new issue