-
Notifications
You must be signed in to change notification settings - Fork 629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add ensureLink/ensureLinkSync for fs #353
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// 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"; | ||
|
||
/** | ||
* Ensures that the hard link exists. | ||
* If the directory structure does not exist, it is created. | ||
* | ||
* @param src the source file path. Directory hard links are not allowed. | ||
* @param dest the destination link path | ||
*/ | ||
export async function ensureLink(src: string, dest: string): Promise<void> { | ||
if (await exists(dest)) { | ||
const destStatInfo = await Deno.lstat(dest); | ||
const destFilePathType = getFileInfoType(destStatInfo); | ||
if (destFilePathType !== PathType.file) { | ||
throw new Error( | ||
`Ensure path exists, expected 'file', got '${destFilePathType}'` | ||
); | ||
} | ||
return; | ||
} | ||
|
||
await ensureDir(path.dirname(dest)); | ||
|
||
await Deno.link(src, dest); | ||
} | ||
|
||
/** | ||
* Ensures that the hard link exists. | ||
* If the directory structure does not exist, it is created. | ||
* | ||
* @param src the source file path. Directory hard links are not allowed. | ||
* @param dest the destination link path | ||
*/ | ||
export function ensureLinkSync(src: string, dest: string): void { | ||
if (existsSync(dest)) { | ||
const destStatInfo = Deno.lstatSync(dest); | ||
const destFilePathType = getFileInfoType(destStatInfo); | ||
if (destFilePathType !== PathType.file) { | ||
throw new Error( | ||
`Ensure path exists, expected 'file', got '${destFilePathType}'` | ||
); | ||
} | ||
return; | ||
} | ||
|
||
ensureDirSync(path.dirname(dest)); | ||
|
||
Deno.linkSync(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,170 @@ | ||
// 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 { ensureLink, ensureLinkSync } from "./ensure_link.ts"; | ||
import * as path from "./path/mod.ts"; | ||
|
||
const testdataDir = path.resolve("fs", "testdata"); | ||
|
||
test(async function ensureLinkIfItNotExist() { | ||
const srcDir = path.join(testdataDir, "ensure_link_1"); | ||
const destDir = path.join(testdataDir, "ensure_link_1_2"); | ||
const testFile = path.join(srcDir, "test.txt"); | ||
const linkFile = path.join(destDir, "link.txt"); | ||
|
||
await assertThrowsAsync(async () => { | ||
await ensureLink(testFile, linkFile); | ||
}); | ||
|
||
await Deno.remove(destDir, { recursive: true }); | ||
}); | ||
|
||
test(function ensureLinkSyncIfItNotExist() { | ||
const testDir = path.join(testdataDir, "ensure_link_2"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
const linkFile = path.join(testDir, "link.txt"); | ||
|
||
assertThrows(() => { | ||
ensureLinkSync(testFile, linkFile); | ||
}); | ||
|
||
Deno.removeSync(testDir, { recursive: true }); | ||
}); | ||
|
||
test(async function ensureLinkIfItExist() { | ||
const testDir = path.join(testdataDir, "ensure_link_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()); | ||
|
||
await ensureLink(testFile, linkFile); | ||
|
||
const srcStat = await Deno.lstat(testFile); | ||
const linkStat = await Deno.lstat(linkFile); | ||
|
||
assertEquals(srcStat.isFile(), true); | ||
assertEquals(linkStat.isFile(), true); | ||
|
||
// har link success. try to change one of them. they should be change both. | ||
|
||
// let's change origin file. | ||
await Deno.writeFile(testFile, new TextEncoder().encode("123")); | ||
|
||
const testFileContent1 = new TextDecoder().decode( | ||
await Deno.readFile(testFile) | ||
); | ||
const linkFileContent1 = new TextDecoder().decode( | ||
await Deno.readFile(testFile) | ||
); | ||
|
||
assertEquals(testFileContent1, "123"); | ||
assertEquals(testFileContent1, linkFileContent1); | ||
|
||
// let's change link file. | ||
await Deno.writeFile(testFile, new TextEncoder().encode("abc")); | ||
|
||
const testFileContent2 = new TextDecoder().decode( | ||
await Deno.readFile(testFile) | ||
); | ||
const linkFileContent2 = new TextDecoder().decode( | ||
await Deno.readFile(testFile) | ||
); | ||
|
||
assertEquals(testFileContent2, "abc"); | ||
assertEquals(testFileContent2, linkFileContent2); | ||
|
||
await Deno.remove(testDir, { recursive: true }); | ||
}); | ||
|
||
test(function ensureLinkSyncIfItExist() { | ||
const testDir = path.join(testdataDir, "ensure_link_4"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
const linkFile = path.join(testDir, "link.txt"); | ||
|
||
Deno.mkdirSync(testDir, true); | ||
Deno.writeFileSync(testFile, new Uint8Array()); | ||
|
||
ensureLinkSync(testFile, linkFile); | ||
|
||
const srcStat = Deno.lstatSync(testFile); | ||
|
||
const linkStat = Deno.lstatSync(linkFile); | ||
|
||
assertEquals(srcStat.isFile(), true); | ||
assertEquals(linkStat.isFile(), true); | ||
|
||
// har link success. try to change one of them. they should be change both. | ||
|
||
// let's change origin file. | ||
Deno.writeFileSync(testFile, new TextEncoder().encode("123")); | ||
|
||
const testFileContent1 = new TextDecoder().decode( | ||
Deno.readFileSync(testFile) | ||
); | ||
const linkFileContent1 = new TextDecoder().decode( | ||
Deno.readFileSync(testFile) | ||
); | ||
|
||
assertEquals(testFileContent1, "123"); | ||
assertEquals(testFileContent1, linkFileContent1); | ||
|
||
// let's change link file. | ||
Deno.writeFileSync(testFile, new TextEncoder().encode("abc")); | ||
|
||
const testFileContent2 = new TextDecoder().decode( | ||
Deno.readFileSync(testFile) | ||
); | ||
const linkFileContent2 = new TextDecoder().decode( | ||
Deno.readFileSync(testFile) | ||
); | ||
|
||
assertEquals(testFileContent2, "abc"); | ||
assertEquals(testFileContent2, linkFileContent2); | ||
|
||
Deno.removeSync(testDir, { recursive: true }); | ||
}); | ||
|
||
test(async function ensureLinkDirectoryIfItExist() { | ||
const testDir = path.join(testdataDir, "ensure_link_origin_3"); | ||
const linkDir = path.join(testdataDir, "ensure_link_link_3"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
|
||
await Deno.mkdir(testDir, true); | ||
await Deno.writeFile(testFile, new Uint8Array()); | ||
|
||
await assertThrowsAsync( | ||
async () => { | ||
await ensureLink(testDir, linkDir); | ||
}, | ||
Deno.DenoError, | ||
"Operation not permitted (os error 1)" | ||
); | ||
|
||
Deno.removeSync(testDir, { recursive: true }); | ||
}); | ||
|
||
test(function ensureLinkSyncDirectoryIfItExist() { | ||
const testDir = path.join(testdataDir, "ensure_link_origin_3"); | ||
const linkDir = path.join(testdataDir, "ensure_link_link_3"); | ||
const testFile = path.join(testDir, "test.txt"); | ||
|
||
Deno.mkdirSync(testDir, true); | ||
Deno.writeFileSync(testFile, new Uint8Array()); | ||
|
||
assertThrows( | ||
() => { | ||
ensureLinkSync(testDir, linkDir); | ||
}, | ||
Deno.DenoError, | ||
"Operation not permitted (os error 1)" | ||
); | ||
|
||
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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hard links don't have a specific type, so we can only use it as file.