fix: don't fail if a linked directory is not found (#3983)

close #3746
This commit is contained in:
Zoltan Kochan
2021-11-14 09:28:00 +02:00
committed by GitHub
parent 652c0bf0b1
commit 631877ebf5
6 changed files with 68 additions and 20 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/local-resolver": patch
---
Don't fail if a local linked directory is not found (unless it should be injected). This is the intended behavior of the "link:" protocol as per Yarn's docs.

View File

@@ -0,0 +1,6 @@
---
"@pnpm/symlink-dependency": patch
"pnpm": patch
---
Don't fail if a linked directory is not found. Just print a warning about it [#3746](https://github.com/pnpm/pnpm/issues/3746).

View File

@@ -151,3 +151,16 @@ test('fail if installing different types of dependencies in a project that uses
await install(manifest, newOpts)
})
test('installation should not fail if a linked dependency points to a directory that does not exist', async () => {
const project = prepareEmpty()
await install({
dependencies: {
'is-positive': '1.0.0',
'not-exists': 'link:../not-exists',
},
}, await testDefaults())
await project.has('is-positive')
})

View File

@@ -55,25 +55,32 @@ export default async function resolveLocal (
localDependencyManifest = await readProjectManifestOnly(spec.fetchSpec) as DependencyManifest
} catch (internalErr: any) { // eslint-disable-line
if (!existsSync(spec.fetchSpec)) {
throw new PnpmError('LINKED_PKG_DIR_NOT_FOUND',
`Could not install from "${spec.fetchSpec}" as it does not exist.`)
}
switch (internalErr.code) {
case 'ENOTDIR': {
throw new PnpmError('NOT_PACKAGE_DIRECTORY',
`Could not install from "${spec.fetchSpec}" as it is not a directory.`)
}
case 'ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND':
case 'ENOENT': {
if (wantedDependency.injected) {
throw new PnpmError('LINKED_PKG_DIR_NOT_FOUND',
`Could not install from "${spec.fetchSpec}" as it does not exist.`)
}
localDependencyManifest = {
name: path.basename(spec.fetchSpec),
version: '0.0.0',
}
break
}
default: {
throw internalErr
}
} else {
switch (internalErr.code) {
case 'ENOTDIR': {
throw new PnpmError('NOT_PACKAGE_DIRECTORY',
`Could not install from "${spec.fetchSpec}" as it is not a directory.`)
}
case 'ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND':
case 'ENOENT': {
localDependencyManifest = {
name: path.basename(spec.fetchSpec),
version: '0.0.0',
}
break
}
default: {
throw internalErr
}
}
}
}
return {

View File

@@ -107,14 +107,23 @@ test('fail when resolving tarball specified with the link: protocol', async () =
}
})
test('fail when resolving from not existing directory', async () => {
const wantedDependency = { pref: 'link:./dir-does-not-exist' }
test('fail when resolving from not existing directory an injected dependency', async () => {
const wantedDependency = { injected: true, pref: 'link:./dir-does-not-exist' }
const projectDir = __dirname
await expect(
resolveFromLocal(wantedDependency, { projectDir })
).rejects.toThrow(`Could not install from "${path.join(projectDir, 'dir-does-not-exist')}" as it does not exist.`)
})
test('do not fail when resolving from not existing directory', async () => {
const wantedDependency = { pref: 'link:./dir-does-not-exist' }
const resolveResult = await resolveFromLocal(wantedDependency, { projectDir: __dirname })
expect(resolveResult?.manifest).toStrictEqual({
name: 'dir-does-not-exist',
version: '0.0.0',
})
})
test('throw error when the path: protocol is used', async () => {
try {
await resolveFromLocal({ pref: 'path:..' }, { projectDir: __dirname })

View File

@@ -4,6 +4,7 @@ import {
DependencyType,
rootLogger,
} from '@pnpm/core-loggers'
import { globalWarn } from '@pnpm/logger'
import { DependenciesField } from '@pnpm/types'
import symlinkDir from 'symlink-dir'
@@ -43,15 +44,22 @@ export default async function symlinkDirectRootDependency (
}
}
const dependencyRealocation = await fs.realpath(dependencyLocation)
let dependencyRealLocation!: string
try {
dependencyRealLocation = await fs.realpath(dependencyLocation)
} catch (err: any) { // eslint-disable-line
if (err.code !== 'ENOENT') throw err
globalWarn(`Local dependency not found at ${dependencyLocation}`)
return
}
const dest = path.join(destModulesDirReal, importAs)
const { reused } = await symlinkDir(dependencyRealocation, dest)
const { reused } = await symlinkDir(dependencyRealLocation, dest)
if (reused) return // if the link was already present, don't log
rootLogger.debug({
added: {
dependencyType: opts.fromDependenciesField && DEP_TYPE_BY_DEPS_FIELD_NAME[opts.fromDependenciesField] as DependencyType,
linkedFrom: dependencyRealocation,
linkedFrom: dependencyRealLocation,
name: importAs,
realName: opts.linkedPackage.name,
version: opts.linkedPackage.version,