diff --git a/.github/workflows/build_on_pr_label.yml b/.github/workflows/build_on_pr_label.yml index b8b925055..ee02e3d61 100644 --- a/.github/workflows/build_on_pr_label.yml +++ b/.github/workflows/build_on_pr_label.yml @@ -75,6 +75,17 @@ jobs: packages/backend-server key: ${{ runner.os }}-${{ matrix.architecture }}-rust-${{ hashFiles('**/Cargo.lock') }} + - name: Cache cargo-about binary + id: cache-cargo-about + uses: actions/cache@v3 + with: + path: ~/.cargo/bin/cargo-about + key: ${{ runner.os }}-${{ matrix.architecture }}-cargo-about-0.8.2 + + - name: Install cargo-about + if: steps.cache-cargo-about.outputs.cache-hit != 'true' + run: cargo install cargo-about --version 0.8.2 + - name: Cache Turbo uses: actions/cache@v3 with: diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 997e35e15..b43a9bb8e 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -97,9 +97,6 @@ jobs: toolchain: stable override: true - - name: Install cargo-about - run: cargo install cargo-about - - name: Cache node_modules uses: actions/cache@v3 with: @@ -114,9 +111,19 @@ jobs: workspaces: | packages/backend packages/backend-server - ~/.cargo/bin/cargo-about key: ${{ runner.os }}-${{ matrix.architecture }}-rust-${{ hashFiles('**/Cargo.lock') }} + - name: Cache cargo-about binary + id: cache-cargo-about + uses: actions/cache@v3 + with: + path: ~/.cargo/bin/cargo-about + key: ${{ runner.os }}-${{ matrix.architecture }}-cargo-about-0.8.2 + + - name: Install cargo-about + if: steps.cache-cargo-about.outputs.cache-hit != 'true' + run: cargo install cargo-about --version 0.8.2 + - name: Cache Turbo uses: actions/cache@v3 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 646cb0cc6..274b569fe 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -87,9 +87,6 @@ jobs: toolchain: stable override: true - - name: Install cargo-about - run: cargo install cargo-about - - name: Cache node_modules uses: actions/cache@v3 with: @@ -104,9 +101,19 @@ jobs: workspaces: | packages/backend packages/backend-server - ~/.cargo/bin/cargo-about key: ${{ runner.os }}-${{ matrix.architecture }}-rust-${{ hashFiles('**/Cargo.lock') }} + - name: Cache cargo-about binary + id: cache-cargo-about + uses: actions/cache@v3 + with: + path: ~/.cargo/bin/cargo-about + key: ${{ runner.os }}-${{ matrix.architecture }}-cargo-about-0.8.2 + + - name: Install cargo-about + if: steps.cache-cargo-about.outputs.cache-hit != 'true' + run: cargo install cargo-about --version 0.8.2 + - name: Cache Turbo uses: actions/cache@v3 with: diff --git a/app/plugins/rust-license.ts b/app/plugins/rust-license.ts index e5fb317f9..026875807 100644 --- a/app/plugins/rust-license.ts +++ b/app/plugins/rust-license.ts @@ -1,6 +1,6 @@ import { spawnSync } from 'child_process' import { join } from 'path' -import { writeFileSync, readFileSync, existsSync, readdirSync } from 'fs' +import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs' import type { Plugin } from 'vite' const NOTICE_FILE_VARIATIONS = [ @@ -51,23 +51,6 @@ const findNoticeInCargoRegistry = (packageName: string, version: string): string return null } -interface UsedBy { - name: string - version: string - license: string - repository?: string - description?: string - authors: string[] -} - -interface License { - id: string - name: string - text: string - source_path?: string - used_by: UsedBy[] -} - const generateCargoLicenseFile = (cargoTomlPath: string, outputPath: string) => { const absoluteCargoPath = join(process.cwd(), '..', cargoTomlPath) console.log( @@ -90,7 +73,16 @@ const generateCargoLicenseFile = (cargoTomlPath: string, outputPath: string) => const result = spawnSync( 'cargo', - ['about', 'generate', '--all-features', '--config', 'about.toml', 'about.hbs'], + [ + 'about', + 'generate', + '--all-features', + '--config', + 'about.toml', + '--output-file', + outputPath, + 'about.hbs' + ], { cwd: absoluteCargoPath, encoding: 'utf8', @@ -113,51 +105,36 @@ const generateCargoLicenseFile = (cargoTomlPath: string, outputPath: string) => console.log(`Cargo about generated license info successfully`) - const licenses: License[] = JSON.parse(result.stdout) - let output = '' - - for (const license of licenses) { - for (const pkg of license.used_by) { - output += `Name: ${pkg.name}\n` - output += `Version: ${pkg.version}\n` - output += `License: ${pkg.license || 'Unknown'}\n` + if (!existsSync(outputPath)) { + throw new Error(`cargo-about did not create output file at ${outputPath}`) + } - if (pkg.description) { - output += `Description: ${pkg.description}\n` - } + let content = readFileSync(outputPath, 'utf8') - if (pkg.repository) { - output += `Repository: ${pkg.repository}\n` - } + const packageRegex = /Name: (.+?)\nVersion: (.+?)\nLicense: (.+?)\n/g + const insertions: { index: number; content: string }[] = [] - if (pkg.authors && pkg.authors.length > 0) { - output += `Authors: ${pkg.authors.join(', ')}\n` - } + let match: RegExpExecArray | null + while ((match = packageRegex.exec(content)) !== null) { + const [fullMatch, name, version, license] = match - // we need this for NOTICE files for Apache - if (isApacheLicense(pkg.license)) { - const noticeContent = findNoticeInCargoRegistry(pkg.name, pkg.version) - if (noticeContent) { - output += '\nNOTICE:\n```\n' - output += noticeContent - output += '\n```\n' - } else { - output += '\nNOTICE: Not found in package (Apache license may require NOTICE file)\n' - } - } + if (isApacheLicense(license)) { + const noticeContent = findNoticeInCargoRegistry(name, version) + const insertIndex = match.index + fullMatch.length - if (license.text) { - output += `\nLicense Text (${license.name}):\n` - output += '```\n' - output += license.text - output += '\n```\n' + if (noticeContent) { + const noticeBlock = `\nNOTICE:\n\`\`\`\n${noticeContent}\n\`\`\`\n` + insertions.push({ index: insertIndex, content: noticeBlock }) } - - output += '\n---\n\n' } } - writeFileSync(outputPath, output) + insertions.reverse() + for (const { index, content: insertContent } of insertions) { + content = content.slice(0, index) + insertContent + content.slice(index) + } + + writeFileSync(outputPath, content) console.log(`License file written to ${outputPath}`) } diff --git a/packages/backend-server/about.hbs b/packages/backend-server/about.hbs index e719cd485..e948b08d3 100644 --- a/packages/backend-server/about.hbs +++ b/packages/backend-server/about.hbs @@ -1,22 +1,19 @@ -[ {{#each licenses}} -{ - "id": "{{id}}", - "name": "{{name}}", - "text": {{{json text}}}, - "source_path": {{#if source_path}}"{{source_path}}"{{else}}null{{/if}}, - "used_by": [ - {{#each used_by}} - { - "name": "{{crate.name}}", - "version": "{{crate.version}}", - "license": "{{crate.license}}", - "repository": {{#if crate.repository}}"{{crate.repository}}"{{else}}null{{/if}}, - "description": {{#if crate.description}}{{{json crate.description}}}{{else}}null{{/if}}, - "authors": [{{#each crate.authors}}"{{this}}"{{#unless @last}},{{/unless}}{{/each}}] - }{{#unless @last}},{{/unless}} - {{/each}} - ] -}{{#unless @last}},{{/unless}} +{{#each used_by}} +Name: {{{crate.name}}} +Version: {{{crate.version}}} +License: {{#if crate.license}}{{{crate.license}}}{{else}}Unknown{{/if}} +{{#if crate.description}}Description: {{{crate.description}}} +{{/if}}{{#if crate.repository}}Repository: {{{crate.repository}}} +{{/if}}{{#if crate.authors}}Authors: {{#each crate.authors}}{{{this}}}{{#unless @last}}, {{/unless}}{{/each}} +{{/if}} + +License Text ({{{../name}}}): +``` +{{{../text}}} +``` + +--- + +{{/each}} {{/each}} -] diff --git a/packages/backend/about.hbs b/packages/backend/about.hbs index e719cd485..e948b08d3 100644 --- a/packages/backend/about.hbs +++ b/packages/backend/about.hbs @@ -1,22 +1,19 @@ -[ {{#each licenses}} -{ - "id": "{{id}}", - "name": "{{name}}", - "text": {{{json text}}}, - "source_path": {{#if source_path}}"{{source_path}}"{{else}}null{{/if}}, - "used_by": [ - {{#each used_by}} - { - "name": "{{crate.name}}", - "version": "{{crate.version}}", - "license": "{{crate.license}}", - "repository": {{#if crate.repository}}"{{crate.repository}}"{{else}}null{{/if}}, - "description": {{#if crate.description}}{{{json crate.description}}}{{else}}null{{/if}}, - "authors": [{{#each crate.authors}}"{{this}}"{{#unless @last}},{{/unless}}{{/each}}] - }{{#unless @last}},{{/unless}} - {{/each}} - ] -}{{#unless @last}},{{/unless}} +{{#each used_by}} +Name: {{{crate.name}}} +Version: {{{crate.version}}} +License: {{#if crate.license}}{{{crate.license}}}{{else}}Unknown{{/if}} +{{#if crate.description}}Description: {{{crate.description}}} +{{/if}}{{#if crate.repository}}Repository: {{{crate.repository}}} +{{/if}}{{#if crate.authors}}Authors: {{#each crate.authors}}{{{this}}}{{#unless @last}}, {{/unless}}{{/each}} +{{/if}} + +License Text ({{{../name}}}): +``` +{{{../text}}} +``` + +--- + +{{/each}} {{/each}} -]