Skip to content

Commit 5495971

Browse files
committed
switch from fs-ext to an ffi implementation
fs-ext is problematic since it requires native .node files but doesn’t provide prebuilds, which makes it hard to use it with a github action and with our Electron app.
1 parent 47b27ad commit 5495971

4 files changed

Lines changed: 37 additions & 25 deletions

File tree

.github/deno-to-node.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ dependencies:
1313
npmjs.com: '*'
1414
---*/
1515

16-
import { build, emptyDir } from "https://deno.land/x/dnt@0.35.0/mod.ts";
16+
import { build, emptyDir } from "https://deno.land/x/dnt@0.36.0/mod.ts";
1717
import SemVer from "../src/utils/semver.ts";
1818

1919
await emptyDir("./dist");
@@ -61,9 +61,6 @@ await build({
6161
"is-what": "^4",
6262
"outdent": "^0.8",
6363
},
64-
devDependencies: {
65-
"@types/fs-ext": "^2"
66-
},
6764
},
6865
postBuild() {
6966
Deno.copyFileSync("LICENSE.txt", "dist/LICENSE.txt");

src/prefab/install.test.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useTestConfig as useTestConfigBase } from "../hooks/useConfig.test.ts"
2-
import { assert, assertEquals } from "deno/testing/asserts.ts"
3-
import install, { ConsoleLogger } from "./install.ts"
2+
import { assert, assertEquals, assertFalse } from "deno/testing/asserts.ts"
3+
import install, { ConsoleLogger, Logger } from "./install.ts"
44
import { stub } from "deno/testing/mock.ts"
55
import SemVer from "../utils/semver.ts"
66
import { Package } from "../types.ts"
@@ -41,16 +41,25 @@ Deno.test("install()", async runner => {
4141
})
4242
})
4343

44-
Deno.test("install lock tests", async () => {
44+
Deno.test("install locks", async () => {
4545
const pkg: Package = {
4646
project: "tea.xyz/brewkit",
4747
version: new SemVer("0.30.0")
4848
}
4949

5050
const conf = useTestConfig()
5151

52-
const installer1 = install(pkg)
53-
const installer2 = install(pkg)
52+
let unlocked_once = false
53+
const logger: Logger = {
54+
downloading: () => assertFalse(unlocked_once),
55+
locking: () => {},
56+
installed: () => {},
57+
installing: () => assertFalse(unlocked_once),
58+
unlocking: () => unlocked_once = true
59+
}
60+
61+
const installer1 = install(pkg, logger)
62+
const installer2 = install(pkg, logger)
5463

5564
const [install1, install2] = await Promise.all([installer1, installer2])
5665

src/prefab/install.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ export default async function install(pkg: Package, logger?: Logger): Promise<In
5252
const shelf = tea_prefix.join(pkg.project)
5353

5454
logger?.locking(pkg)
55-
const { rid } = await Deno.open(shelf.mkdir('p').string)
56-
await flock(rid, 'ex')
55+
const { rid: fd } = await Deno.open(shelf.mkdir('p').string)
56+
await flock(fd, 'ex')
5757

5858
try {
5959
const already_installed = await cellar.has(pkg)
@@ -125,8 +125,8 @@ export default async function install(pkg: Package, logger?: Logger): Promise<In
125125
throw err
126126
} finally {
127127
logger?.unlocking(pkg)
128-
await flock(rid, 'un')
129-
Deno.close(rid) // docs aren't clear if we need to do this or not
128+
await flock(fd, 'un')
129+
Deno.close(fd) // docs aren't clear if we need to do this or not
130130
}
131131
}
132132

src/utils/flock.node.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
1-
import { flock as flock_base } from "npm:fs-ext@2.0.0"
2-
3-
function flock(fd: number, op: 'ex' | 'un') {
4-
return new Promise<void>((resolve, reject) => {
5-
flock_base(fd, op, (err: Error | null) => {
6-
if (err) {
7-
reject(err)
8-
} else {
9-
resolve()
10-
}
11-
})
12-
})
1+
import koffi from 'npm:koffi@2'
2+
import * as util from "node:util"
3+
import host from "./host.ts"
4+
5+
const filename = host().platform == 'darwin' ? 'libSystem.dylib' : 'libc.so.6'
6+
const libc = koffi.load(filename)
7+
8+
const LOCK_EX = 2;
9+
const LOCK_UN = 8;
10+
11+
const cflock = libc.func('int flock(int, int)');
12+
const flockAsync = util.promisify(cflock.async);
13+
14+
async function flock(fd: number, op: 'un' | 'ex') {
15+
const rv = await flockAsync(fd, op == 'ex' ? LOCK_EX : LOCK_UN);
16+
if (rv === -1) {
17+
throw new Error("flock failed") // TODO read errno
18+
}
1319
}
1420

1521
export { flock }

0 commit comments

Comments
 (0)