feat: expand oracle and topology evidence gates
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { execFileSync } from 'node:child_process'
|
||||
import { mkdir, stat } from 'node:fs/promises'
|
||||
import { mkdir, rename, stat } from 'node:fs/promises'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
|
||||
@@ -9,24 +9,64 @@ const directoryArgument = process.argv.slice(2).find((argument) => argument.star
|
||||
const target = resolve(root, directoryArgument?.slice('--directory='.length) || toolchain.sourceCheckout.defaultDirectory)
|
||||
const git = (...args) => execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'], timeout: 300000 }).trim()
|
||||
const exists = await stat(target).then(() => true, () => false)
|
||||
const offline = process.env.FREECAD_SOURCE_OFFLINE === '1'
|
||||
|
||||
if (!exists) {
|
||||
if (offline) throw new Error(`FREECAD_SOURCE_OFFLINE=1 requires an existing pinned checkout: ${target}`)
|
||||
await mkdir(dirname(target), { recursive: true })
|
||||
git('clone', '--filter=blob:none', '--no-checkout', toolchain.source.repository, target)
|
||||
} else {
|
||||
const remote = git('-C', target, 'remote', 'get-url', 'origin')
|
||||
if (remote !== toolchain.source.repository) throw new Error(`Existing checkout has unexpected origin: ${remote}`)
|
||||
const dirty = git('-C', target, 'status', '--porcelain')
|
||||
if (dirty) throw new Error(`Existing FreeCAD checkout is dirty: ${target}`)
|
||||
const submodulePaths = git('-C', target, 'config', '--file', '.gitmodules', '--get-regexp', 'path')
|
||||
.split(/\r?\n/)
|
||||
.filter(Boolean)
|
||||
.map((line) => line.slice(line.indexOf(' ') + 1).trim())
|
||||
const parentDirty = git('-C', target, 'status', '--porcelain')
|
||||
const unexpectedDirty = parentDirty.split(/\r?\n/).filter((line) => line && !submodulePaths.some((path) => line.endsWith(` ${path}`) || line.endsWith(`\t${path}`)))
|
||||
if (unexpectedDirty.length > 0) throw new Error(`Existing FreeCAD checkout is dirty outside submodules: ${target}`)
|
||||
|
||||
// A previous interrupted clone can leave a non-empty directory without a
|
||||
// gitlink checkout. Move only those exact submodule targets into an ignored,
|
||||
// recoverable cache before asking Git to initialize them again.
|
||||
if (!offline) {
|
||||
const staleRoot = resolve(root, '.cache/freecad/stale-submodules', String(Date.now()))
|
||||
let moved = 0
|
||||
for (const submodulePath of submodulePaths) {
|
||||
const submodule = resolve(target, submodulePath)
|
||||
const present = await stat(submodule).then(() => true, () => false)
|
||||
if (!present) continue
|
||||
const hasGitMetadata = await stat(resolve(submodule, '.git')).then(() => true, () => false)
|
||||
const childDirty = hasGitMetadata
|
||||
? git('-C', submodule, 'status', '--porcelain').length > 0
|
||||
: true
|
||||
if (!hasGitMetadata || childDirty) {
|
||||
const destination = resolve(staleRoot, submodulePath)
|
||||
await mkdir(dirname(destination), { recursive: true })
|
||||
await rename(submodule, destination)
|
||||
moved += 1
|
||||
console.error(`Moved stale FreeCAD submodule ${submodulePath} to ${destination}`)
|
||||
}
|
||||
}
|
||||
if (moved > 0) await mkdir(staleRoot, { recursive: true })
|
||||
} else {
|
||||
console.error('FREECAD_SOURCE_OFFLINE=1: preserving the pinned source checkout and skipping submodule repair.')
|
||||
}
|
||||
}
|
||||
|
||||
git('-C', target, 'fetch', '--depth=1', 'origin', `refs/tags/${toolchain.source.tag}`)
|
||||
const fetched = git('-C', target, 'rev-parse', 'FETCH_HEAD')
|
||||
if (fetched !== toolchain.source.commit) throw new Error(`Fetched FreeCAD tag resolved to ${fetched}, expected ${toolchain.source.commit}.`)
|
||||
git('-C', target, 'checkout', '--detach', toolchain.source.commit)
|
||||
const currentRevision = git('-C', target, 'rev-parse', 'HEAD')
|
||||
if (offline && currentRevision === toolchain.source.commit) {
|
||||
console.error(`FREECAD_SOURCE_OFFLINE=1: using pinned FreeCAD source ${currentRevision}.`)
|
||||
} else {
|
||||
git('-C', target, 'fetch', '--depth=1', 'origin', `refs/tags/${toolchain.source.tag}`)
|
||||
const fetched = git('-C', target, 'rev-parse', 'FETCH_HEAD')
|
||||
if (fetched !== toolchain.source.commit) throw new Error(`Fetched FreeCAD tag resolved to ${fetched}, expected ${toolchain.source.commit}.`)
|
||||
git('-C', target, 'checkout', '--detach', toolchain.source.commit)
|
||||
}
|
||||
// The locked source graph includes GSL, OndselSolver, AddonManager and the
|
||||
// test support checkout. Initialize every gitlink so a clean oracle build does
|
||||
// not silently fall back to a partial module set.
|
||||
git('-C', target, 'submodule', 'sync', '--recursive')
|
||||
git('-C', target, 'submodule', 'update', '--init', '--recursive')
|
||||
if (offline) console.error('FREECAD_SOURCE_OFFLINE=1: skipping network-dependent submodule update.')
|
||||
else git('-C', target, 'submodule', 'update', '--init', '--recursive')
|
||||
console.log(`FreeCAD source ready: ${target} @ ${toolchain.source.commit}`)
|
||||
|
||||
Reference in New Issue
Block a user