diff --git a/desktop/scripts/build-sidecars.ts b/desktop/scripts/build-sidecars.ts index 52cf79be..3106468e 100644 --- a/desktop/scripts/build-sidecars.ts +++ b/desktop/scripts/build-sidecars.ts @@ -1,6 +1,9 @@ import { chmod, copyFile, mkdir, readFile, writeFile } from 'node:fs/promises' import path from 'node:path' -import { getBundledRipgrepName } from './prepare-ripgrep' +import { + getBundledRipgrepName, + stageRipgrepLicenses, +} from './prepare-ripgrep' const desktopRoot = path.resolve(import.meta.dir, '..') const repoRoot = path.resolve(desktopRoot, '..') @@ -27,6 +30,7 @@ if (scanExit !== 0) { } await mkdir(binariesDir, { recursive: true }) +await stageRipgrepLicenses(binariesDir) await stageHostRipgrepForOfflineBuild() // 单一合并 sidecar:server / cli 共享一份 bun runtime + 共享依赖代码。 diff --git a/desktop/scripts/prepare-ripgrep.test.ts b/desktop/scripts/prepare-ripgrep.test.ts index abaef226..425ff5fc 100644 --- a/desktop/scripts/prepare-ripgrep.test.ts +++ b/desktop/scripts/prepare-ripgrep.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, test } from 'vitest' -import { mkdtemp, rm, writeFile } from 'node:fs/promises' +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import path from 'node:path' import { @@ -7,7 +7,9 @@ import { getRipgrepAsset, getRipgrepDownloadUrl, prepareRipgrep, + RIPGREP_LICENSE_FILES, RIPGREP_VERSION, + stageRipgrepLicenses, } from './prepare-ripgrep' const tempDirs: string[] = [] @@ -59,6 +61,17 @@ describe('prepare-ripgrep target mapping', () => { ) }) + test('stages the pinned ripgrep license set for offline builds', async () => { + const fixtureDir = await mkdtemp(path.join(tmpdir(), 'cc-haha-ripgrep-licenses-')) + tempDirs.push(fixtureDir) + + const licensesDir = await stageRipgrepLicenses(fixtureDir) + + for (const fileName of RIPGREP_LICENSE_FILES) { + expect(await readFile(path.join(licensesDir, fileName), 'utf8')).not.toHaveLength(0) + } + }) + test('rejects a local archive that does not match the pinned checksum', async () => { const fixtureDir = await mkdtemp(path.join(tmpdir(), 'cc-haha-ripgrep-test-')) tempDirs.push(fixtureDir) diff --git a/desktop/scripts/prepare-ripgrep.ts b/desktop/scripts/prepare-ripgrep.ts index 33fabeaa..3e71c31b 100644 --- a/desktop/scripts/prepare-ripgrep.ts +++ b/desktop/scripts/prepare-ripgrep.ts @@ -14,7 +14,9 @@ import path from 'node:path' import { fileURLToPath } from 'node:url' export const RIPGREP_VERSION = '15.1.0' +export const RIPGREP_LICENSE_FILES = ['COPYING', 'LICENSE-MIT', 'UNLICENSE'] as const const scriptDirectory = path.dirname(fileURLToPath(import.meta.url)) +const ripgrepLicenseSourceDirectory = path.join(scriptDirectory, 'ripgrep-licenses') type RipgrepAsset = { assetTriple: string @@ -80,6 +82,17 @@ export function getRipgrepDownloadUrl(targetTriple: string): string { return `https://github.com/BurntSushi/ripgrep/releases/download/${RIPGREP_VERSION}/${asset.archiveName}` } +export async function stageRipgrepLicenses(binariesDir: string): Promise { + const licensesDir = path.join(binariesDir, 'ripgrep-licenses') + await mkdir(licensesDir, { recursive: true }) + await Promise.all(RIPGREP_LICENSE_FILES.map(fileName => + copyFile( + path.join(ripgrepLicenseSourceDirectory, fileName), + path.join(licensesDir, fileName), + ))) + return licensesDir +} + export async function prepareRipgrep({ targetTriple, archivePath = process.env.CC_HAHA_RIPGREP_ARCHIVE, @@ -157,13 +170,7 @@ export async function prepareRipgrep({ }, null, 2)}\n`, ) - const licensesDir = path.join(binariesDir, 'ripgrep-licenses') - await mkdir(licensesDir, { recursive: true }) - await Promise.all([ - copyFile(path.join(archiveRoot, 'COPYING'), path.join(licensesDir, 'COPYING')), - copyFile(path.join(archiveRoot, 'LICENSE-MIT'), path.join(licensesDir, 'LICENSE-MIT')), - copyFile(path.join(archiveRoot, 'UNLICENSE'), path.join(licensesDir, 'UNLICENSE')), - ]) + await stageRipgrepLicenses(binariesDir) console.log(`[prepare-ripgrep] ${destination}`) return destination diff --git a/desktop/scripts/ripgrep-licenses/COPYING b/desktop/scripts/ripgrep-licenses/COPYING new file mode 100644 index 00000000..bb9c20a0 --- /dev/null +++ b/desktop/scripts/ripgrep-licenses/COPYING @@ -0,0 +1,3 @@ +This project is dual-licensed under the Unlicense and MIT licenses. + +You may use this code under the terms of either license. diff --git a/desktop/scripts/ripgrep-licenses/LICENSE-MIT b/desktop/scripts/ripgrep-licenses/LICENSE-MIT new file mode 100644 index 00000000..3b0a5dc0 --- /dev/null +++ b/desktop/scripts/ripgrep-licenses/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/desktop/scripts/ripgrep-licenses/UNLICENSE b/desktop/scripts/ripgrep-licenses/UNLICENSE new file mode 100644 index 00000000..68a49daa --- /dev/null +++ b/desktop/scripts/ripgrep-licenses/UNLICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to