Skip to content

Commit

Permalink
fix: don't break when injecting a dependency with broken symlinks (#5599
Browse files Browse the repository at this point in the history
)

close #5598
  • Loading branch information
zkochan committed Nov 7, 2022
1 parent 46852d4 commit 6710d9d
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/great-jeans-teach.md
@@ -0,0 +1,5 @@
---
"@pnpm/directory-fetcher": major
---

@pnpm/logger added to peer dependencies.
6 changes: 6 additions & 0 deletions .changeset/young-toes-talk.md
@@ -0,0 +1,6 @@
---
"@pnpm/directory-fetcher": patch
"pnpm": patch
---

Installation shouldn't fail when the injected dependency has broken symlinks. The broken symlinks should be just skipped [#5598](https://github.com/pnpm/pnpm/issues/5598).
3 changes: 3 additions & 0 deletions packages/directory-fetcher/package.json
Expand Up @@ -30,6 +30,9 @@
"url": "https://github.com/pnpm/pnpm/issues"
},
"homepage": "https://github.com/pnpm/pnpm/blob/main/packages/directory-fetcher#readme",
"peerDependencies": {
"@pnpm/logger": "^5.0.0"
},
"dependencies": {
"@pnpm/fetcher-base": "workspace:*",
"@pnpm/read-project-manifest": "workspace:*",
Expand Down
17 changes: 15 additions & 2 deletions packages/directory-fetcher/src/index.ts
@@ -1,10 +1,13 @@
import { promises as fs } from 'fs'
import { promises as fs, Stats } from 'fs'
import path from 'path'
import type { DirectoryFetcher, DirectoryFetcherOptions } from '@pnpm/fetcher-base'
import { logger } from '@pnpm/logger'
import { safeReadProjectManifestOnly } from '@pnpm/read-project-manifest'
import fromPairs from 'ramda/src/fromPairs'
import packlist from 'npm-packlist'

const directoryFetcherLogger = logger('directory-fetcher')

export interface CreateDirectoryFetcherOptions {
includeOnlyPackageFiles?: boolean
}
Expand Down Expand Up @@ -65,7 +68,17 @@ async function _fetchAllFilesFromDir (
.filter((file) => file !== 'node_modules')
.map(async (file) => {
const filePath = path.join(dir, file)
const stat = await fs.stat(filePath)
let stat: Stats
try {
stat = await fs.stat(filePath)
} catch (err: any) { // eslint-disable-line @typescript-eslint/no-explicit-any
// Broken symlinks are skipped
if (err.code === 'ENOENT') {
directoryFetcherLogger.debug({ brokenSymlink: filePath })
return
}
throw err
}
const relativeSubdir = `${relativeDir}${relativeDir ? '/' : ''}${file}`
if (stat.isDirectory()) {
const subFilesIndex = await _fetchAllFilesFromDir(filePath, relativeSubdir)
Expand Down
Empty file.
@@ -0,0 +1,4 @@
{
"name": "simple-pkg",
"version": "0.0.0"
}
31 changes: 31 additions & 0 deletions packages/directory-fetcher/test/index.ts
@@ -1,9 +1,15 @@
/// <reference path="../../../typings/index.d.ts"/>
import path from 'path'
import { createDirectoryFetcher } from '@pnpm/directory-fetcher'
// @ts-expect-error
import { debug } from '@pnpm/logger'
import { fixtures } from '@pnpm/test-fixtures'

const f = fixtures(__dirname)
jest.mock('@pnpm/logger', () => {
const debug = jest.fn()
return ({ debug, logger: () => ({ debug }) })
})

test('fetch including only package files', async () => {
process.chdir(f.find('simple-pkg'))
Expand Down Expand Up @@ -79,3 +85,28 @@ test('fetch a directory that has no package.json', async () => {
'index.js',
])
})

test('fetch does not fail on package with broken symlink', async () => {
debug.mockClear()
process.chdir(f.find('pkg-with-broken-symlink'))
const fetcher = createDirectoryFetcher()

// eslint-disable-next-line
const fetchResult = await fetcher.directory({} as any, {
directory: '.',
type: 'directory',
}, {
lockfileDir: process.cwd(),
})

expect(fetchResult.local).toBe(true)
expect(fetchResult.packageImportMethod).toBe('hardlink')
expect(fetchResult.filesIndex['package.json']).toBe(path.resolve('package.json'))

// Only those files are included which would get published
expect(Object.keys(fetchResult.filesIndex).sort()).toStrictEqual([
'index.js',
'package.json',
])
expect(debug).toHaveBeenCalledWith({ brokenSymlink: path.resolve('not-exists') })
})
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6710d9d

Please sign in to comment.