diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7fa420..bc36a97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,11 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + # Node 18 and 20 bundle node-gyp versions that do not yet recognize + # the Visual Studio 2026 installation on windows-latest. Keep the + # compatibility matrix on VS 2022; release-windows below exercises + # the current publishing image with the current node-gyp. + os: [ubuntu-latest, macos-latest, windows-2022] node: ["18", "20", "22"] steps: @@ -31,3 +35,30 @@ jobs: - name: Run tests run: bun test test/ + + release-windows: + name: Windows release toolchain + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + + - name: Install dependencies without building + run: npm install --ignore-scripts + + - name: Download amalgamation + run: node scripts/download.js + + - name: Build with the publishing toolchain + run: npx node-gyp rebuild + + - name: Run tests + run: bun test test/ diff --git a/binding.gyp b/binding.gyp index 5a16d14..305b0bf 100644 --- a/binding.gyp +++ b/binding.gyp @@ -49,7 +49,8 @@ "libraries": ["-lpthread"] }], ["OS=='win'", { - "defines": ["strncasecmp=_strnicmp"] + "defines": ["strncasecmp=_strnicmp"], + "libraries": ["Ws2_32.lib"] }] ] } diff --git a/scripts/build-amalgamation.js b/scripts/build-amalgamation.js index b9ef6d2..9cca418 100644 --- a/scripts/build-amalgamation.js +++ b/scripts/build-amalgamation.js @@ -31,15 +31,19 @@ if (!fs.existsSync(inH)) { console.log("Preparing released doltlite amalgamation...") fs.mkdirSync(outDir, { recursive: true }) let amalgamation = fs.readFileSync(inC, "utf8") -amalgamation += ` -#if defined(DOLTLITE_PROLLY) && defined(SQLITE_USE_SEH) && !defined(SQLITE_OMIT_WAL) -SQLITE_PRIVATE int sqlite3PagerWalSystemErrno(Pager *pPager){ - (void)pPager; - return 0; -} +// DoltLite releases before v0.11.37 emitted the Winsock 2 headers after +// SQLite's Windows VFS had already included windows.h. Keep those releases +// buildable while newer release amalgamations carry the ordering fix directly. +if (!amalgamation.includes("DOLTLITE_AMALGAMATION_WINSOCK2_EARLY")) { + amalgamation = `/* DOLTLITE_NODE_WINSOCK2_EARLY_FALLBACK */ +#ifdef _WIN32 +# include +# include #endif -` + +${amalgamation}` +} fs.writeFileSync(outC, amalgamation) fs.copyFileSync(inH, outH) fs.writeFileSync(versionMarker, `${pkg.version}\n`) diff --git a/test/amalgamation.test.ts b/test/amalgamation.test.ts new file mode 100644 index 0000000..79b2caa --- /dev/null +++ b/test/amalgamation.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, test } from "bun:test" +import { existsSync, readFileSync } from "fs" +import { join } from "path" + +const sourcePath = join(import.meta.dir, "..", "amalgamation", ".source", "sqlite3.c") +const outputPath = join(import.meta.dir, "..", "amalgamation", "doltlite.c") + +describe("released amalgamation preparation", () => { + test("preserves the core SEH pager shim without appending a duplicate", () => { + expect(existsSync(sourcePath)).toBe(true) + expect(existsSync(outputPath)).toBe(true) + + const source = readFileSync(sourcePath, "utf8") + const output = readFileSync(outputPath, "utf8") + const definition = /^(?:SQLITE_PRIVATE )?int sqlite3PagerWalSystemErrno\(Pager \*pPager\)\{/gm + + expect(output.match(definition)?.length ?? 0).toBe(source.match(definition)?.length ?? 0) + }) + + test("selects Winsock 2 before the first windows.h include", () => { + const output = readFileSync(outputPath, "utf8") + const winsock = output.search(/^# *include /m) + const windows = output.search(/^# *include [<"]windows\.h[>"]/m) + + expect(winsock).toBeGreaterThanOrEqual(0) + expect(windows).toBeGreaterThanOrEqual(0) + expect(winsock).toBeLessThan(windows) + }) + + test("uses an unmodified fixed release amalgamation", () => { + const source = readFileSync(sourcePath, "utf8") + const output = readFileSync(outputPath, "utf8") + + if (source.includes("DOLTLITE_AMALGAMATION_WINSOCK2_EARLY")) { + expect(output).toBe(source) + } else { + expect(output).toContain("DOLTLITE_NODE_WINSOCK2_EARLY_FALLBACK") + } + }) +})