-
Notifications
You must be signed in to change notification settings - Fork 629
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add ensureSymlink/ensureSymlinkSync for fs modules (#268)
- Loading branch information
Showing
4 changed files
with
260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. | ||
import * as path from "./path/mod.ts"; | ||
import { ensureDir, ensureDirSync } from "./ensure_dir.ts"; | ||
import { exists, existsSync } from "./exists.ts"; | ||
import { PathType, getFileInfoType } from "./utils.ts"; | ||
|
||
const isWindows = Deno.platform.os === "win"; | ||
|
||
/** | ||
* Ensures that the link exists. | ||
* If the directory structure does not exist, it is created. | ||
* | ||
* @param src the source file path | ||
* @param dest the destination link path | ||
*/ | ||
export async function ensureSymlink(src: string, dest: string): Promise<void> { | ||
const srcStatInfo = await Deno.lstat(src); | ||
const srcFilePathType = getFileInfoType(srcStatInfo); | ||
|
||
if (await exists(dest)) { | ||
const destStatInfo = await Deno.lstat(dest); | ||
const destFilePathType = getFileInfoType(destStatInfo); | ||
if (destFilePathType !== PathType.symlink) { | ||
throw new Error( | ||
`Ensure path exists, expected 'symlink', got '${destFilePathType}'` | ||
); | ||
} | ||
return; | ||
} | ||
|
||
await ensureDir(path.dirname(dest)); | ||
|
||
// TODO(axetroy): remove this if condition. refs: https://github.com/denoland/deno/issues/2169 | ||
if (isWindows) { | ||
await Deno.symlink(src, dest, srcFilePathType || undefined); | ||
} else { | ||
await Deno.symlink(src, dest); | ||
} | ||
} | ||
|
||
/** | ||
* Ensures that the link exists. | ||
* If the directory structure does not exist, it is created. | ||
* | ||
* @param src the source file path | ||
* @param dest the destination link path | ||
*/ | ||
export function ensureSymlinkSync(src: string, dest: string): void { | ||
const srcStatInfo = Deno.lstatSync(src); | ||
const srcFilePathType = getFileInfoType(srcStatInfo); | ||
|
||
if (existsSync(dest)) { | ||
const destStatInfo = Deno.lstatSync(dest); | ||
const destFilePathType = getFileInfoType(destStatInfo); | ||
if (destFilePathType !== PathType.symlink) { | ||
throw new Error( | ||
`Ensure path exists, expected 'symlink', got '${destFilePathType}'` | ||
); | ||
} | ||
return; | ||
} | ||
|
||
ensureDirSync(path.dirname(dest)); | ||
|
||
// TODO(axetroy): remove this if condition. refs: https://github.com/denoland/deno/issues/2169 | ||
if (isWindows) { | ||
Deno.symlinkSync(src, dest, srcFilePathType || undefined); | ||
} else { | ||
Deno.symlinkSync(src, dest); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. | ||
// TODO(axetroy): Add test for Windows once symlink is implemented for Windows. | ||
import { test } from "../testing/mod.ts"; | ||
import { | ||
assertEquals, | ||
assertThrows, | ||
assertThrowsAsync | ||
} from "../testing/asserts.ts"; | ||
import { ensureSymlink, ensureSymlinkSync } from "./ensure_symlink.ts"; | ||
import * as path from "./path/mod.ts"; | ||
|
||
const testdataDir = path.resolve("fs", "testdata"); | ||
const isWindows = Deno.platform.os === "win"; | ||
|
||
test(async function ensureSymlinkIfItNotExist() { | ||
const testDir = path.join(testdataDir, "link_file_1"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
|
||
assertThrowsAsync(async () => { | ||
await ensureSymlink(testFile, path.join(testDir, "test1.txt")); | ||
}); | ||
|
||
assertThrowsAsync(async () => { | ||
await Deno.stat(testFile).then(() => { | ||
throw new Error("test file should exists."); | ||
}); | ||
}); | ||
}); | ||
|
||
test(function ensureSymlinkSyncIfItNotExist() { | ||
const testDir = path.join(testdataDir, "link_file_2"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
|
||
assertThrows(() => { | ||
ensureSymlinkSync(testFile, path.join(testDir, "test1.txt")); | ||
}); | ||
|
||
assertThrows(() => { | ||
Deno.statSync(testFile); | ||
throw new Error("test file should exists."); | ||
}); | ||
}); | ||
|
||
test(async function ensureSymlinkIfItExist() { | ||
const testDir = path.join(testdataDir, "link_file_3"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
const linkFile = path.join(testDir, "link.txt"); | ||
|
||
await Deno.mkdir(testDir, true); | ||
await Deno.writeFile(testFile, new Uint8Array()); | ||
|
||
if (isWindows) { | ||
await assertThrowsAsync( | ||
() => ensureSymlink(testFile, linkFile), | ||
Error, | ||
"Not implemented" | ||
); | ||
await Deno.remove(testDir, { recursive: true }); | ||
return; | ||
} else { | ||
await ensureSymlink(testFile, linkFile); | ||
} | ||
|
||
const srcStat = await Deno.lstat(testFile); | ||
const linkStat = await Deno.lstat(linkFile); | ||
|
||
assertEquals(srcStat.isFile(), true); | ||
assertEquals(linkStat.isSymlink(), true); | ||
|
||
await Deno.remove(testDir, { recursive: true }); | ||
}); | ||
|
||
test(function ensureSymlinkSyncIfItExist() { | ||
const testDir = path.join(testdataDir, "link_file_4"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
const linkFile = path.join(testDir, "link.txt"); | ||
|
||
Deno.mkdirSync(testDir, true); | ||
Deno.writeFileSync(testFile, new Uint8Array()); | ||
|
||
if (isWindows) { | ||
assertThrows( | ||
() => ensureSymlinkSync(testFile, linkFile), | ||
Error, | ||
"Not implemented" | ||
); | ||
Deno.removeSync(testDir, { recursive: true }); | ||
return; | ||
} else { | ||
ensureSymlinkSync(testFile, linkFile); | ||
} | ||
|
||
const srcStat = Deno.lstatSync(testFile); | ||
|
||
const linkStat = Deno.lstatSync(linkFile); | ||
|
||
assertEquals(srcStat.isFile(), true); | ||
assertEquals(linkStat.isSymlink(), true); | ||
|
||
Deno.removeSync(testDir, { recursive: true }); | ||
}); | ||
|
||
test(async function ensureSymlinkDirectoryIfItExist() { | ||
const testDir = path.join(testdataDir, "link_file_origin_3"); | ||
const linkDir = path.join(testdataDir, "link_file_link_3"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
|
||
await Deno.mkdir(testDir, true); | ||
await Deno.writeFile(testFile, new Uint8Array()); | ||
|
||
if (isWindows) { | ||
await assertThrowsAsync( | ||
() => ensureSymlink(testDir, linkDir), | ||
Error, | ||
"Not implemented" | ||
); | ||
await Deno.remove(testDir, { recursive: true }); | ||
return; | ||
} else { | ||
await ensureSymlink(testDir, linkDir); | ||
} | ||
|
||
const testDirStat = await Deno.lstat(testDir); | ||
const linkDirStat = await Deno.lstat(linkDir); | ||
const testFileStat = await Deno.lstat(testFile); | ||
|
||
assertEquals(testFileStat.isFile(), true); | ||
assertEquals(testDirStat.isDirectory(), true); | ||
assertEquals(linkDirStat.isSymlink(), true); | ||
|
||
await Deno.remove(linkDir, { recursive: true }); | ||
await Deno.remove(testDir, { recursive: true }); | ||
}); | ||
|
||
test(function ensureSymlinkSyncDirectoryIfItExist() { | ||
const testDir = path.join(testdataDir, "link_file_origin_3"); | ||
const linkDir = path.join(testdataDir, "link_file_link_3"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
|
||
Deno.mkdirSync(testDir, true); | ||
Deno.writeFileSync(testFile, new Uint8Array()); | ||
|
||
if (isWindows) { | ||
assertThrows( | ||
() => ensureSymlinkSync(testDir, linkDir), | ||
Error, | ||
"Not implemented" | ||
); | ||
Deno.removeSync(testDir, { recursive: true }); | ||
return; | ||
} else { | ||
ensureSymlinkSync(testDir, linkDir); | ||
} | ||
|
||
const testDirStat = Deno.lstatSync(testDir); | ||
const linkDirStat = Deno.lstatSync(linkDir); | ||
const testFileStat = Deno.lstatSync(testFile); | ||
|
||
assertEquals(testFileStat.isFile(), true); | ||
assertEquals(testDirStat.isDirectory(), true); | ||
assertEquals(linkDirStat.isSymlink(), true); | ||
|
||
Deno.removeSync(linkDir, { recursive: true }); | ||
Deno.removeSync(testDir, { recursive: true }); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters