mirror of
https://github.com/stablyai/orca.git
synced 2026-09-21 16:02:20 +00:00
* perf(dev): clone one Electron dist per repo instead of per worktree Every worktree extracted its own ~295MB node_modules/electron/dist, measured at 69GB across 241 worktrees on one machine. Extract once per repository into <git-common-dir>/orca-cache/electron, then APFS-clone it into each worktree: copy-on-write, so the second worktree allocates ~0 bytes and still gets a real, private, writable directory. Hangs off install-electron-package-binary.mjs, inside the transaction it already uses to swap dist. Every cache path returns a boolean and false means "install normally", so non-APFS, cross-volume, corrupt entry, no Git, folder workspace and CI all keep today's behavior. No symlinks, no lifecycle changes. out/electron-dev's per-branch Electron.app copy clones too, via the same helper. Refs #13709 * perf(dev): share the Electron dist on Linux and Windows too Extends the shared dist cache beyond macOS APFS. Three mechanisms, strongest isolation first: macOS APFS cp -c private copy-on-write Linux btrfs cp --reflink private copy-on-write ext4 / NTFS hardlink + 0555 shared inodes, forced read-only Reflinks cover btrfs/XFS/bcachefs/ZFS but not ext4, and Windows block cloning is ReFS-only, so most Linux and effectively all Windows developers need hardlinks to get any saving at all. Extracted dist is 327MB on linux-x64 and 374MB on win32-x64, both larger than macOS. Hardlinks share inodes, so a write through one worktree would rewrite every sibling and the cache. Nothing in this repo writes inside dist -- every mutation replaces the directory via rename -- but Electron's own install.js extracts over an existing dist with O_TRUNC, and is reachable through `pnpm rebuild electron`. Publishing the entry read-only turns that from silent cross-worktree corruption into EPERM. Directories stay writable so the install transaction's renames and unlinks still work. out/electron-dev's per-branch Electron.app is patched and codesigned after it is copied, so it uses copyPrivateTree, which never hardlinks. Refs #13709 * test(dev): keep shared-dist tests honest across ext4 and NTFS Verified on real hardware: Ubuntu 24.04/ext4 (no reflink support, so the hardlink tier is the only thing that helps there) and Windows/NTFS. Three tests faked platform: 'darwin' while invoking the real mechanism, so they failed on Linux where /bin/cp -c does not exist. Mechanism selection is now asserted with injected stubs; real filesystem behavior is asserted against whatever the host actually supports. Windows maps chmod onto the read-only attribute alone, so a directory never reports 0o755 and a read-only file reports 0o444. Mode-bit assertions that encoded POSIX semantics are now behavioral (the tree stays removable), and the executable-bit assertion is POSIX-only -- confirmed on NTFS that a read-only hardlinked .exe still runs. * fix(dev): stop a losing publisher from discarding a good cache entry Greptile caught a TOCTOU in the shared Electron dist cache. Quarantining an invalid entry happened before sharing the replacement tree, which takes seconds -- long enough for a sibling worktree to publish a good entry that this one would then rename away. If the follow-up publish also failed, the cache was left empty and every worktree re-downloaded. Stage first, then re-validate immediately before the destructive rename, so an entry that became good during the share is kept. On a failed swap, restore the quarantined entry instead of leaving no entry at all: a stale entry still beats an empty cache, because the next publisher re-validates and replaces it. An entry that cannot be validated is never displaced, matching the pre-staging rule. Also covers the Electron upgrade path end to end: a version bump gets its own cache entry and leaves the previous one for worktrees still on the old branch. * feat(dev): add a script to share existing worktrees' Electron dists An install only shares when Electron is (re)installed, and rebuild-native-deps returns early when the package is already usable -- so a worktree that already has a working dist never reaches the sharing path and keeps its own copy until the next Electron upgrade. pnpm reclaim:electron-dists reports what it would share; --apply does it. Each worktree is converted behind a rename, so an interrupted run leaves a working dist either way, and any worktree that fails is left untouched. Measured on one machine: 677 worktrees, ~195 GiB reclaimable. * fix(dev): keep the reclaim script's error formatting type-safe
627 lines
23 KiB
JavaScript
627 lines
23 KiB
JavaScript
import {
|
|
existsSync,
|
|
lstatSync,
|
|
mkdirSync,
|
|
readdirSync,
|
|
readFileSync,
|
|
rmSync,
|
|
statSync,
|
|
writeFileSync
|
|
} from 'node:fs'
|
|
import { join } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
addSiblingWorktree,
|
|
initGitRepo,
|
|
mkTempProject,
|
|
readExtractorCallCount,
|
|
readSharedDistMarker,
|
|
runInstallScript,
|
|
sharedCacheRoot,
|
|
sharedEntryName,
|
|
sharedEntryNameFor,
|
|
writeFakeElectronDist,
|
|
writeFakeElectronGet,
|
|
writeFakeElectronPackage,
|
|
writeFakeExtractor,
|
|
writeNonDarwinPlatformPreload,
|
|
writeTypeDefPublishFailurePreload
|
|
} from './install-electron-package-binary-test-fixtures.mjs'
|
|
|
|
describe('install-electron-package-binary', () => {
|
|
it('installs Electron from an isolated cache and repairs path.txt', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
writeFakeElectronDist(projectDir, {
|
|
version: 'v40.0.0',
|
|
executableContents: 'old executable',
|
|
pathContents: 'stale-path'
|
|
})
|
|
|
|
const result = runInstallScript(projectDir)
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(readFileSync(join(projectDir, 'electron-get.log'), 'utf8')).toMatch(
|
|
/cacheRoot=.*orca-electron-.*cache/
|
|
)
|
|
expect(readFileSync(join(projectDir, 'electron-get.log'), 'utf8')).toContain('force=true')
|
|
expect(readFileSync(join(projectDir, 'node_modules', 'electron', 'path.txt'), 'utf8')).toBe(
|
|
'electron'
|
|
)
|
|
expect(readFileSync(join(projectDir, 'node_modules/electron/electron.d.ts'), 'utf8')).toBe(
|
|
'replacement types'
|
|
)
|
|
expect(existsSync(join(projectDir, 'node_modules/electron/dist/electron.d.ts'))).toBe(false)
|
|
if (process.platform !== 'win32') {
|
|
expect(
|
|
lstatSync(
|
|
join(projectDir, 'node_modules', 'electron', 'dist', 'version-link')
|
|
).isSymbolicLink()
|
|
).toBe(true)
|
|
}
|
|
expect(result.stdout).toContain('Repaired Electron path.txt -> electron')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('repairs existing Electron path metadata without downloading', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeElectronDist(projectDir)
|
|
|
|
const result = runInstallScript(projectDir)
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(readFileSync(join(projectDir, 'node_modules/electron/path.txt'), 'utf8')).toBe(
|
|
'electron'
|
|
)
|
|
expect(result.stdout).toContain('Repaired Electron path.txt -> electron')
|
|
expect(existsSync(join(projectDir, 'electron-get.log'))).toBe(false)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('reuses a configured persistent cache without forcing a fresh download', () => {
|
|
const projectDir = mkTempProject()
|
|
const cacheRoot = join(projectDir, 'electron-cache')
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_CACHE_ROOT: cacheRoot
|
|
})
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(readFileSync(join(projectDir, 'electron-get.log'), 'utf8')).toContain(
|
|
`cacheRoot=${cacheRoot} platform=linux arch=x64 force=false`
|
|
)
|
|
expect(existsSync(cacheRoot)).toBe(true)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('preserves an existing Electron distribution when replacement download fails', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, { downloadFailures: 1, downloadErrorCode: 'EACCES' })
|
|
writeFakeElectronDist(projectDir, {
|
|
version: 'v40.0.0',
|
|
executableContents: 'existing executable',
|
|
pathContents: 'electron'
|
|
})
|
|
|
|
const result = runInstallScript(projectDir)
|
|
const electronDir = join(projectDir, 'node_modules/electron')
|
|
|
|
expect(result.status).toBe(1)
|
|
expect(readFileSync(join(electronDir, 'dist/version'), 'utf8')).toBe('v40.0.0')
|
|
expect(readFileSync(join(electronDir, 'dist/electron'), 'utf8')).toBe('existing executable')
|
|
expect(readFileSync(join(electronDir, 'path.txt'), 'utf8')).toBe('electron')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('restores an existing Electron distribution when publishing its type definitions fails', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
writeFakeElectronDist(projectDir, {
|
|
version: 'v40.0.0',
|
|
executableContents: 'existing executable',
|
|
pathContents: 'electron'
|
|
})
|
|
writeFileSync(join(projectDir, 'node_modules/electron/electron.d.ts'), 'existing types')
|
|
const preloadPath = writeTypeDefPublishFailurePreload(projectDir)
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
NODE_OPTIONS: [process.env.NODE_OPTIONS, `--require=${preloadPath}`]
|
|
.filter(Boolean)
|
|
.join(' ')
|
|
})
|
|
const electronDir = join(projectDir, 'node_modules/electron')
|
|
|
|
expect(result.status).toBe(1)
|
|
expect(result.stderr).toContain('injected Electron type definition publish failure')
|
|
expect(readFileSync(join(electronDir, 'dist/version'), 'utf8')).toBe('v40.0.0')
|
|
expect(readFileSync(join(electronDir, 'dist/electron'), 'utf8')).toBe('existing executable')
|
|
expect(readFileSync(join(electronDir, 'path.txt'), 'utf8')).toBe('electron')
|
|
expect(readFileSync(join(electronDir, 'electron.d.ts'), 'utf8')).toBe('existing types')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('uses Electron 42 install env vars before npm config platform flags', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ELECTRON_INSTALL_PLATFORM: 'win32',
|
|
ELECTRON_INSTALL_ARCH: 'arm64',
|
|
npm_config_platform: 'linux',
|
|
npm_config_arch: 'x64'
|
|
})
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(readFileSync(join(projectDir, 'electron-get.log'), 'utf8')).toContain(
|
|
'platform=win32 arch=arm64'
|
|
)
|
|
expect(readFileSync(join(projectDir, 'node_modules', 'electron', 'path.txt'), 'utf8')).toBe(
|
|
'electron.exe'
|
|
)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('does not trigger Electron 42 lazy require downloads while checking install state', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir, { lazyRequireMarker: 'lazy-require.marker' })
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir)
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(existsSync(join(projectDir, 'lazy-require.marker'))).toBe(false)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('retries transient Electron download failures', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, {
|
|
downloadFailures: 1,
|
|
downloadErrorCode: 'ECONNRESET'
|
|
})
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,0'
|
|
})
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(
|
|
readFileSync(join(projectDir, 'electron-get.log'), 'utf8').trim().split('\n')
|
|
).toHaveLength(2)
|
|
expect(result.stderr).toContain('Transient Electron download failure (ECONNRESET)')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('keeps a persistent cache root while retrying transient failures', () => {
|
|
const projectDir = mkTempProject()
|
|
const cacheRoot = join(projectDir, 'electron-cache')
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, {
|
|
downloadFailures: 1,
|
|
downloadErrorCode: 'ECONNRESET'
|
|
})
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
mkdirSync(cacheRoot, { recursive: true })
|
|
writeFileSync(join(cacheRoot, 'preserved.marker'), 'keep me')
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_CACHE_ROOT: cacheRoot,
|
|
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,0'
|
|
})
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(existsSync(join(cacheRoot, 'preserved.marker'))).toBe(true)
|
|
expect(
|
|
readFileSync(join(projectDir, 'electron-get.log'), 'utf8').trim().split('\n')
|
|
).toHaveLength(2)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('retries HTTP/2 stream refusal Electron download failures', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, {
|
|
downloadFailures: 1,
|
|
downloadErrorCode: 'ERR_HTTP2_STREAM_ERROR'
|
|
})
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,0'
|
|
})
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(
|
|
readFileSync(join(projectDir, 'electron-get.log'), 'utf8').trim().split('\n')
|
|
).toHaveLength(2)
|
|
expect(result.stderr).toContain(
|
|
'Transient Electron download failure (ERR_HTTP2_STREAM_ERROR)'
|
|
)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('retries Electron download HTTP 503 failures from Fetch Response.status', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, {
|
|
downloadFailures: 1,
|
|
downloadHttpStatus: 503
|
|
})
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,0'
|
|
})
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(
|
|
readFileSync(join(projectDir, 'electron-get.log'), 'utf8').trim().split('\n')
|
|
).toHaveLength(2)
|
|
expect(result.stderr).toContain('Transient Electron download failure (HTTP 503)')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('fails after exhausting transient Electron download retries', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, {
|
|
downloadFailures: 5,
|
|
downloadErrorCode: 'ECONNRESET'
|
|
})
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,0'
|
|
})
|
|
|
|
expect(result.status).toBe(1)
|
|
expect(
|
|
readFileSync(join(projectDir, 'electron-get.log'), 'utf8').trim().split('\n')
|
|
).toHaveLength(3)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('rejects invalid Electron download retry delays before downloading', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,nope'
|
|
})
|
|
|
|
expect(result.status).toBe(1)
|
|
expect(result.stderr).toContain(
|
|
'ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS must contain non-negative integers'
|
|
)
|
|
expect(existsSync(join(projectDir, 'electron-get.log'))).toBe(false)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('does not retry permanent Electron download failures', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, {
|
|
downloadFailures: 3,
|
|
downloadErrorCode: 'EACCES'
|
|
})
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, {
|
|
ORCA_ELECTRON_PACKAGE_RETRY_DELAYS_MS: '0,0'
|
|
})
|
|
|
|
expect(result.status).toBe(1)
|
|
expect(
|
|
readFileSync(join(projectDir, 'electron-get.log'), 'utf8').trim().split('\n')
|
|
).toHaveLength(1)
|
|
expect(result.stderr).not.toContain('Transient Electron download failure')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('fails instead of silently accepting a partial Electron extract', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: false })
|
|
mkdirSync(join(projectDir, 'node_modules', 'electron', 'dist', 'locales'), {
|
|
recursive: true
|
|
})
|
|
writeFileSync(join(projectDir, 'node_modules', 'electron', 'path.txt'), 'stale-path')
|
|
|
|
const result = runInstallScript(projectDir)
|
|
|
|
expect(result.status).toBe(1)
|
|
expect(result.stderr).toContain('Electron archive extract did not contain executable')
|
|
expect(result.stderr).toContain('extractEntries=locales')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
// The shared cache is macOS-only: it exists to avoid a second copy via APFS clonefile.
|
|
it('publishes a shared Electron dist entry after a fresh download', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
initGitRepo(projectDir)
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(projectDir, { CI: '' })
|
|
const entryPath = join(sharedCacheRoot(projectDir), sharedEntryName)
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(lstatSync(entryPath).isDirectory()).toBe(true)
|
|
expect(lstatSync(entryPath).isSymbolicLink()).toBe(false)
|
|
expect(readFileSync(join(entryPath, 'version'), 'utf8')).toBe('v41.5.0')
|
|
expect(existsSync(join(entryPath, 'electron'))).toBe(true)
|
|
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryName)
|
|
expect(result.stdout).toMatch(/Published Electron 41\.5\.0 to .*41\.5\.0-linux-x64$/m)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('shares the Electron dist into a sibling worktree without downloading', () => {
|
|
const projectDir = mkTempProject()
|
|
const siblingDir = `${projectDir}-sibling`
|
|
|
|
try {
|
|
initGitRepo(projectDir)
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
expect(runInstallScript(projectDir, { CI: '' }).status).toBe(0)
|
|
|
|
addSiblingWorktree(projectDir, siblingDir)
|
|
writeFakeElectronPackage(siblingDir)
|
|
writeFakeElectronGet(siblingDir)
|
|
writeFakeExtractor(siblingDir, { createExecutable: true })
|
|
|
|
const result = runInstallScript(siblingDir, { CI: '' })
|
|
const siblingDistDir = join(siblingDir, 'node_modules/electron/dist')
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(readExtractorCallCount(siblingDir)).toBe(0)
|
|
expect(existsSync(join(siblingDir, 'electron-get.log'))).toBe(false)
|
|
expect(lstatSync(siblingDistDir).isDirectory()).toBe(true)
|
|
expect(lstatSync(siblingDistDir).isSymbolicLink()).toBe(false)
|
|
expect(readFileSync(join(siblingDistDir, 'version'), 'utf8')).toBe('v41.5.0')
|
|
expect(existsSync(join(siblingDistDir, 'electron'))).toBe(true)
|
|
expect(readFileSync(join(siblingDir, 'node_modules/electron/path.txt'), 'utf8')).toBe(
|
|
'electron'
|
|
)
|
|
expect(readSharedDistMarker(siblingDir)).toBe(sharedEntryName)
|
|
expect(result.stdout).toContain('Shared Electron 41.5.0 from')
|
|
} finally {
|
|
rmSync(siblingDir, { recursive: true, force: true })
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('publishes an already installed Electron dist that predates the shared cache', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
initGitRepo(projectDir)
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
writeFakeElectronDist(projectDir, {
|
|
executableContents: 'existing executable',
|
|
pathContents: 'electron'
|
|
})
|
|
|
|
const result = runInstallScript(projectDir, { CI: '' })
|
|
const entryPath = join(sharedCacheRoot(projectDir), sharedEntryName)
|
|
const distDir = join(projectDir, 'node_modules/electron/dist')
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(readExtractorCallCount(projectDir)).toBe(0)
|
|
expect(existsSync(join(projectDir, 'electron-get.log'))).toBe(false)
|
|
expect(readFileSync(join(entryPath, 'version'), 'utf8')).toBe('v41.5.0')
|
|
expect(readFileSync(join(entryPath, 'electron'), 'utf8')).toBe('existing executable')
|
|
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryName)
|
|
expect(readFileSync(join(distDir, 'electron'), 'utf8')).toBe('existing executable')
|
|
expect(readFileSync(join(distDir, 'version'), 'utf8')).toBe('v41.5.0')
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('replaces a corrupt shared Electron dist entry instead of re-downloading forever', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
initGitRepo(projectDir)
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
const entryPath = join(sharedCacheRoot(projectDir), sharedEntryName)
|
|
mkdirSync(entryPath, { recursive: true })
|
|
writeFileSync(join(entryPath, 'version'), 'v40.0.0')
|
|
writeFileSync(join(entryPath, 'electron'), 'stale executable')
|
|
|
|
const result = runInstallScript(projectDir, { CI: '' })
|
|
const distDir = join(projectDir, 'node_modules/electron/dist')
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(result.stderr).not.toContain('Failed to install Electron package binary')
|
|
expect(readExtractorCallCount(projectDir)).toBe(1)
|
|
expect(readFileSync(join(distDir, 'version'), 'utf8')).toBe('v41.5.0')
|
|
expect(readFileSync(join(projectDir, 'node_modules/electron/path.txt'), 'utf8')).toBe(
|
|
'electron'
|
|
)
|
|
// Why not just fall back: an entry left corrupt makes every sibling worktree download again.
|
|
expect(readFileSync(join(entryPath, 'version'), 'utf8')).toBe('v41.5.0')
|
|
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryName)
|
|
expect(readdirSync(sharedCacheRoot(projectDir))).toEqual([sharedEntryName])
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('hardlinks the shared Electron dist on a host without copy-on-write', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
initGitRepo(projectDir)
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
const preloadPath = writeNonDarwinPlatformPreload(projectDir)
|
|
const nonDarwinEnv = {
|
|
CI: '',
|
|
NODE_OPTIONS: [process.env.NODE_OPTIONS, `--require=${preloadPath}`]
|
|
.filter(Boolean)
|
|
.join(' ')
|
|
}
|
|
|
|
const result = runInstallScript(projectDir, nonDarwinEnv)
|
|
const entryPath = join(sharedCacheRoot(projectDir), sharedEntryName)
|
|
const distDir = join(projectDir, 'node_modules/electron/dist')
|
|
|
|
expect(result.status, result.stderr).toBe(0)
|
|
expect(readFileSync(join(distDir, 'version'), 'utf8')).toBe('v41.5.0')
|
|
expect(readFileSync(join(entryPath, 'version'), 'utf8')).toBe('v41.5.0')
|
|
// Why read-only: these are the same inodes, so an extract over dist would otherwise rewrite
|
|
// the cache and every sibling worktree at once.
|
|
expect(statSync(join(entryPath, 'electron')).mode & 0o222).toBe(0)
|
|
expect(statSync(join(entryPath, 'electron')).ino).toBe(
|
|
statSync(join(distDir, 'electron')).ino
|
|
)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('gives an Electron upgrade its own cache entry and leaves the old one for other branches', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
initGitRepo(projectDir)
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir)
|
|
writeFakeExtractor(projectDir, { createExecutable: true })
|
|
expect(runInstallScript(projectDir, { CI: '' }).status).toBe(0)
|
|
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryNameFor('41.5.0'))
|
|
|
|
// Upgrade the pinned Electron, exactly as a branch bumping the dependency would.
|
|
writeFakeElectronPackage(projectDir, { version: '42.0.0' })
|
|
writeFakeExtractor(projectDir, { createExecutable: true, version: '42.0.0' })
|
|
const upgraded = runInstallScript(projectDir, { CI: '' })
|
|
const cacheRoot = sharedCacheRoot(projectDir)
|
|
|
|
expect(upgraded.status, upgraded.stderr).toBe(0)
|
|
expect(readFileSync(join(projectDir, 'node_modules/electron/dist/version'), 'utf8')).toBe(
|
|
'v42.0.0'
|
|
)
|
|
expect(readSharedDistMarker(projectDir)).toBe(sharedEntryNameFor('42.0.0'))
|
|
// Why the old entry stays: sibling worktrees on the previous branch still share it.
|
|
expect(readdirSync(cacheRoot).sort()).toEqual([
|
|
sharedEntryNameFor('41.5.0'),
|
|
sharedEntryNameFor('42.0.0')
|
|
])
|
|
expect(readFileSync(join(cacheRoot, sharedEntryNameFor('41.5.0'), 'version'), 'utf8')).toBe(
|
|
'v41.5.0'
|
|
)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
|
|
it('does not exit successfully when Electron download never settles', () => {
|
|
const projectDir = mkTempProject()
|
|
|
|
try {
|
|
writeFakeElectronPackage(projectDir)
|
|
writeFakeElectronGet(projectDir, { downloadNeverSettles: true })
|
|
writeFakeExtractor(projectDir, { createExecutable: false })
|
|
|
|
const result = runInstallScript(projectDir)
|
|
|
|
expect(result.status).not.toBe(0)
|
|
expect(result.stderr).toContain('Detected unsettled top-level await')
|
|
expect(existsSync(join(projectDir, 'node_modules', 'electron', 'path.txt'))).toBe(false)
|
|
} finally {
|
|
rmSync(projectDir, { recursive: true, force: true })
|
|
}
|
|
})
|
|
})
|