Skip to content

Commit 3fe24b3

Browse files
committed
Stash wip
1 parent 97f1122 commit 3fe24b3

File tree

3 files changed

+213
-71
lines changed

3 files changed

+213
-71
lines changed

src/detectPackageManager.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ import { join } from "./path"
33
import chalk from "chalk"
44
import process from "process"
55
import findWorkspaceRoot from "find-yarn-workspace-root"
6+
import { spawnSafeSync } from "./spawnSafe"
7+
import { parse } from "semver"
68

7-
export type PackageManager = "yarn" | "npm" | "npm-shrinkwrap"
9+
export type PackageManager = "yarn" | "berry" | "npm" | "npm-shrinkwrap"
810

911
function printNoYarnLockfileError() {
1012
console.error(`
@@ -63,7 +65,31 @@ export const detectPackageManager = (
6365
return shrinkWrapExists ? "npm-shrinkwrap" : "npm"
6466
}
6567
} else if (yarnLockExists || findWorkspaceRoot()) {
66-
return "yarn"
68+
try {
69+
const version = spawnSafeSync("yarn", ["--version"], {
70+
cwd: appRootPath,
71+
})
72+
.stdout.toString()
73+
.trim()
74+
const majorVersion = parse(version)?.major ?? null
75+
if (majorVersion === null) {
76+
console.error(`
77+
${chalk.red.bold("**ERROR**")} ${chalk.red(
78+
`Unable to parse the result of 'yarn --version': "${version}" `,
79+
)}
80+
`)
81+
process.exit(1)
82+
}
83+
84+
return majorVersion === 1 ? "yarn" : "berry"
85+
} catch (e) {
86+
console.error(`
87+
${chalk.red.bold("**ERROR**")} ${chalk.red(
88+
`Unable to execute 'yarn --version'`,
89+
)}
90+
`)
91+
process.exit(1)
92+
}
6793
} else {
6894
printNoLockfilesError()
6995
process.exit(1)

src/index.ts

Lines changed: 70 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,65 +11,75 @@ import { join } from "./path"
1111
import { normalize, sep } from "path"
1212
import slash = require("slash")
1313

14-
const appPath = getAppRootPath()
15-
const argv = minimist(process.argv.slice(2), {
16-
boolean: [
17-
"use-yarn",
18-
"case-sensitive-path-filtering",
19-
"reverse",
20-
"help",
21-
"version",
22-
],
23-
string: ["patch-dir"],
24-
})
25-
const packageNames = argv._
26-
27-
console.log(
28-
chalk.bold("patch-package"),
29-
// tslint:disable-next-line:no-var-requires
30-
require(join(__dirname, "../package.json")).version,
31-
)
32-
33-
if (argv.version || argv.v) {
34-
// noop
35-
} else if (argv.help || argv.h) {
36-
printHelp()
37-
} else {
38-
const patchDir = slash(normalize((argv["patch-dir"] || "patches") + sep))
39-
if (patchDir.startsWith("/")) {
40-
throw new Error("--patch-dir must be a relative path")
41-
}
42-
if (packageNames.length) {
43-
const includePaths = makeRegExp(
44-
argv.include,
45-
"include",
46-
/.*/,
47-
argv["case-sensitive-path-filtering"],
48-
)
49-
const excludePaths = makeRegExp(
50-
argv.exclude,
51-
"exclude",
52-
/package\.json$/,
53-
argv["case-sensitive-path-filtering"],
54-
)
55-
const packageManager = detectPackageManager(
56-
appPath,
57-
argv["use-yarn"] ? "yarn" : null,
58-
)
59-
packageNames.forEach((packagePathSpecifier: string) => {
60-
makePatch({
61-
packagePathSpecifier,
62-
appPath,
63-
packageManager,
64-
includePaths,
65-
excludePaths,
66-
patchDir,
67-
})
68-
})
14+
async function main() {
15+
const appPath = getAppRootPath()
16+
const argv = minimist(process.argv.slice(2), {
17+
boolean: [
18+
"use-yarn",
19+
"case-sensitive-path-filtering",
20+
"reverse",
21+
"help",
22+
"version",
23+
],
24+
string: ["patch-dir"],
25+
})
26+
const packageNames = argv._
27+
28+
console.log(
29+
chalk.bold("patch-package"),
30+
// tslint:disable-next-line:no-var-requires
31+
require(join(__dirname, "../package.json")).version,
32+
)
33+
34+
const packageManager = detectPackageManager(
35+
appPath,
36+
argv["use-yarn"] ? "yarn" : null,
37+
)
38+
39+
if (argv.version || argv.v) {
40+
// noop
41+
} else if (argv.help || argv.h) {
42+
printHelp()
6943
} else {
70-
console.log("Applying patches...")
71-
const reverse = !!argv["reverse"]
72-
applyPatchesForApp({ appPath, reverse, patchDir })
44+
const patchDir = slash(normalize((argv["patch-dir"] || "patches") + sep))
45+
if (patchDir.startsWith("/")) {
46+
throw new Error("--patch-dir must be a relative path")
47+
}
48+
if (packageNames.length) {
49+
const includePaths = makeRegExp(
50+
argv.include,
51+
"include",
52+
/.*/,
53+
argv["case-sensitive-path-filtering"],
54+
)
55+
const excludePaths = makeRegExp(
56+
argv.exclude,
57+
"exclude",
58+
/package\.json$/,
59+
argv["case-sensitive-path-filtering"],
60+
)
61+
62+
for (const packagePathSpecifier of packageNames) {
63+
await makePatch({
64+
packagePathSpecifier,
65+
appPath,
66+
packageManager,
67+
includePaths,
68+
excludePaths,
69+
patchDir,
70+
})
71+
}
72+
} else {
73+
if (packageManager === "berry") {
74+
console.log(
75+
"You're using yarn 2, so running `patch-package` without arguments has no effect! Instead your patches will be applied by yarn itself :)",
76+
)
77+
process.exit(0)
78+
}
79+
console.log("Applying patches...")
80+
const reverse = !!argv["reverse"]
81+
applyPatchesForApp({ appPath, reverse, patchDir })
82+
}
7383
}
7484
}
7585

@@ -126,3 +136,5 @@ Usage:
126136
Make regexps used in --include or --exclude filters case-sensitive.
127137
`)
128138
}
139+
140+
main()

