Skip to content

Commit d219293

Browse files
authored
fix(install): reinstall same dependencies (#47)
When installing duplicated dependencies, it triggers concurrency issues in Node.js (see: nodejs/node#53534). This can be avoided by pre-deduplication. Signed-off-by: Kevin Cui <[email protected]>
1 parent 14a0035 commit d219293

File tree

13 files changed

+129
-4
lines changed

13 files changed

+129
-4
lines changed

src/cmd/install.test.ts

+29
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ describe.sequential("install all", () => {
127127
publish(path.join(remoteStorage, "c-0.0.2"), ctx.registry.endpoint, "fake-token"),
128128
publish(path.join(remoteStorage, "d-0.0.1"), ctx.registry.endpoint, "fake-token"),
129129
publish(path.join(remoteStorage, "e-0.0.1"), ctx.registry.endpoint, "fake-token"),
130+
publish(path.join(remoteStorage, "e-0.0.2"), ctx.registry.endpoint, "fake-token"),
131+
publish(path.join(remoteStorage, "f-0.0.1"), ctx.registry.endpoint, "fake-token"),
132+
publish(path.join(remoteStorage, "e-0.0.3"), ctx.registry.endpoint, "fake-token"),
130133
]);
131134
}
132135

@@ -155,6 +158,8 @@ describe.sequential("install all", () => {
155158
"a-0.0.1",
156159
"b-0.0.1",
157160
"c-0.0.1",
161+
"f-0.0.1",
162+
"e-0.0.3",
158163
]));
159164

160165
expect(result.deps).toStrictEqual({
@@ -200,6 +205,27 @@ describe.sequential("install all", () => {
200205
target: expect.any(String),
201206
meta: expect.any(Object),
202207
},
208+
"e-0.0.2": {
209+
name: "e",
210+
version: "0.0.2",
211+
isAlreadyExist: false,
212+
target: expect.any(String),
213+
meta: expect.any(Object),
214+
},
215+
"e-0.0.3": {
216+
name: "e",
217+
version: "0.0.3",
218+
isAlreadyExist: false,
219+
target: expect.any(String),
220+
meta: expect.any(Object),
221+
},
222+
"f-0.0.1": {
223+
name: "f",
224+
version: "0.0.1",
225+
isAlreadyExist: false,
226+
target: expect.any(String),
227+
meta: expect.any(Object),
228+
},
203229
});
204230

205231
const fileList = await globby(`**/${ooPackageName}`, {
@@ -215,6 +241,9 @@ describe.sequential("install all", () => {
215241
"c-0.0.2/package.oo.yaml",
216242
"d-0.0.1/package.oo.yaml",
217243
"e-0.0.1/package.oo.yaml",
244+
"e-0.0.2/package.oo.yaml",
245+
"e-0.0.3/package.oo.yaml",
246+
"f-0.0.1/package.oo.yaml",
218247
]));
219248
});
220249
});

src/utils/fs.test.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { readdir } from "node:fs/promises";
2+
import path from "node:path";
3+
import { globby } from "globby";
4+
import { beforeEach, describe, expect, it } from "vitest";
5+
import { fixture } from "../../tests/helper/fs";
6+
import { copyDir, remove, tempDir } from "./fs";
7+
8+
beforeEach(async (ctx) => {
9+
const temp = await tempDir();
10+
11+
ctx.workdir = temp;
12+
13+
return async () => {
14+
await remove(temp);
15+
};
16+
});
17+
18+
describe.concurrent("copyDir", () => {
19+
it("should copy dir", async (ctx) => {
20+
const p = fixture("fs_copy_dir");
21+
const target = path.join(ctx.workdir, "target");
22+
await copyDir(p, target);
23+
expect(await readdir(target)).toEqual(await readdir(p));
24+
});
25+
26+
it("should copy dir with filter", async (ctx) => {
27+
const p = fixture("fs_copy_dir");
28+
const target = path.join(ctx.workdir, "target");
29+
30+
const files = await globby("**/3.txt", {
31+
cwd: p,
32+
dot: true,
33+
onlyFiles: false,
34+
gitignore: true,
35+
absolute: true,
36+
});
37+
38+
await copyDir(p, target, (source, _) => {
39+
if (source === p) {
40+
return true;
41+
}
42+
43+
return files[0].includes(source);
44+
});
45+
46+
const files2 = await globby("**", {
47+
cwd: target,
48+
dot: true,
49+
onlyFiles: false,
50+
gitignore: true,
51+
absolute: false,
52+
});
53+
54+
expect(files2).toContain(path.join("bar", "baz", "3.txt"));
55+
});
56+
57+
// see: https://github.com/nodejs/node/pull/53534
58+
it.skip("should copy dir with dir already exists", async (ctx) => {
59+
const p = fixture("fs_copy_dir");
60+
const target = path.join(ctx.workdir, "target");
61+
const ps = Array.from({ length: 100 }).fill(0).map(() => copyDir(p, target));
62+
await Promise.all(ps);
63+
});
64+
});

