blob: cd4ad4d9c99c1dec9d987c0239d64ec60c4dcce9 [file] [log] [blame]
/*
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.
*/
var nlf = require('nlf'),
treeify = require('treeify'),
optimist = require('optimist'),
fs = require('fs'),
path = require('path'),
Q = require('q'),
flagutil = require('./flagutil');
var jsonObject = {},
validLicenses = [],
knownIssues = {},
licensesFile = path.join('cordova-coho', 'src', 'validLicenses.json'),
knownIssuesFile = path.join('cordova-coho', 'src', 'knownIssues.json'),
reposWithDependencies = [],
flagged = [];
module.exports = function*(argv) {
var opt = flagutil.registerRepoFlag(optimist)
opt = flagutil.registerHelpFlag(opt);
var argv = opt
.usage('Go through each specified repo and check the licenses of node modules that are 3rd-party dependencies.\n\n' +
'Usage: $0 check-license --repo=name [-r repos]')
.argv;
if (argv.h) {
optimist.showHelp();
process.exit(1);
}
var repos = flagutil.computeReposFromFlag(argv.r, {includeModules: true});
checkLicense(repos);
};
function getRepoLicense(repoName){
return Q.nfapply(nlf.find, [{
directory : path.join(process.cwd(), repoName)
}
]).then(function (p) {
return p;
});
}
function checkLicense(repos) {
//get the license info for each repo's dependencies and sub-dependencies
var results = [];
var previous = Q.resolve();
repos.forEach(function (repo) {
previous = previous.then(function () {
var packageDir = findPackageDir(repo);
if (packageDir) {
reposWithDependencies.push(repo.id);
return getRepoLicense(packageDir);
} else {
Q.resolve('Repo directory does not exist: ' + repos.repoName + '. First run coho repo-clone.'); //don't end execution if repo doesn't have dependencies or doesn't exist
}
}).then(function (data) {
results.push(data); //push the result of this repo to the results array for later processing
});
});
//process the results after the licenses for all repos have been retrieved
previous.then(function (result) {
processResults(results, repos);
}, function (err) {
console.log(err);
});
}
function findPackageDir(repo) {
var packageDir = repo.repoName;
if (repo.path) {
packageDir = path.join(packageDir, repo.path);
}
return fs.existsSync(path.join(packageDir, 'package.json')) ? packageDir : null;
}
//process the results of each repo
function processResults(results, repos) {
//get valid licenses file to flag packages
validLicenses = fs.readFileSync(licensesFile, 'utf8');
if (!validLicenses)
{
console.log('No valid licenses file. Please make sure it exists.');
return;
}
validLicenses = (JSON.parse(validLicenses)).validLicenses;
//get known issues file to report known package issues
knownIssues = fs.readFileSync(knownIssuesFile, 'utf8');
if (!knownIssues)
{
console.log('No known issues file. Please make sure it exists.');
return;
}
knownIssues = JSON.parse(knownIssues);
//go through each repo, get its dependencies and add to json object
for (var i = 0; i < results.length; ++i) {
var repo = repos[i];
if (reposWithDependencies.indexOf(repo.id) > -1)
{
var repoJsonObj = {};
repoJsonObj.dependencies = getDependencies(results[i]);
var repoIdentifier = repo.repoName;
if (repo.path) {
repoIdentifier += "/" + repo.path;
}
jsonObject[repoIdentifier] = repoJsonObj;
}
}
//output results (license info for all packages + list of flagged packages)
console.log('Below is the license info for all the packages');
console.log(treeify.asTree(jsonObject, true));
console.log('\n***********************************************************************************************************************');
console.log('***********************************************************************************************************************');
console.log('***********************************************************************************************************************\n');
if (flagged.length) {
for (var j = 0; j < flagged.length; ++j)
{
if (knownIssues[ flagged[j].name ]) {
flagged[j]['known-issues'] = knownIssues[ flagged[j].name ];
}
console.log(treeify.asTree(flagged[j], true));
}
console.log(flagged.length + ' packages were flagged. Please verify manually that the licenses are valid. See those packages above, and update knownIssues.json with your findings, if applicable.');
} else {
console.log('No packages were flagged.');
}
}
//get dependencies for a repo
function getDependencies(packages) {
var dependencies = [];
for (var j = 0; j < packages.length; ++j)
{
//pull out only relevant info and add to dependencies array
var obj = {};
obj.name = packages[j].name;
obj.id = packages[j].id;
obj.directory = [packages[j].directory];
obj.licenses = packages[j].licenseSources.package.sources;
dependencies.push(obj);
//flag any packages whose licenses may not be compatible
if (!hasValidLicense(obj))
{
var duplicate = false;
//avoid duplicating already flagged packages
for (var z = 0; z < flagged.length; ++z)
{
if (flagged[z].id == obj.id)
{
duplicate = true;
break;
}
}
if (duplicate)
flagged[z].directory = flagged[z].directory.concat(obj.directory); //if it is already flagged then just add the directory to the directories array
else
flagged.push(JSON.parse(JSON.stringify(obj)));
}
}
return dependencies;
}
//check if package has valid licenses
function hasValidLicense(package) {
var isValid = false;
if (package.licenses.length == 0)
return isValid;
else
{
//go through each license of the package
for (var x = 0; x < package.licenses.length; ++x)
{
isValid = false;
//go through valid licenses and try to match with package license
for (var y = 0; y < validLicenses.length; ++y)
{
var pattern = new RegExp(validLicenses[y], "gi"); //construct regular expression from valid license
if ((package.licenses[x].license).match(pattern)) //match it against the package license
isValid = true;
}
//shortcut - if one license isn't valid then go ahead and flag it
if (isValid == false)
break;
}
}
return isValid;
}