Skip to content

Commit 48c419f

Browse files
committed
patch parse error handling. Closes ds300#131
1 parent 2a3cc3c commit 48c419f

10 files changed

+2391
-1714
lines changed

package.json

+21-22
Original file line numberDiff line numberDiff line change
@@ -46,40 +46,39 @@
4646
},
4747
"devDependencies": {
4848
"@types/app-root-path": "^1.2.4",
49-
"@types/chalk": "^0.4.31",
5049
"@types/cross-spawn": "^6.0.0",
51-
"@types/fs-extra": "^4.0.0",
50+
"@types/fs-extra": "^5.0.5",
5251
"@types/is-ci": "^1.1.0",
53-
"@types/jest": "^23.3.12",
52+
"@types/jest": "^24.0.11",
5453
"@types/minimist": "^1.2.0",
55-
"@types/node": "^7.0.18",
56-
"@types/rimraf": "^0.0.28",
54+
"@types/node": "^11.11.6",
55+
"@types/rimraf": "^2.0.2",
5756
"@types/semver": "^5.5.0",
58-
"@types/tmp": "^0.0.33",
59-
"husky": "^0.13.3",
60-
"jest": "^23.6.0",
61-
"lint-staged": "^3.4.1",
62-
"np": "^2.15.0",
63-
"prettier": "^1.15.3",
57+
"@types/tmp": "^0.0.34",
58+
"husky": "^1.3.1",
59+
"jest": "^24.5.0",
60+
"lint-staged": "^8.1.5",
61+
"np": "^4.0.2",
62+
"prettier": "^1.16.4",
6463
"randomstring": "^1.1.5",
65-
"ts-jest": "^23.10.5",
66-
"ts-node": "6",
67-
"tslint": "^5.2.0",
68-
"typescript": "^3.2.2"
64+
"ts-jest": "^24.0.0",
65+
"ts-node": "8.0.3",
66+
"tslint": "^5.14.0",
67+
"typescript": "^3.4.0-rc"
6968
},
7069
"dependencies": {
7170
"@yarnpkg/lockfile": "^1.1.0",
72-
"chalk": "^1.1.3",
71+
"chalk": "^2.4.2",
7372
"cross-spawn": "^6.0.5",
74-
"fs-extra": "^4.0.1",
73+
"fs-extra": "^7.0.1",
7574
"is-ci": "^2.0.0",
76-
"klaw-sync": "^4.0.0",
75+
"klaw-sync": "^6.0.0",
7776
"minimist": "^1.2.0",
78-
"rimraf": "^2.6.2",
77+
"rimraf": "^2.6.3",
7978
"semver": "^5.6.0",
80-
"slash": "^1.0.0",
81-
"tmp": "^0.0.31",
82-
"update-notifier": "^2.4.0"
79+
"slash": "^2.0.0",
80+
"tmp": "^0.0.33",
81+
"update-notifier": "^2.5.0"
8382
},
8483
"files": [
8584
"index.js",

src/applyPatches.ts

+52-33
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { bold, green, red, yellow } from "chalk"
1+
import chalk from "chalk"
22
import { getPatchFiles } from "./patchFs"
33
import { executeEffects } from "./patch/apply"
4-
import { existsSync, readFileSync } from "fs-extra"
4+
import { existsSync } from "fs-extra"
55
import { join, resolve } from "./path"
66
import { posix } from "path"
7-
import { getPackageDetailsFromPatchFilename } from "./PackageDetails"
8-
import { parsePatchFile } from "./patch/parse"
7+
import {
8+
getPackageDetailsFromPatchFilename,
9+
PackageDetails,
10+
} from "./PackageDetails"
911
import { reversePatch } from "./patch/reverse"
1012
import isCi from "is-ci"
1113
import semver from "semver"
14+
import { readPatch } from "./patch/read"
1215

1316
// don't want to exit(1) on postinsall locally.
1417
// see https://github.com/ds300/patch-package/issues/86
@@ -34,9 +37,10 @@ function getInstalledPackageVersion({
3437
const packageDir = join(appPath, path)
3538
if (!existsSync(packageDir)) {
3639
console.log(
37-
`${yellow("Warning:")} Patch file found for package ${posix.basename(
38-
pathSpecifier,
39-
)}` + ` which is not present at ${packageDir}`,
40+
`${chalk.yellow(
41+
"Warning:",
42+
)} Patch file found for package ${posix.basename(pathSpecifier)}` +
43+
` which is not present at ${packageDir}`,
4044
)
4145

4246
return null
@@ -47,28 +51,28 @@ function getInstalledPackageVersion({
4751
return semver.valid(version)
4852
}
4953

50-
export const applyPatchesForApp = (
54+
export function applyPatchesForApp(
5155
appPath: string,
5256
reverse: boolean,
53-
patchDir: string = "patches",
54-
): void => {
57+
patchDir: string,
58+
): void {
5559
const patchesDirectory = join(appPath, patchDir)
5660
const files = findPatchFiles(patchesDirectory)
5761

5862
if (files.length === 0) {
59-
console.error(red("No patch files found"))
63+
console.error(chalk.red("No patch files found"))
6064
return
6165
}
6266

6367
files.forEach(filename => {
64-
const details = getPackageDetailsFromPatchFilename(filename)
68+
const packageDetails = getPackageDetailsFromPatchFilename(filename)
6569

66-
if (!details) {
70+
if (!packageDetails) {
6771
console.warn(`Unrecognized patch file in patches directory ${filename}`)
6872
return
6973
}
7074

71-
const { name, version, path, pathSpecifier } = details
75+
const { name, version, path, pathSpecifier } = packageDetails
7276

7377
const installedPackageVersion = getInstalledPackageVersion({
7478
appPath,
@@ -80,7 +84,14 @@ export const applyPatchesForApp = (
8084
return
8185
}
8286

83-
if (applyPatch(resolve(patchesDirectory, filename) as string, reverse)) {
87+
if (
88+
applyPatch({
89+
patchFilePath: resolve(patchesDirectory, filename) as string,
90+
reverse,
91+
packageDetails,
92+
patchDir,
93+
})
94+
) {
8495
// yay patch was applied successfully
8596
// print warning if version mismatch
8697
if (installedPackageVersion !== version) {
@@ -92,7 +103,9 @@ export const applyPatchesForApp = (
92103
path,
93104
})
94105
} else {
95-
console.log(`${bold(pathSpecifier)}@${version} ${green("✔")}`)
106+
console.log(
107+
`${chalk.bold(pathSpecifier)}@${version} ${chalk.green("✔")}`,
108+
)
96109
}
97110
} else {
98111
// completely failed to apply patch
@@ -119,12 +132,18 @@ export const applyPatchesForApp = (
119132
})
120133
}
121134

122-
export const applyPatch = (
123-
patchFilePath: string,
124-
reverse: boolean,
125-
): boolean => {
126-
const patchFileContents = readFileSync(patchFilePath).toString()
127-
const patch = parsePatchFile(patchFileContents)
135+
export function applyPatch({
136+
patchFilePath,
137+
reverse,
138+
packageDetails,
139+
patchDir,
140+
}: {
141+
patchFilePath: string
142+
reverse: boolean
143+
packageDetails: PackageDetails
144+
patchDir: string
145+
}): boolean {
146+
const patch = readPatch({ patchFilePath, packageDetails, patchDir })
128147
try {
129148
executeEffects(reverse ? reversePatch(patch) : patch, { dryRun: false })
130149
} catch (e) {
@@ -152,18 +171,18 @@ function printVersionMismatchWarning({
152171
path: string
153172
}) {
154173
console.warn(`
155-
${red("Warning:")} patch-package detected a patch file version mismatch
174+
${chalk.red("Warning:")} patch-package detected a patch file version mismatch
156175
157176
Don't worry! This is probably fine. The patch was still applied
158177
successfully. Here's the deets:
159178
160179
Patch file created for
161180
162-
${packageName}@${bold(originalVersion)}
181+
${packageName}@${chalk.bold(originalVersion)}
163182
164183
applied to
165184
166-
${packageName}@${bold(actualVersion)}
185+
${packageName}@${chalk.bold(actualVersion)}
167186
168187
At path
169188
@@ -173,7 +192,7 @@ ${red("Warning:")} patch-package detected a patch file version mismatch
173192
breakage even though the patch was applied successfully. Make sure the package
174193
still behaves like you expect (you wrote tests, right?) and then run
175194
176-
${bold(`patch-package ${pathSpecifier}`)}
195+
${chalk.bold(`patch-package ${pathSpecifier}`)}
177196
178197
to update the version in the patch file name and make this warning go away.
179198
`)
@@ -191,8 +210,8 @@ function printBrokenPatchFileError({
191210
pathSpecifier: string
192211
}) {
193212
console.error(`
194-
${red.bold("**ERROR**")} ${red(
195-
`Failed to apply patch for package ${bold(packageName)} at path`,
213+
${chalk.red.bold("**ERROR**")} ${chalk.red(
214+
`Failed to apply patch for package ${chalk.bold(packageName)} at path`,
196215
)}
197216
198217
${path}
@@ -231,13 +250,13 @@ function printPatchApplictionFailureError({
231250
pathSpecifier: string
232251
}) {
233252
console.error(`
234-
${red.bold("**ERROR**")} ${red(
235-
`Failed to apply patch for package ${bold(packageName)} at path`,
253+
${chalk.red.bold("**ERROR**")} ${chalk.red(
254+
`Failed to apply patch for package ${chalk.bold(packageName)} at path`,
236255
)}
237256
238257
${path}
239258
240-
This error was caused because ${bold(packageName)} has changed since you
259+
This error was caused because ${chalk.bold(packageName)} has changed since you
241260
made the patch file for it. This introduced conflicts with your patch,
242261
just like a merge conflict in Git when separate incompatible changes are
243262
made to the same piece of code.
@@ -256,7 +275,7 @@ ${red.bold("**ERROR**")} ${red(
256275
257276
Info:
258277
Patch file: patches/${patchFileName}
259-
Patch was made for version: ${green.bold(originalVersion)}
260-
Installed version: ${red.bold(actualVersion)}
278+
Patch was made for version: ${chalk.green.bold(originalVersion)}
279+
Installed version: ${chalk.red.bold(actualVersion)}
261280
`)
262281
}

src/index.ts

+34-20
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { bold, italic } from "chalk"
1+
import chalk from "chalk"
22
import process from "process"
33
import minimist from "minimist"
44

@@ -8,6 +8,8 @@ import { makePatch } from "./makePatch"
88
import { makeRegExp } from "./makeRegExp"
99
import { detectPackageManager } from "./detectPackageManager"
1010
import { join } from "./path"
11+
import { normalize, sep } from "path"
12+
import slash = require("slash")
1113

1214
const appPath = getAppRootPath()
1315
const argv = minimist(process.argv.slice(2), {
@@ -23,7 +25,7 @@ const argv = minimist(process.argv.slice(2), {
2325
const packageNames = argv._
2426

2527
console.log(
26-
bold("patch-package"),
28+
chalk.bold("patch-package"),
2729
// tslint:disable-next-line:no-var-requires
2830
require(join(__dirname, "../package.json")).version,
2931
)
@@ -33,32 +35,42 @@ if (argv.version || argv.v) {
3335
} else if (argv.help || argv.h) {
3436
printHelp()
3537
} else {
38+
const packageManager = detectPackageManager(
39+
appPath,
40+
argv["use-yarn"] ? "yarn" : null,
41+
)
42+
const patchDir = slash(normalize((argv["patch-dir"] || "patches") + sep))
43+
if (patchDir.startsWith("/")) {
44+
throw new Error("--patch-dir must be a relative path")
45+
}
3646
if (packageNames.length) {
37-
const include = makeRegExp(
47+
const includePaths = makeRegExp(
3848
argv.include,
3949
"include",
4050
/.*/,
4151
argv["case-sensitive-path-filtering"],
4252
)
43-
const exclude = makeRegExp(
53+
const excludePaths = makeRegExp(
4454
argv.exclude,
4555
"exclude",
4656
/package\.json$/,
4757
argv["case-sensitive-path-filtering"],
4858
)
49-
packageNames.forEach((packageName: string) => {
50-
makePatch(
51-
packageName,
59+
60+
packageNames.forEach((packagePathSpecifier: string) => {
61+
makePatch({
62+
packagePathSpecifier,
5263
appPath,
53-
detectPackageManager(appPath, argv["use-yarn"] ? "yarn" : null),
54-
include,
55-
exclude,
56-
argv["patch-dir"],
57-
)
64+
packageManager,
65+
includePaths,
66+
excludePaths,
67+
patchDir,
68+
})
5869
})
5970
} else {
6071
console.log("Applying patches...")
61-
applyPatchesForApp(appPath, !!argv["reverse"], argv["patch-dir"])
72+
const reverse = !!argv["reverse"]
73+
applyPatchesForApp(appPath, reverse, patchDir)
6274
}
6375
}
6476

@@ -69,9 +81,9 @@ Usage:
6981
1. Patching packages
7082
====================
7183
72-
${bold("patch-package")}
84+
${chalk.bold("patch-package")}
7385
74-
Without arguments, the ${bold(
86+
Without arguments, the ${chalk.bold(
7587
"patch-package",
7688
)} command will attempt to find and apply
7789
patch files to your project. It looks for files named like
@@ -81,34 +93,36 @@ Usage:
8193
2. Creating patch files
8294
=======================
8395
84-
${bold("patch-package")} <package-name>${italic("[ <package-name>]")}
96+
${chalk.bold("patch-package")} <package-name>${chalk.italic(
97+
"[ <package-name>]",
98+
)}
8599
86100
When given package names as arguments, patch-package will create patch files
87101
based on any changes you've made to the versions installed by yarn/npm.
88102
89103
Options:
90104
91-
${bold("--use-yarn")}
105+
${chalk.bold("--use-yarn")}
92106
93107
By default, patch-package checks whether you use npm or yarn based on
94108
which lockfile you have. If you have both, it uses npm by default.
95109
Set this option to override that default and always use yarn.
96110
97-
${bold("--exclude <regexp>")}
111+
${chalk.bold("--exclude <regexp>")}
98112
99113
Ignore paths matching the regexp when creating patch files.
100114
Paths are relative to the root dir of the package to be patched.
101115
102116
Default: 'package\\.json$'
103117
104-
${bold("--include <regexp>")}
118+
${chalk.bold("--include <regexp>")}
105119
106120
Only consider paths matching the regexp when creating patch files.
107121
Paths are relative to the root dir of the package to be patched.
108122
109123
Default '.*'
110124
111-
${bold("--case-sensitive-path-filtering")}
125+
${chalk.bold("--case-sensitive-path-filtering")}
112126
113127
Make regexps used in --include or --exclude filters case-sensitive.
114128
`)

0 commit comments

Comments
 (0)