src/utils/npm.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ export async function transformNodeModules(dir: string) {
127127
absolute: true,
128128
});
129129

130+
const map = new Map<string, {
131+
source: string;
132+
name: string;
133+
version: string;
134+
}>();
135+
130136
const ps = result
131137
// Filter out paths that do not conform to this rule: node_modules/PACKAGE_NAME/package/package.oo.yaml
132138
.filter((p) => {
@@ -137,12 +143,15 @@ export async function transformNodeModules(dir: string) {
137143
.map(async (p) => {
138144
const source = path.dirname(p);
139145
const { name, version } = await generatePackageJson(source, false);
140-
return {
146+
147+
map.set(`${name}-${version}`, {
141148
source,
142149
name,
143150
version,
144-
};
151+
});
145152
});
146153

147-
return await Promise.all(ps);
154+
await Promise.all(ps);
155+
156+
return Array.from(map.values());
148157
}

tests/fixtures/fs_copy_dir/1.txt

Whitespace-only changes.

tests/fixtures/fs_copy_dir/bar/2.txt

Whitespace-only changes.

tests/fixtures/fs_copy_dir/bar/baz/3.txt

Whitespace-only changes.

tests/fixtures/install_all/README.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ entry
66
a: 0.0.1
77
c: 0.0.2
88
d: 0.0.1
9+
e: 0.0.2
910
b: 0.0.1
1011
e: 0.0.1
1112
c: 0.0.1
13+
e: 0.0.2
14+
b: 0.0.1
15+
f: 0.0.1
16+
e: 0.0.1
17+
e: 0.0.3
1218
```
1319

1420
#### Local Storage (Already exists locally)
@@ -26,11 +32,14 @@ b: 0.0.1
2632
c: 0.0.2
2733
d: 0.0.1
2834
e: 0.0.1
35+
e: 0.0.2
36+
e: 0.0.3
37+
f: 0.0.1
2938
```
3039

3140
### Installation Logic
3241

33-
1. Only install the `a:0.0.1` `b:0.0.1` `c:0.0.2` `d:0.0.1` `e:0.0.1` dependencies.
42+
1. Only install the `a:0.0.1` `b:0.0.1` `c:0.0.2` `d:0.0.1` `e:0.0.1` `e:0.0.2` `f:0.0.1` `e:0.0.3` dependencies.
3443
2. Do not install the `c:0.0.1` dependency as it is already installed locally.
3544
3. Do install the `e:0.0.1` dependency as it is sub-dependency of `b:0.0.1`.
3645
1. _oopm_ don't know about this sub-dependency as it is not mentioned in the `entry` package.

tests/fixtures/install_all/entry/package.oo.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ dependencies:
44
a: 0.0.1
55
b: 0.0.1
66
c: 0.0.1
7+
f: 0.0.1
8+
e: 0.0.3

tests/fixtures/install_all/remote_storage/a-0.0.1/package.oo.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ version: 0.0.1
33
dependencies:
44
c: 0.0.2
55
d: 0.0.1
6+
e: 0.0.2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
name: c
22
version: 0.0.2
3+
dependencies:
4+
e: 0.0.2
5+
b: 0.0.1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
name: e
2+
version: 0.0.2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
name: e
2+
version: 0.0.3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name: f
2+
version: 0.0.1
3+
dependencies:
4+
e: 0.0.1

0 commit comments

Comments
 (0)