Skip to content

Commit f6d902a

Browse files
committed
workaround link(pkg) twice at once
1 parent ecb3b09 commit f6d902a

4 files changed

Lines changed: 57 additions & 7 deletions

File tree

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ const { pkgs: tree } = await hydrate(pkg)
5757
const { installed, pending } = await resolve(tree)
5858

5959
for (const pkg of pending) {
60-
const install = await install(pkg)
60+
const installation = await install(pkg)
6161
// ^^ install packages that aren’t yet installed
6262
// ^^ takes a logger parameter so you can show progress to the user
6363
// ^^ you could do these in parallel to speed things up
6464
// ^^ by default, versioned installs go to ~/.tea, separated from the user’s system. The install location can be customized, see next section.
65-
installed.push(install)
65+
await link(installation)
66+
// ^^ creates v*, vx, vx.y symlinks ∵ some packages depend on this
67+
installed.push(installation)
6668
}
6769

6870
const { map, flatten } = useShellEnv()

src/prefab/install.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ Deno.test("install()", async runner => {
2424
assertEquals(installation.pkg.version, pkg.version)
2525
assertEquals(installation.path, conf.prefix.join(pkg.project, `v${pkg.version}`))
2626

27-
installation.path.rm({ recursive: true })
27+
/// so next test works
28+
installation.path.rm({ recursive: true })
2829

2930
stubber.restore()
3031
})

src/prefab/link.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { useTestConfig } from "../hooks/useConfig.test.ts"
2+
import { assert } from "deno/testing/asserts.ts"
3+
import SemVer from "../utils/semver.ts"
4+
import { Package } from "../types.ts"
5+
import install from "./install.ts"
6+
import link from "./link.ts";
7+
8+
Deno.test("link()", async runner => {
9+
const pkg: Package = {
10+
project: "tea.xyz/brewkit",
11+
version: new SemVer("0.30.0")
12+
}
13+
14+
await runner.step("link()", async () => {
15+
useTestConfig()
16+
17+
const installation = await install(pkg)
18+
await link(installation)
19+
await link(installation) // calling twice works
20+
21+
/// test symlinks work
22+
assert(installation.path.parent().join("v*").isDirectory())
23+
assert(installation.path.parent().join(`v${pkg.version.major}`).isDirectory())
24+
})
25+
26+
await runner.step("link() ×2 at once", async () => {
27+
const installation = await install(pkg)
28+
const p1 = link(installation)
29+
const p2 = link(installation)
30+
31+
await Promise.all([p1, p2])
32+
33+
/// test symlinks work
34+
assert(installation.path.parent().join("v*").isDirectory())
35+
assert(installation.path.parent().join(`v${pkg.version.major}`).isDirectory())
36+
})
37+
})

src/prefab/link.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,19 @@ export default async function link(pkg: Package | Installation) {
4343
}
4444

4545
async function makeSymlink(symname: string) {
46-
await Deno.symlink(
47-
installation.path.basename(),
48-
shelf.join(symname).rm().string,
49-
{type: 'dir'})
46+
try {
47+
await Deno.symlink(
48+
installation.path.basename(), // makes it relative
49+
shelf.join(symname).rm().string,
50+
{type: 'dir'})
51+
} catch (err) {
52+
if (err instanceof Deno.errors.AlreadyExists) {
53+
//FIXME race condition for installing the same pkg simultaneously
54+
// real fix is to lock around the entire download/untar/link process
55+
return
56+
} else {
57+
throw err
58+
}
59+
}
5060
}
5161
}

0 commit comments

Comments
 (0)