feat: complete WorkBuddy parity and Windows release workflow
This commit is contained in:
1 parent
143516b3a8
commit
d5512df549
434 files changed
+54977
-1854
No files matched your search
@@ -0,0 +1,65 @@
|
||||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import { spawn, execFileSync } from 'node:child_process'
|
||||
import { createHash } from 'node:crypto'
|
||||
import { verifyBundledGit } from './vendor-sandbox-git.mjs'
|
||||
|
||||
export async function buildSandbox({ outputDirectory = path.resolve('resources/sandbox/win32-x64'), probe = false } = {}) {
|
||||
if (process.platform !== 'win32' || process.arch !== 'x64') throw new Error('The sandbox native build currently requires Windows x64')
|
||||
const bundledGit = !probe ? await verifyBundledGit(path.join(outputDirectory, 'git')).catch(error => { throw new Error(`Bundled Git is missing or invalid; run npm run sandbox:vendor-git. ${error.message}`) }) : undefined
|
||||
const programFiles = process.env['ProgramFiles(x86)'] || 'C:\\Program Files (x86)'
|
||||
const vswhere = path.join(programFiles, 'Microsoft Visual Studio/Installer/vswhere.exe')
|
||||
const installation = execFileSync(vswhere, ['-latest', '-products', '*', '-requires', 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64', '-property', 'installationPath'], { encoding: 'utf8', windowsHide: true }).trim()
|
||||
if (!installation) throw new Error('Visual Studio C++ Build Tools are required; see native/sandbox/README.md')
|
||||
const versions = async directory => (await fs.readdir(directory)).filter(name => /^\d+(?:\.\d+)+$/.test(name)).sort((a, b) => b.localeCompare(a, undefined, { numeric: true }))
|
||||
const msvcRoot = path.join(installation, 'VC/Tools/MSVC')
|
||||
const msvc = path.join(msvcRoot, (await versions(msvcRoot))[0])
|
||||
const sdkRoot = path.join(programFiles, 'Windows Kits/10')
|
||||
const sdk = (await versions(path.join(sdkRoot, 'Include')))[0]
|
||||
if (!sdk) throw new Error('Windows 10/11 SDK is required')
|
||||
const compilerDirectory = path.join(msvc, 'bin/Hostx64/x64')
|
||||
const environment = { ...process.env,
|
||||
PATH: `${compilerDirectory};${process.env.PATH || ''}`,
|
||||
INCLUDE: [path.join(msvc, 'include'), ...['ucrt', 'shared', 'um', 'winrt'].map(part => path.join(sdkRoot, 'Include', sdk, part))].join(';'),
|
||||
LIB: [path.join(msvc, 'lib/x64'), ...['ucrt', 'um'].map(part => path.join(sdkRoot, 'Lib', sdk, part, 'x64'))].join(';') }
|
||||
await fs.mkdir(outputDirectory, { recursive: true })
|
||||
const objects = await fs.mkdtemp(path.resolve('.tmp/sandbox-native-build-'))
|
||||
const source = path.resolve(probe ? 'native/sandbox/probe.cpp' : 'native/sandbox/runner.cpp')
|
||||
const binary = path.join(outputDirectory, probe ? 'sandbox-probe.exe' : 'ycode-sandbox.exe')
|
||||
const args = ['/nologo', '/std:c++17', '/EHsc', '/W4', '/WX', '/MT', '/O2', '/Brepro', '/utf-8', '/DUNICODE', '/D_UNICODE', '/D_WIN32_WINNT=0x0A00', `/Fo${objects}${path.sep}`, `/Fe${binary}`, source, '/link', '/INCREMENTAL:NO', 'advapi32.lib', 'userenv.lib', 'ws2_32.lib', 'bcrypt.lib']
|
||||
await new Promise((resolve, reject) => {
|
||||
const child = spawn(path.join(compilerDirectory, 'cl.exe'), args, { env: environment, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] })
|
||||
let log = ''
|
||||
child.stdout.on('data', bytes => { log += bytes })
|
||||
child.stderr.on('data', bytes => { log += bytes })
|
||||
child.once('error', reject)
|
||||
child.once('close', code => code === 0 ? resolve() : reject(new Error(`Sandbox compiler exited ${code}\n${log}`)))
|
||||
})
|
||||
const hash = bytes => createHash('sha256').update(bytes).digest('hex')
|
||||
const manifest = { protocol: 1, backend: 'windows-appcontainer', version: '0.7.0', architecture: 'x64',
|
||||
sourceSha256: hash(await fs.readFile(source)), binarySha256: hash(await fs.readFile(binary)), compiler: path.basename(msvc), sdk }
|
||||
if (!probe) {
|
||||
manifest.workspaceTransactions = 1
|
||||
manifest.workspaceState = 1
|
||||
manifest.gitMetadataTransactions = 1
|
||||
manifest.bundledGit = bundledGit
|
||||
manifest.sources = Object.fromEntries(await Promise.all(['runner.cpp', 'filesystem-read.h', 'filesystem-write.h', 'workspace-state.h', 'git-control.h', 'node-bridge.cjs', 'node-process.cjs', 'python-sitecustomize.py'].map(async name => [name, hash(await fs.readFile(path.resolve('native/sandbox', name)))])))
|
||||
const adapter = await fs.readFile(path.resolve('native/sandbox/node-bridge.cjs'))
|
||||
await fs.writeFile(path.join(outputDirectory, 'node-bridge.cjs'), adapter)
|
||||
manifest.nodeBridgeSha256 = hash(adapter)
|
||||
const processes = await fs.readFile(path.resolve('native/sandbox/node-process.cjs'))
|
||||
await fs.writeFile(path.join(outputDirectory, 'node-process.cjs'), processes)
|
||||
manifest.nodeProcessSha256 = hash(processes)
|
||||
const pythonAdapter = await fs.readFile(path.resolve('native/sandbox/python-sitecustomize.py'))
|
||||
await fs.writeFile(path.join(outputDirectory, 'python-sitecustomize.py'), pythonAdapter)
|
||||
manifest.pythonAdapterSha256 = hash(pythonAdapter)
|
||||
}
|
||||
if (!probe) await fs.writeFile(path.join(outputDirectory, 'manifest.json'), JSON.stringify(manifest, null, 2) + '\n')
|
||||
console.log(`SANDBOX_BUILD_PASS ${path.relative(process.cwd(), binary)}`)
|
||||
return binary
|
||||
}
|
||||
|
||||
if (process.argv[1] && path.resolve(process.argv[1]) === import.meta.filename) {
|
||||
await fs.mkdir(path.resolve('.tmp'), { recursive: true })
|
||||
await buildSandbox({ probe: process.argv.includes('--probe') })
|
||||
}
|
||||
Reference in new issue
Block a user