src/makePatch.ts

Lines changed: 115 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@ import {
99
mkdirSync,
1010
unlinkSync,
1111
mkdirpSync,
12+
readdirSync,
1213
} from "fs-extra"
1314
import { sync as rimraf } from "rimraf"
1415
import { copySync } from "fs-extra"
15-
import { dirSync } from "tmp"
1616
import { getPatchFiles } from "./patchFs"
1717
import {
1818
getPatchDetailsFromCliString,
1919
getPackageDetailsFromPatchFilename,
20+
PackageDetails,
2021
} from "./PackageDetails"
2122
import { resolveRelativeFileDependencies } from "./resolveRelativeFileDependencies"
2223
import { getPackageResolution } from "./getPackageResolution"
2324
import { parsePatchFile } from "./patch/parse"
2425
import { gzipSync } from "zlib"
26+
import readline from "readline"
27+
import { dirSync } from "tmp"
2528

2629
function printNoPackageFoundError(
2730
packageName: string,
@@ -32,9 +35,105 @@ function printNoPackageFoundError(
3235
3336
File not found: ${packageJsonPath}`,
3437
)
38+
process.exit(1)
39+
}
40+
41+
function printNoUnpluggedPackageFound({
42+
packageName,
43+
unpluggedDir,
44+
}: {
45+
packageName: string
46+
unpluggedDir: string
47+
}) {
48+
console.error(
49+
`Could not find an unnplugged version of ${packageName} in ${unpluggedDir}`,
50+
)
51+
process.exit(1)
3552
}
3653

37-
export function makePatch({
54+
async function findRelativePackagePath({
55+
appPath,
56+
packageDetails,
57+
packageManager,
58+
}: {
59+
appPath: string
60+
packageDetails: PackageDetails
61+
packageManager: PackageManager
62+
}): Promise<string> {
63+
if (packageManager === "berry") {
64+
const unpluggedDir = join(appPath, ".yarn/unplugged")
65+
if (!existsSync(unpluggedDir)) {
66+
printNoUnpluggedPackageFound({
67+
packageName: packageDetails.name,
68+
unpluggedDir,
69+
})
70+
}
71+
const dirs = readdirSync(unpluggedDir).filter(
72+
name =>
73+
name.startsWith(packageDetails.name) &&
74+
name
75+
.slice(packageDetails.name.length)
76+
// optional protocol (e.g. npm) - optional version - hash
77+
.match(/^(-\w+)?(-\d+\.\d+\.\d+.*?)?-[0-9a-f]+$/),
78+
)
79+
if (dirs.length === 0) {
80+
printNoUnpluggedPackageFound({
81+
packageName: packageDetails.name,
82+
unpluggedDir,
83+
})
84+
}
85+
if (dirs.length > 1) {
86+
const rl = readline.createInterface({
87+
input: process.stdin,
88+
output: process.stdout,
89+
})
90+
91+
return new Promise<string>(resolvePromise => {
92+
rl.question(
93+
`There are mulitple unplugged versions of ${chalk.bold(
94+
packageDetails.name,
95+
)}\n\n` +
96+
dirs
97+
.map(
98+
(dir, index) =>
99+
`${chalk.cyan.bold(index.toString())}${chalk.gray(
100+
")",
101+
)} ${dir}`,
102+
)
103+
.join("\n") +
104+
"\n\n" +
105+
`Please select a ${chalk.cyan.bold("version")} ` +
106+
chalk.yellow.bold(">> "),
107+
answer => {
108+
const index = Number(answer.trim())
109+
if (index != null && index >= 0 && index < dirs.length) {
110+
resolvePromise(
111+
join(
112+
".yarn/unplugged",
113+
dirs[index],
114+
"node_modules",
115+
packageDetails.name,
116+
),
117+
)
118+
} else {
119+
console.error(chalk.red.bold("That didn't work."))
120+
console.error(
121+
`Please try again and provide a number in the range 0-${dirs.length -
122+
1}`,
123+
)
124+
process.exit(1)
125+
}
126+
},
127+
)
128+
})
129+
}
130+
return join(".yarn/unplugged", dirs[0], "node_modules", packageDetails.name)
131+
}
132+
133+
return packageDetails.path
134+
}
135+
136+
export async function makePatch({
38137
packagePathSpecifier,
39138
appPath,
40139
packageManager,
@@ -55,17 +154,22 @@ export function makePatch({
55154
console.error("No such package", packagePathSpecifier)
56155
return
57156
}
58-
const appPackageJson = require(join(appPath, "package.json"))
59-
const packagePath = join(appPath, packageDetails.path)
60-
const packageJsonPath = join(packagePath, "package.json")
61-
62-
if (!existsSync(packageJsonPath)) {
63-
printNoPackageFoundError(packagePathSpecifier, packageJsonPath)
64-
process.exit(1)
157+
const appJson = require(join(appPath, "package.json"))
158+
const relativePackagePath = await findRelativePackagePath({
159+
appPath,
160+
packageDetails,
161+
packageManager,
162+
})
163+
164+
const appPackageJsonPath = join(appPath, relativePackagePath, "package.json")
165+
166+
if (!existsSync(appPackageJsonPath)) {
167+
// won't happen with berry
168+
printNoPackageFoundError(packagePathSpecifier, appPackageJsonPath)
65169
}
66170

67171
const tmpRepo = dirSync({ unsafeCleanup: true })
68-
const tmpRepoPackagePath = join(tmpRepo.name, packageDetails.path)
172+
const tmpRepoPackagePath = join(tmpRepo.name, relativePackagePath)
69173
const tmpRepoNpmRoot = tmpRepoPackagePath.slice(
70174
0,
71175
-`/node_modules/${packageDetails.name}`.length,
@@ -92,7 +196,7 @@ export function makePatch({
92196
},
93197
resolutions: resolveRelativeFileDependencies(
94198
appPath,
95-
appPackageJson.resolutions || {},
199+
appJson.resolutions || {},
96200
),
97201
}),
98202
)

0 commit comments

Comments
 (0)