#!/usr/bin/env node /* * 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. */ const fs = require('fs'); const checker = require('license-checker'); const LICENSES_FILE = '../licenses.yaml'; const START_MARKER_LINE = '# Web console modules start'; const END_MARKER_LINE = '# Web console modules end'; const SEPARATOR = '\n\n---\n\n'; const extraLinesForLib = {}; const extraPackages = { // This is a OSS font so it is not listed by the npm scraper but we still want to attribute it so pretend to inject it // as a phantom package 'opensans@1.101.0': { licenses: 'Apache-2.0', repository: 'https://github.com/google/fonts/tree/master/apache/opensans', publisher: 'Google', url: 'https://fonts.google.com/specimen/Open+Sans', }, }; function injectConsoleLicenses(consoleLicenses) { const text = fs.readFileSync(LICENSES_FILE, 'utf-8'); const textLines = text.split('\n'); // Extract the license for the file itself let beforeLines = []; let afterLines = []; let state = 'before'; for (let textLine of textLines) { switch (state) { case 'before': beforeLines.push(textLine); if (textLine === START_MARKER_LINE) { state = 'main'; } break; case 'main': if (textLine === END_MARKER_LINE) { state = 'after'; afterLines.push(textLine); } break; case 'after': afterLines.push(textLine); break; } } if (state === 'before') throw new Error(`missing starter marker '${START_MARKER_LINE}'`); if (state === 'main') throw new Error(`missing ending marker '${END_MARKER_LINE}'`); // Write out the new file fs.writeFileSync( LICENSES_FILE, [beforeLines.join('\n'), consoleLicenses.join(SEPARATOR), afterLines.join('\n')].join('\n'), ); } checker.init( { start: '.', production: true, }, function (err, packages) { if (err) { console.log('err', err); return; } Object.assign(packages, extraPackages); const seen = {}; const mapped = Object.keys(packages) .sort() .map(p => { const m = p.match(/^(.+)@(\d+\.\d+\.\d+.*)$/); if (!m) throw new Error(`Malformed name@version`); const name = m[1]; if (name === 'web-console') return; // This is me! if (seen[name]) return; // Dedupe seen[name] = true; const version = m[2]; const meta = packages[p]; let { publisher, licenses, licenseFile } = meta; if (!licenses) throw new Error(`Package '${p} does not have a licenses`); let properLicenseName; // Map the licenses to their proper name let licenseExt; // Map the licenses to the right extension switch (licenses) { case 'MIT': properLicenseName = 'MIT License'; licenseExt = 'MIT'; break; case 'ISC': properLicenseName = 'ISC License'; licenseExt = 'ISC'; break; case 'Apache-2.0': properLicenseName = 'Apache License version 2.0'; licenseExt = 'A2'; break; case 'BSD-2-Clause': properLicenseName = 'BSD-2-Clause License'; licenseExt = 'BSD2'; break; case 'BSD-3-Clause': properLicenseName = 'BSD-3-Clause License'; licenseExt = 'BSD3'; break; case '0BSD': properLicenseName = 'Zero-Clause BSD'; licenseExt = '0BSD'; break; default: throw new Error(`Unknown license '${licenses}' in ${p}`); } const simpleName = name.replace('/', '-'); const licenseDest = `licenses/bin/${simpleName}.${licenseExt}`; let hasLicense = false; if (licenseExt !== 'A2') { if (licenseFile && licenseFile.match(/\/license(?:\.\w+)?/i)) { // If the file ends with license.ext? then copy it over try { fs.copyFileSync(licenseFile, `../${licenseDest}`); hasLicense = true; } catch (e) { console.log(`Could not copy license for '${p}': ${JSON.stringify(meta)}`); } } else { // See if the license is already there (manually) keep it try { fs.statSync(`../${licenseDest}`); hasLicense = true; } catch (e) { console.log(`Could not find license for '${p}': ${JSON.stringify(meta)}`); console.log(`Find and copy the package's license file to '../${licenseDest}'`); } } } if (!publisher && hasLicense) { // Extract copyright from license const licenseText = fs.readFileSync(`../${licenseDest}`, 'utf-8'); const m = licenseText.match( /(?:^|\n)\s*Copyright(?: (?:\(c\)|©))?(?: 2[0-9]{3}(?:-\w+)?,?)? ([^0-9][^\n]*)\n/m, ); if (m) { publisher = m[1] .replace(/All rights reserved./i, '') .replace(/[0-9-]{4,9}/, '') .trim(); } } if (!publisher) { // Hand coded copyrights if (name === 'asap') publisher = 'Contributors'; if (name === 'diff-match-patch') publisher = 'Google'; if (name === 'esutils') publisher = 'Yusuke Suzuki'; // https://github.com/estools/esutils#license } if (!publisher) { console.log(`No license for '${name}' ('${licenseDest}')`); } // Make our blob const lines = [ `name: "${name}"`, `license_category: binary`, `module: web-console`, `license_name: ${properLicenseName}`, publisher ? `copyright: ${publisher}` : undefined, `version: ${version}`, hasLicense ? `license_file_path: ${licenseDest}` : undefined, extraLinesForLib[name], ]; return lines.filter(Boolean).join('\n'); }) .filter(Boolean); injectConsoleLicenses(mapped); }, );