Skip to content

Commit 5cfc6c9

Browse files
authored
fix: handle parallel installs (#84)
* fix: handle parallel installs * build: skip unnecessary shims
1 parent f17384e commit 5cfc6c9

15 files changed

+184
-45
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.
3.23 KB
Binary file not shown.
Binary file not shown.
-112 KB
Binary file not shown.
324 KB
Binary file not shown.
3.75 KB
Binary file not shown.

mkshims.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@ import path from 'path';
55
import {Engine} from './sources/Engine';
66
import {SupportedPackageManagerSet} from './sources/types';
77

8-
const EXCLUDE_SHIMS = new Set([
9-
`vcc.js`,
10-
]);
8+
function shouldGenerateShim(name: string) {
9+
if (name === 'vcc.js') {
10+
return false;
11+
} else if (name.startsWith('vendors')) {
12+
return false;
13+
}
14+
return true;
15+
}
1116

1217
const engine = new Engine();
1318

@@ -38,7 +43,7 @@ async function main() {
3843
}
3944

4045
for (const binaryName of fs.readdirSync(distDir)) {
41-
if (EXCLUDE_SHIMS.has(binaryName))
46+
if (shouldGenerateShim(binaryName) === false)
4247
continue;
4348

4449
await cmdShim(path.join(distDir, binaryName), path.join(shimsDir, path.basename(binaryName, `.js`)), {createCmdFile: true});
@@ -55,12 +60,16 @@ async function main() {
5560
const remapPath = (p: string) => path.resolve(__dirname, path.relative(virtualNodewinDir, p));
5661

5762
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),
63+
readFile: (p: string, encoding: BufferEncoding, cb: (err: any, str: string) => void) => fs.readFile(remapPath(p), encoding, cb),
5964
stat: (p: string, cb: () => void) => fs.stat(remapPath(p), cb),
6065
});
6166

62-
for (const binaryName of fs.readdirSync(distDir))
67+
for (const binaryName of fs.readdirSync(distDir)) {
68+
if (shouldGenerateShim(binaryName) === false)
69+
continue;
70+
6371
await cmdShim(path.join(virtualNodewinDir, `dist/${binaryName}`), path.join(physicalNodewinDir, path.basename(binaryName, `.js`)), {createCmdFile: true, fs: easyStatFs});
72+
}
6473

6574
console.log(`All shims have been generated.`);
6675
}

package.json

Lines changed: 5 additions & 2 deletions
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",
@@ -56,10 +58,11 @@
5658
"which": "^2.0.2"
5759
},
5860
"scripts": {
59-
"build": "rm -rf dist && webpack && ts-node ./mkshims.ts",
61+
"build": "rm -rf dist shims && webpack && ts-node ./mkshims.ts",
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 is 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)