blob: 1dc820b94c1b26b7e266594f44ed537d649a7d33 [file] [log] [blame]
#!/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 = new Map();
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.has(name)) return; // Dedupe
seen.set(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 (name === 'echarts') publisher = 'Apache Software Foundation';
}
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);
},
);