diff --git a/tools/embedded-mpv/README.md b/tools/embedded-mpv/README.md index 38a7b949a..688f174a5 100644 --- a/tools/embedded-mpv/README.md +++ b/tools/embedded-mpv/README.md @@ -86,9 +86,11 @@ The macOS builder verifies every downloaded archive against its pinned SHA-256 digest before extraction. FreeType uses its official SourceForge distribution as the primary source and the official Savannah distribution as a fallback; a failed or mismatched download is discarded before the next -mirror is attempted. Changes to the downloader participate in the runtime -cache key, so cached native artifacts cannot outlive source-acquisition policy -changes. +mirror is attempted. The runtime manifest records the selected URL for a new +download and the complete ordered candidate list for every archive, so +fallback use remains visible in the source provenance. Changes to the +downloader participate in the runtime cache key, so cached native artifacts +cannot outlive source-acquisition policy changes. The Linux builder runs only on Linux x64. It requires the tool versions and system development interfaces declared in `build-linux-runtime.cjs`, including diff --git a/tools/embedded-mpv/build-macos-runtime.mjs b/tools/embedded-mpv/build-macos-runtime.mjs index 19e1347b3..325f366ab 100644 --- a/tools/embedded-mpv/build-macos-runtime.mjs +++ b/tools/embedded-mpv/build-macos-runtime.mjs @@ -318,7 +318,7 @@ function downloadSources() { } const archivePath = archivePathFor(sourcePackage); - const { sourceSha256 } = downloadPinnedSource({ + const { sourceSha256, sourceUrl, sourceUrls } = downloadPinnedSource({ archivePath, expectedSha256: sourcePackage.expectedSha256, urls: [sourcePackage.url, ...(sourcePackage.mirrors ?? [])], @@ -352,6 +352,8 @@ function downloadSources() { '1', ]); sourcePackage.sha256 = sourceSha256; + sourcePackage.sourceUrl = sourceUrl; + sourcePackage.sourceUrls = sourceUrls; } } @@ -511,7 +513,13 @@ function sourceMetadata(packageId) { const sourcePackage = packageById.get(packageId); return { version: sourcePackage.version, - sourceUrl: sourcePackage.url ?? sourcePackage.gitUrl, + sourceUrl: + sourcePackage.sourceUrl ?? + sourcePackage.url ?? + sourcePackage.gitUrl, + ...(sourcePackage.sourceUrls + ? { sourceUrls: sourcePackage.sourceUrls } + : {}), ...(sourcePackage.tag ? { sourceTag: sourcePackage.tag } : {}), ...(sourcePackage.sha256 ? { sourceSha256: sourcePackage.sha256 } @@ -541,7 +549,13 @@ function writeManifest() { sourcePackage.id, { version: sourcePackage.version, - sourceUrl: sourcePackage.url ?? sourcePackage.gitUrl, + sourceUrl: + sourcePackage.sourceUrl ?? + sourcePackage.url ?? + sourcePackage.gitUrl, + ...(sourcePackage.sourceUrls + ? { sourceUrls: sourcePackage.sourceUrls } + : {}), ...(sourcePackage.tag ? { sourceTag: sourcePackage.tag } : {}), diff --git a/tools/embedded-mpv/download-pinned-source.mjs b/tools/embedded-mpv/download-pinned-source.mjs index db68a8057..e50f9776e 100644 --- a/tools/embedded-mpv/download-pinned-source.mjs +++ b/tools/embedded-mpv/download-pinned-source.mjs @@ -19,11 +19,16 @@ export function downloadPinnedSource({ }) { const partialPath = `${archivePath}.partial`; const failures = []; + const sourceUrls = [...urls]; if (fs.existsSync(archivePath)) { const actualSha256 = sha256File(archivePath); if (actualSha256 === expectedSha256) { - return { sourceSha256: actualSha256, sourceUrl: null }; + return { + sourceSha256: actualSha256, + sourceUrl: null, + sourceUrls, + }; } failures.push( `cached archive: ${checksumFailure( @@ -34,7 +39,7 @@ export function downloadPinnedSource({ fs.rmSync(archivePath, { force: true }); } - for (const url of urls) { + for (const url of sourceUrls) { fs.rmSync(partialPath, { force: true }); try { download({ destinationPath: partialPath, url }); @@ -45,7 +50,7 @@ export function downloadPinnedSource({ ); } fs.renameSync(partialPath, archivePath); - return { sourceSha256: actualSha256, sourceUrl: url }; + return { sourceSha256: actualSha256, sourceUrl: url, sourceUrls }; } catch (error) { failures.push(`${url}: ${error.message}`); fs.rmSync(partialPath, { force: true }); diff --git a/tools/embedded-mpv/download-pinned-source.test.mjs b/tools/embedded-mpv/download-pinned-source.test.mjs index 2cd94debe..42c0e5bac 100644 --- a/tools/embedded-mpv/download-pinned-source.test.mjs +++ b/tools/embedded-mpv/download-pinned-source.test.mjs @@ -54,6 +54,20 @@ test('pins official FreeType mirrors in the macOS runtime builder', () => { builderSource, /0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289/ ); + assert.match( + builderSource, + /const\s*\{\s*sourceSha256,\s*sourceUrl,\s*sourceUrls\s*\}\s*=\s*downloadPinnedSource/ + ); + assert.match(builderSource, /sourcePackage\.sourceUrl = sourceUrl/); + assert.match(builderSource, /sourcePackage\.sourceUrls = sourceUrls/); + assert.match( + builderSource, + /sourceUrl:\s*sourcePackage\.sourceUrl\s*\?\?\s*sourcePackage\.url/ + ); + assert.match( + builderSource, + /sourcePackage\.sourceUrls\s*\?\s*\{\s*sourceUrls:\s*sourcePackage\.sourceUrls\s*\}/ + ); }); test('includes the pinned downloader in the macOS runtime cache key', () => { @@ -91,6 +105,7 @@ test('uses the next mirror when the primary source is unavailable', () => { assert.deepEqual(result, { sourceSha256: sha256(archive), sourceUrl: urls[1], + sourceUrls: urls, }); assert.equal(fs.existsSync(`${archivePath}.partial`), false); });