Skip to content

Commit 497089b

Browse files
committed
fix: handle parallel installs
1 parent f17384e commit 497089b

15 files changed

+169
-39
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ jobs:
3232
env:
3333
TARGET_BRANCH: ${{github.event.pull_request.base.ref}}
3434

35+
- name: 'Check for type errors'
36+
run: yarn typecheck
37+
3538
build:
3639
strategy:
3740
fail-fast: false

.pnp.cjs

Lines changed: 40 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

mkshims.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ async function main() {
5555
const remapPath = (p: string) => path.resolve(__dirname, path.relative(virtualNodewinDir, p));
5656

5757
const easyStatFs = Object.assign(Object.create(fs), {
58-
readFile: (p: string, encoding: string, cb: (err: any, str: string) => void) => fs.readFile(remapPath(p), encoding, cb),
58+
readFile: (p: string, encoding: BufferEncoding, cb: (err: any, str: string) => void) => fs.readFile(remapPath(p), encoding, cb),
5959
stat: (p: string, cb: () => void) => fs.stat(remapPath(p), cb),
6060
});
6161

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
"@babel/preset-typescript": "^7.13.0",
2828
"@types/debug": "^4.1.5",
2929
"@types/jest": "^26.0.23",
30-
"@types/node": "^13.9.2",
30+
"@types/node": "^17.0.10",
31+
"@types/rimraf": "^3.0.2",
3132
"@types/semver": "^7.1.0",
3233
"@types/tar": "^4.0.3",
3334
"@types/which": "^1.3.2",
@@ -43,6 +44,7 @@
4344
"eslint-plugin-arca": "^0.9.5",
4445
"jest": "^26.0.0",
4546
"nock": "^13.0.4",
47+
"rimraf": "^3.0.2",
4648
"semver": "^7.1.3",
4749
"supports-color": "^7.1.0",
4850
"tar": "^6.0.1",
@@ -60,6 +62,7 @@
6062
"corepack": "ts-node ./sources/main.ts",
6163
"prepack": "node ./.yarn/releases/*.*js build",
6264
"postpack": "rm -rf dist shims",
65+
"typecheck": "tsc --noEmit",
6366
"test": "yarn jest"
6467
},
6568
"files": [

sources/corepackUtils.ts

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -87,39 +87,50 @@ export async function installVersion(installTarget: string, locator: Locator, {s
8787
const url = spec.url.replace(`{}`, locator.reference);
8888
debugUtils.log(`Installing ${locator.name}@${locator.reference} from ${url}`);
8989

90-
return await fsUtils.mutex(installFolder, async () => {
91-
// Creating a temporary folder inside the install folder means that we
92-
// are sure it'll be in the same drive as the destination, so we can
93-
// just move it there atomically once we are done
90+
// Creating a temporary folder inside the install folder means that we
91+
// are sure it'll be in the same drive as the destination, so we can
92+
// just move it there atomically once we are done
9493

95-
const tmpFolder = folderUtils.getTemporaryFolder(installTarget);
96-
const stream = await httpUtils.fetchUrlStream(url);
94+
const tmpFolder = folderUtils.getTemporaryFolder(installTarget);
95+
const stream = await httpUtils.fetchUrlStream(url);
9796

98-
const parsedUrl = new URL(url);
99-
const ext = path.posix.extname(parsedUrl.pathname);
97+
const parsedUrl = new URL(url);
98+
const ext = path.posix.extname(parsedUrl.pathname);
10099

101-
let outputFile: string | null = null;
100+
let outputFile: string | null = null;
102101

103-
let sendTo: any;
104-
if (ext === `.tgz`) {
105-
sendTo = tar.x({strip: 1, cwd: tmpFolder});
106-
} else if (ext === `.js`) {
107-
outputFile = path.join(tmpFolder, path.posix.basename(parsedUrl.pathname));
108-
sendTo = fs.createWriteStream(outputFile);
109-
}
102+
let sendTo: any;
103+
if (ext === `.tgz`) {
104+
sendTo = tar.x({strip: 1, cwd: tmpFolder});
105+
} else if (ext === `.js`) {
106+
outputFile = path.join(tmpFolder, path.posix.basename(parsedUrl.pathname));
107+
sendTo = fs.createWriteStream(outputFile);
108+
}
110109

111-
stream.pipe(sendTo);
110+
stream.pipe(sendTo);
112111

113-
await new Promise(resolve => {
114-
sendTo.on(`finish`, resolve);
115-
});
112+
await new Promise(resolve => {
113+
sendTo.on(`finish`, resolve);
114+
});
116115

117-
await fs.promises.mkdir(path.dirname(installFolder), {recursive: true});
116+
await fs.promises.mkdir(path.dirname(installFolder), {recursive: true});
117+
try {
118118
await fs.promises.rename(tmpFolder, installFolder);
119+
} catch (err) {
120+
if (
121+
err.code === `ENOTEMPTY` ||
122+
// On Windows the error code is EPERM so we check if it's because its a directory
123+
(err.code === `EPERM` && (await fs.promises.stat(installFolder)).isDirectory())
124+
) {
125+
debugUtils.log(`Another instance of corepack installed ${locator.name}@${locator.reference}`);
126+
await fsUtils.rimraf(tmpFolder);
127+
} else {
128+
throw err;
129+
}
130+
}
119131

120-
debugUtils.log(`Install finished`);
121-
return installFolder;
122-
});
132+
debugUtils.log(`Install finished`);
133+
return installFolder;
123134
}
124135

125136
export async function runVersion(installSpec: { location: string, spec: PackageManagerSpec }, locator: Locator, binName: string, args: Array<string>, context: Context) {

0 commit comments

Comments
 (0)