| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent c5cb6bc commit 6305a74
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -191,8 +191,10 @@ function onLink(destStat, src, dest, verbatimSymlinks) { | |||
| 191 | 191 | if (!verbatimSymlinks && !isAbsolute(resolvedSrc)) { | |
| 192 | 192 | resolvedSrc = resolve(dirname(src), resolvedSrc); | |
| 193 | 193 | } | |
| 194 | + const srcIsDir = fsBinding.internalModuleStat(src) === 1; | ||
| 195 | + const symlinkType = srcIsDir ? 'dir' : 'file'; | ||
| 194 | 196 | if (!destStat) { | |
| 195 | - return symlinkSync(resolvedSrc, dest); | ||
| 197 | + return symlinkSync(resolvedSrc, dest, symlinkType); | ||
| 196 | 198 | } | |
| 197 | 199 | let resolvedDest; | |
| 198 | 200 | try { | |
@@ -202,14 +204,13 @@ function onLink(destStat, src, dest, verbatimSymlinks) { | |||
| 202 | 204 | // Windows may throw UNKNOWN error. If dest already exists, | |
| 203 | 205 | // fs throws error anyway, so no need to guard against it here. | |
| 204 | 206 | if (err.code === 'EINVAL' || err.code === 'UNKNOWN') { | |
| 205 | - return symlinkSync(resolvedSrc, dest); | ||
| 207 | + return symlinkSync(resolvedSrc, dest, symlinkType); | ||
| 206 | 208 | } | |
| 207 | 209 | throw err; | |
| 208 | 210 | } | |
| 209 | 211 | if (!isAbsolute(resolvedDest)) { | |
| 210 | 212 | resolvedDest = resolve(dirname(dest), resolvedDest); | |
| 211 | 213 | } | |
| 212 | - const srcIsDir = fsBinding.internalModuleStat(src) === 1; | ||
| 213 | 214 | ||
| 214 | 215 | if (srcIsDir && isSrcSubdir(resolvedSrc, resolvedDest)) { | |
| 215 | 216 | throw new ERR_FS_CP_EINVAL({ | |
@@ -233,12 +234,12 @@ function onLink(destStat, src, dest, verbatimSymlinks) { | |||
| 233 | 234 | code: 'EINVAL', | |
| 234 | 235 | }); | |
| 235 | 236 | } | |
| 236 | - return copyLink(resolvedSrc, dest); | ||
| 237 | + return copyLink(resolvedSrc, dest, symlinkType); | ||
| 237 | 238 | } | |
| 238 | 239 | ||
| 239 | - function copyLink(resolvedSrc, dest) { | ||
| 240 | + function copyLink(resolvedSrc, dest, symlinkType) { | ||
| 240 | 241 | unlinkSync(dest); | |
| 241 | - return symlinkSync(resolvedSrc, dest); | ||
| 242 | + return symlinkSync(resolvedSrc, dest, symlinkType); | ||
| 242 | 243 | } | |
| 243 | 244 | ||
| 244 | 245 | module.exports = { cpSyncFn }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -336,8 +336,10 @@ async function onLink(destStat, src, dest, opts) { | |||
| 336 | 336 | if (!opts.verbatimSymlinks && !isAbsolute(resolvedSrc)) { | |
| 337 | 337 | resolvedSrc = resolve(dirname(src), resolvedSrc); | |
| 338 | 338 | } | |
| 339 | + const srcIsDir = fsBinding.internalModuleStat(src) === 1; | ||
| 340 | + const symlinkType = srcIsDir ? 'dir' : 'file'; | ||
| 339 | 341 | if (!destStat) { | |
| 340 | - return symlink(resolvedSrc, dest); | ||
| 342 | + return symlink(resolvedSrc, dest, symlinkType); | ||
| 341 | 343 | } | |
| 342 | 344 | let resolvedDest; | |
| 343 | 345 | try { | |
@@ -347,16 +349,14 @@ async function onLink(destStat, src, dest, opts) { | |||
| 347 | 349 | // Windows may throw UNKNOWN error. If dest already exists, | |
| 348 | 350 | // fs throws error anyway, so no need to guard against it here. | |
| 349 | 351 | if (err.code === 'EINVAL' || err.code === 'UNKNOWN') { | |
| 350 | - return symlink(resolvedSrc, dest); | ||
| 352 | + return symlink(resolvedSrc, dest, symlinkType); | ||
| 351 | 353 | } | |
| 352 | 354 | throw err; | |
| 353 | 355 | } | |
| 354 | 356 | if (!isAbsolute(resolvedDest)) { | |
| 355 | 357 | resolvedDest = resolve(dirname(dest), resolvedDest); | |
| 356 | 358 | } | |
| 357 | 359 | ||
| 358 | - const srcIsDir = fsBinding.internalModuleStat(src) === 1; | ||
| 359 | - | ||
| 360 | 360 | if (srcIsDir && isSrcSubdir(resolvedSrc, resolvedDest)) { | |
| 361 | 361 | throw new ERR_FS_CP_EINVAL({ | |
| 362 | 362 | message: `cannot copy ${resolvedSrc} to a subdirectory of self ` + | |
@@ -380,12 +380,12 @@ async function onLink(destStat, src, dest, opts) { | |||
| 380 | 380 | code: 'EINVAL', | |
| 381 | 381 | }); | |
| 382 | 382 | } | |
| 383 | - return copyLink(resolvedSrc, dest); | ||
| 383 | + return copyLink(resolvedSrc, dest, symlinkType); | ||
| 384 | 384 | } | |
| 385 | 385 | ||
| 386 | - async function copyLink(resolvedSrc, dest) { | ||
| 386 | + async function copyLink(resolvedSrc, dest, symlinkType) { | ||
| 387 | 387 | await unlink(dest); | |
| 388 | - return symlink(resolvedSrc, dest); | ||
| 388 | + return symlink(resolvedSrc, dest, symlinkType); | ||
| 389 | 389 | } | |
| 390 | 390 | ||
| 391 | 391 | module.exports = { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,46 @@ | |||
| 1 | + // This tests that cp with verbatimSymlinks and filter preserves | ||
| 2 | + // the directory symlink type on Windows (does not create a file symlink). | ||
| 3 | + import { mustNotMutateObjectDeep, isWindows } from '../common/index.mjs'; | ||
| 4 | + import { nextdir } from '../common/fs.js'; | ||
| 5 | + import assert from 'node:assert'; | ||
| 6 | + import { | ||
| 7 | + mkdirSync, | ||
| 8 | + writeFileSync, | ||
| 9 | + symlinkSync, | ||
| 10 | + readlinkSync, | ||
| 11 | + readdirSync, | ||
| 12 | + statSync, | ||
| 13 | + } from 'node:fs'; | ||
| 14 | + import { cp } from 'node:fs/promises'; | ||
| 15 | + import { join } from 'node:path'; | ||
| 16 | + | ||
| 17 | + import tmpdir from '../common/tmpdir.js'; | ||
| 18 | + tmpdir.refresh(); | ||
| 19 | + | ||
| 20 | + // Setup source with a relative directory symlink | ||
| 21 | + const src = nextdir(); | ||
| 22 | + mkdirSync(join(src, 'packages', 'my-lib'), mustNotMutateObjectDeep({ recursive: true })); | ||
| 23 | + writeFileSync(join(src, 'packages', 'my-lib', 'index.js'), 'module.exports = "hello"'); | ||
| 24 | + mkdirSync(join(src, 'linked'), mustNotMutateObjectDeep({ recursive: true })); | ||
| 25 | + symlinkSync(join('..', 'packages', 'my-lib'), join(src, 'linked', 'my-lib'), 'dir'); | ||
| 26 | + | ||
| 27 | + // Copy with verbatimSymlinks: true AND a filter function | ||
| 28 | + const dest = nextdir(); | ||
| 29 | + await cp(src, dest, mustNotMutateObjectDeep({ | ||
| 30 | + recursive: true, | ||
| 31 | + verbatimSymlinks: true, | ||
| 32 | + filter: () => true, | ||
| 33 | + })); | ||
| 34 | + | ||
| 35 | + // Verify the symlink target is preserved verbatim | ||
| 36 | + const link = readlinkSync(join(dest, 'linked', 'my-lib')); | ||
| 37 | + if (isWindows) { | ||
| 38 | + assert.strictEqual(link.toLowerCase(), join('..', 'packages', 'my-lib').toLowerCase()); | ||
| 39 | + } else { | ||
| 40 | + assert.strictEqual(link, join('..', 'packages', 'my-lib')); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + // Verify the symlink works as a directory (not a file symlink) | ||
| 44 | + const destSymlink = join(dest, 'linked', 'my-lib'); | ||
| 45 | + assert.ok(statSync(destSymlink).isDirectory(), 'symlink target should be accessible as a directory'); | ||
| 46 | + assert.deepStrictEqual(readdirSync(destSymlink), ['index.js']); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,46 @@ | |||
| 1 | + // This tests that cpSync with verbatimSymlinks and filter preserves | ||
| 2 | + // the directory symlink type on Windows (does not create a file symlink). | ||
| 3 | + import { mustNotMutateObjectDeep, isWindows } from '../common/index.mjs'; | ||
| 4 | + import { nextdir } from '../common/fs.js'; | ||
| 5 | + import assert from 'node:assert'; | ||
| 6 | + import { | ||
| 7 | + cpSync, | ||
| 8 | + mkdirSync, | ||
| 9 | + writeFileSync, | ||
| 10 | + symlinkSync, | ||
| 11 | + readlinkSync, | ||
| 12 | + readdirSync, | ||
| 13 | + statSync, | ||
| 14 | + } from 'node:fs'; | ||
| 15 | + import { join } from 'node:path'; | ||
| 16 | + | ||
| 17 | + import tmpdir from '../common/tmpdir.js'; | ||
| 18 | + tmpdir.refresh(); | ||
| 19 | + | ||
| 20 | + // Setup source with a relative directory symlink | ||
| 21 | + const src = nextdir(); | ||
| 22 | + mkdirSync(join(src, 'packages', 'my-lib'), mustNotMutateObjectDeep({ recursive: true })); | ||
| 23 | + writeFileSync(join(src, 'packages', 'my-lib', 'index.js'), 'module.exports = "hello"'); | ||
| 24 | + mkdirSync(join(src, 'linked'), mustNotMutateObjectDeep({ recursive: true })); | ||
| 25 | + symlinkSync(join('..', 'packages', 'my-lib'), join(src, 'linked', 'my-lib'), 'dir'); | ||
| 26 | + | ||
| 27 | + // Copy with verbatimSymlinks: true AND a filter function | ||
| 28 | + const dest = nextdir(); | ||
| 29 | + cpSync(src, dest, mustNotMutateObjectDeep({ | ||
| 30 | + recursive: true, | ||
| 31 | + verbatimSymlinks: true, | ||
| 32 | + filter: () => true, | ||
| 33 | + })); | ||
| 34 | + | ||
| 35 | + // Verify the symlink target is preserved verbatim | ||
| 36 | + const link = readlinkSync(join(dest, 'linked', 'my-lib')); | ||
| 37 | + if (isWindows) { | ||
| 38 | + assert.strictEqual(link.toLowerCase(), join('..', 'packages', 'my-lib').toLowerCase()); | ||
| 39 | + } else { | ||
| 40 | + assert.strictEqual(link, join('..', 'packages', 'my-lib')); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + // Verify the symlink works as a directory (not a file symlink) | ||
| 44 | + const destSymlink = join(dest, 'linked', 'my-lib'); | ||
| 45 | + assert.ok(statSync(destSymlink).isDirectory(), 'symlink target should be accessible as a directory'); | ||
| 46 | + assert.deepStrictEqual(readdirSync(destSymlink), ['index.js']); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments