fix: pnpm patch should ignore files that are not included in the patched package (#6596)

close #6565

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
Kirk Lin
2023-06-08 08:33:28 +08:00
committed by GitHub
parent 29a2a69806
commit f0d68ab2fd
5 changed files with 86 additions and 1 deletions

View File

@@ -5,14 +5,17 @@ import { type Config, types as allTypes } from '@pnpm/config'
import { install } from '@pnpm/plugin-commands-installation'
import { readPackageJsonFromDir } from '@pnpm/read-package-json'
import { tryReadProjectManifest } from '@pnpm/read-project-manifest'
import glob from 'fast-glob'
import normalizePath from 'normalize-path'
import pick from 'ramda/src/pick'
import equals from 'ramda/src/equals'
import execa from 'safe-execa'
import escapeStringRegexp from 'escape-string-regexp'
import renderHelp from 'render-help'
import tempy from 'tempy'
import { writePackage } from './writePackage'
import { parseWantedDependency } from '@pnpm/parse-wanted-dependency'
import packlist from 'npm-packlist'
export const rcOptionsTypes = cliOptionsTypes
@@ -49,7 +52,10 @@ export async function handler (opts: install.InstallCommandOptions & Pick<Config
const pkgNameAndVersion = `${patchedPkgManifest.name}@${patchedPkgManifest.version}`
const srcDir = tempy.directory()
await writePackage(parseWantedDependency(pkgNameAndVersion), srcDir, opts)
const patchContent = await diffFolders(srcDir, userDir)
const patchedPkgDir = await preparePkgFilesForDiff(userDir)
const patchContent = await diffFolders(srcDir, patchedPkgDir)
const patchFileName = pkgNameAndVersion.replace('/', '__')
await fs.promises.writeFile(path.join(patchesDir, `${patchFileName}.patch`), patchContent, 'utf8')
const { writeProjectManifest, manifest } = await tryReadProjectManifest(lockfileDir)
@@ -129,3 +135,36 @@ function removeTrailingAndLeadingSlash (p: string) {
}
return p
}
/**
* Link files from the source directory to a new temporary directory,
* but only if not all files in the source directory should be included in the package.
* If all files should be included, return the original source directory without creating any links.
* This is required in order for the diff to not include files that are not part of the package.
*/
async function preparePkgFilesForDiff (src: string): Promise<string> {
const files = Array.from(new Set((await packlist({ path: src })).map((f) => path.join(f))))
// If there are no extra files in the source directories, then there is no reason
// to copy.
if (await areAllFilesInPkg(files, src)) {
return src
}
const dest = tempy.directory()
await Promise.all(
files.map(async (file) => {
const srcFile = path.join(src, file)
const destFile = path.join(dest, file)
const destDir = path.dirname(destFile)
await fs.promises.mkdir(destDir, { recursive: true })
await fs.promises.link(srcFile, destFile)
})
)
return dest
}
async function areAllFilesInPkg (files: string[], basePath: string) {
const allFiles = await glob('**', {
cwd: basePath,
})
return equals(allFiles.sort(), files.sort())
}