Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spdx backend #15

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions LICENSE.spdx.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
Creator: [user]
PackageName: [name]
PackageOriginator: [user]
PackageHomePage: [webpage]
PackageLicenseDeclared: [spdx-license-identifier]
55 changes: 37 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,52 @@ npm install --global @captainsafia/legit
### Usage

```
Usage: legit [options]
Usage: legit [options] [placeholders]

Options:

-h, --help output usage information
-V, --version output the version number
-a, --list-all List installed licenses
-l, --license <license> The license to include
-u, --user <user> The individual who owns the license
-y, --year <year> The year the license is effective
-l, --license The license to include, as an SPDX License Identifier (mandatory)

Placeholders:
<key>=<value>
```

![Legit Demo](legit-demo.gif)
### Example
```
mkdir /tmp/test ; cd $_
legit -l Apache-2.0 year=2001 user=maoo name=legit webpage=https://github.com/maoo/legit
```

If not `year` is the defined, the current one is used.

Placeholder keys are resolved against [license-placeholders.yml](license-placeholders.yml) definition, depending on the license in use.

If no placeholders configuration is available for the requested license, legit will prepend the following license header:
```
Copyright (c) [year] [user]


```

### Supported Licenses

legit uses SPDX license IDs and definitions as a backend, therefore all [SPDX licenses](https://spdx.org/licenses/) are supported.

[license-placeholders.yml](license-placeholders.yml) defines placeholder mappings for the following licenses:

### Available Licenses
- [AGPL-3.0](https://spdx.org/licenses/AGPL-3.0.html)
- [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html)
- [BSD-2-Clause](https://spdx.org/licenses/BSD-2-Clause.html)
- [ISC](https://spdx.org/licenses/ISC.html)
- [MIT](https://spdx.org/licenses/MIT.html)
- [MPL-2.0](https://spdx.org/licenses/MPL-2.0.html)
- [Unlicense](https://spdx.org/licenses/Unlicense.html)

legit currently supports a limited subset of licenses, listed below. In order
to add a license, submit a pull request that contains a template of the license
inside the `licenses` directory with the strings `[user]` and `[year]` used to
denote where the parameters should be inserted.
### Known issues

#### Currently Supported Licenses
- MIT (mit)
- Mozilla Public License 2.0 (mpl2)
- Apache License 2.0 (apache2)
- GNU Affero General Public License 3.0 (agpl3)
- ISC License (isc)
- BSD 2-Clause License (bsd2clause)
- Unlicense (unlicense)
- placeholders including `'` character don't work
- Regexp support for license placeholders
- Integrate with [SPDX Templatizing efforts](https://wiki.spdx.org/view/Legal_Team/Templatizing)
134 changes: 107 additions & 27 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,129 @@

var fs = require('fs');
var program = require('commander');
const licensesPath = __dirname + '/licenses/';
var spdxLicenses = require('spdx-licenses');
var spdxLicenseIds = require('spdx-license-ids');
var request = require('sync-request');
var yaml = require('node-yaml');
var replaceAll = require("replaceall");

// Easily switch on/off debugging statements
var isDebugMode = false;
console.debug = function(args) {
if (isDebugMode) {
console.log(args);
}
}

function validateLicense(license) {
license = license.toLowerCase();
const licenses = fs.readdirSync(licensesPath);
if (licenses.indexOf(license) > -1) {
return license;
spdxLicense = spdxLicenses.spdx(license);
if (spdxLicense) {
console.debug('Found SPDX License: ' + spdxLicense.id + ' (' + spdxLicense.name + ')');
} else {
return 'mit';
console.error('Unknown SPDX license identifier ' + license + '; please refer to https://spdx.org/licenses');
process.exit(1);
}
return spdxLicense.id;
}

program
.version('1.0.0')
.usage('[options]')
.option('-a, --list-all', 'List installed licenses')
.option('-l, --license <license>', 'The license to include', validateLicense)
.option('-u, --user <user>', 'The individual who owns the license')
.option('-y, --year <year>', 'The year the license is effective')
.usage('[options] [key=value replacement pairs]')
.option('-a, --list-all', 'List all SPDX license identifiers')
.option('-l, --license <license>', 'The license to include, as an SPDX license identifier (mandatory)', validateLicense)
.parse(process.argv);

console.debug(program.args);

if (program.license) {
const cwd = process.cwd();
const licenseFile = licensesPath + program.license;
fs.readFile(licenseFile, 'utf8', function (error, data) {
if (error) console.log(error);
if (program.user) {
var year = program.year || new Date().getFullYear();
var result = data.replace('[user]', program.user).replace('[year]', year);
fs.writeFile(cwd + '/LICENSE', result, 'utf8', function (error) {
if (error) return console.log(error);

// Create a placeholders hash
var placeholders = {}
program.args.forEach(function(placeholder) {
keyValue = placeholder.split("=");
placeholders[keyValue[0]] = keyValue[1];
});

// Populate defaults, if needed
placeholders['spdx-license-identifier'] = program.license;
placeholders['year'] = placeholders['year'] || (new Date().getFullYear()).toString();
placeholders['webpage'] = placeholders['webpage'] || "NONE"; // See https://spdx.org/spdx-specification-21-web-version#h.3o7alnk

// Fetch license text from official SPDX license list on GitHub
var licenseUrl = 'https://raw.githubusercontent.com/spdx/license-list/master/' + program.license + '.txt';
var licenseText = request('GET', licenseUrl).getBody().toString('utf8');

// Write LICENSE file
fs.readFile(__dirname + '/license-placeholders.yml', 'utf8', function (error, data) {
if (error) {
console.log(error);
process.exit(1);
} else {
// Replace placeholders them in the license text
console.debug('license placeholders raw:\n' + data);
var licensePlaceholders = yaml.parse(data);

var parsedLicenseText = licenseText;

placeholderTokens = licensePlaceholders[program.license];

// Define default license header
if (!placeholderTokens) {
parsedLicenseText = "Copyright (c) [year] [user]\n\n"+parsedLicenseText;
placeholderTokens = [{
"user": '[user]',
"year": '[year]'
}]
}

placeholderTokens.forEach(function(placeholderItem) {
Object.keys(placeholderItem).forEach(function(placeholderKey) {
var placeholderToken = placeholderItem[placeholderKey];
var placeholderValue = placeholders[placeholderKey];
console.debug('Replacing ' + placeholderToken + ' with ' + placeholderValue + ' in LICENSE text');
if (placeholderValue) {
parsedLicenseText = replaceAll(placeholderToken, placeholderValue, parsedLicenseText);
} else {
console.log("WARNING! Couldn't read placeholder '" + placeholderToken + "' from command-line params");
}
});
});

// Write content
fs.writeFile(cwd + '/LICENSE', parsedLicenseText, 'utf8', function (error) {
if (error) {
console.error(error);
process.exit(1);
}})}});

// Write LICENSE.spdx file
fs.readFile(__dirname + "/LICENSE.spdx.template", 'utf8', function (error, data) {
if (error) {
console.log(error);
process.exit(1);
} else {
program.help();
}
});
var spdxLicenseText = data;
Object.keys(placeholders).forEach(function(placeholderKey) {
var placeholderValue = placeholders[placeholderKey];
var placeholderToken = '[' + placeholderKey + ']';
if (placeholderValue) {
spdxLicenseText = replaceAll(placeholderToken, placeholderValue, spdxLicenseText);
} else {
console.log("WARNING! Couldn't read placeholder '" + placeholderKey + "' from command-line params");
}
});

fs.writeFile(cwd + '/LICENSE.spdx', spdxLicenseText, 'utf8', function (error) {
if (error) {
console.error(error);
process.exit(1);
}});
}});
} else if (program.listAll) {
fs.readdir(licensesPath, function (err, items) {
for (var i = 0; i < items.length; i++) {
console.log(items[i]);
}
})
spdxLicenseIds.sort().forEach(function(spdxLicenseId) {
console.log(spdxLicenseId);
});
} else {
program.help();
}
26 changes: 26 additions & 0 deletions license-placeholders.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# List of placeholders resolved in SPDX licences - https://spdx.org/licenses
#
# Commented lines define licenses that don't include placeholders in their text
#
AGPL-3.0:
- user: '<name of author>'
- year: '<year>'
- name: '<one line to give the programs name and a brief idea of what it does.>'

Apache-2.0:
- user: '[name of copyright owner]'
- year: '[yyyy]'

BSD-2-Clause:
- user: '<owner>'
- year: '<year>'

# ISC:

MIT:
- user: '<copyright holders>'
- year: '<year>'

# MPL-2.0:

# Unlicense:
Loading