/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import { execFileSync } from 'node:child_process'; import { createHash } from 'node:crypto'; import { readdirSync, readFileSync, writeFileSync } from 'node:fs'; import { dirname, join, relative } from 'node:path'; import { fileURLToPath } from 'node:url'; const repoRoot = dirname(dirname(fileURLToPath(import.meta.url))); const manifestPath = join(repoRoot, 'experiments', 'windows-sandbox', 'launcher', 'Cargo.toml'); const lockPath = join(repoRoot, 'experiments', 'windows-sandbox', 'launcher', 'Cargo.lock'); const outputPath = join( repoRoot, 'apps', 'desktop', 'resources', 'licenses', 'cargo', 'THIRD_PARTY_NOTICES.txt', ); const check = process.argv.includes('--check'); const metadata = JSON.parse( execFileSync( process.env.CARGO ?? 'cargo', ['metadata', '--manifest-path', manifestPath, '--locked', '--format-version', '1'], { cwd: repoRoot, encoding: 'utf8' }, ), ); const packages = metadata.packages .filter((pkg) => pkg.name !== 'maka-windows-sandbox-spike') .sort((left, right) => Buffer.compare( Buffer.from(`${left.name}@${left.version}`, 'utf8'), Buffer.from(`${right.name}@${right.version}`, 'utf8'), ), ); const sections = packages.map((pkg) => { if (!pkg.license) throw new Error(`${pkg.name}@${pkg.version}: missing SPDX license metadata`); const directory = dirname(pkg.manifest_path); const licenseFiles = readdirSync(directory, { withFileTypes: true }) .filter( (entry) => entry.isFile() && /^(licen[cs]e|copying|notice)(?:[._-].*)?$/iu.test(entry.name), ) .map((entry) => entry.name) .sort(); if (licenseFiles.length === 0) { throw new Error(`${pkg.name}@${pkg.version}: packaged crate has no license or notice text`); } const source = pkg.repository ?? pkg.homepage ?? pkg.source ?? 'unknown'; const heading = `${pkg.name} ${pkg.version}`; return [ heading, '-'.repeat(heading.length), `SPDX license: ${pkg.license}`, `Source: ${source}`, ...licenseFiles.flatMap((name) => [ '', `--- ${name} ---`, readFileSync(join(directory, name), 'utf8').replace(/\r\n?/gu, '\n').trimEnd(), ]), ].join('\n'); }); const lockDigest = createHash('sha256').update(readFileSync(lockPath)).digest('hex'); const output = `Maka Windows sandbox Cargo dependency notices ================================================ Generated by scripts/generate-windows-cargo-notices.mjs from the exact Cargo.lock dependency graph. Do not edit this file by hand. Manifest: ${relative(repoRoot, manifestPath).replaceAll('\\', '/')} Cargo.lock SHA-256: ${lockDigest} ${sections.join('\n\n')} `; if (check) { const existing = readFileSync(outputPath, 'utf8'); if (existing !== output) { throw new Error( 'Windows Cargo dependency notices are stale. Run npm run generate:windows-cargo-notices.', ); } console.log('[windows-cargo-notices] OK — Cargo dependency inventory is current.'); } else { writeFileSync(outputPath, output); console.log(`[windows-cargo-notices] wrote ${outputPath}`); }