1
0
Fork 0

Merge pull request #4264 from alcohol/use-composer-spdx

remove spdx files, introduce external library
pull/4299/head^2
Jordi Boggiano 2015-07-20 18:29:14 +01:00
commit 00c26791fa
13 changed files with 95 additions and 1810 deletions

View File

@ -1,10 +0,0 @@
#!/usr/bin/env php
<?php
require __DIR__ . '/../src/bootstrap.php';
use Composer\Util\SpdxLicensesUpdater;
$updater = new SpdxLicensesUpdater;
$updater->dumpLicenses(__DIR__ . '/../res/spdx-licenses.json');
$updater->dumpExceptions(__DIR__ . '/../res/spdx-exceptions.json');

View File

@ -23,7 +23,8 @@
},
"require": {
"php": ">=5.3.2",
"justinrainbow/json-schema": "~1.4",
"justinrainbow/json-schema": "^1.4.4",
"composer/spdx-licenses": "~1.0",
"seld/jsonlint": "~1.0",
"symfony/console": "~2.5",
"symfony/finder": "~2.2",

78
composer.lock generated
View File

@ -4,24 +4,84 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "556ac817fc0b456bddc48918ef09930d",
"hash": "ed946efe7113827ff28dec6e3679b74b",
"packages": [
{
"name": "justinrainbow/json-schema",
"version": "1.4.1",
"name": "composer/spdx-licenses",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "2465fe486c864e30badaa4d005ebdf89dbc503f3"
"url": "https://github.com/composer/spdx-licenses.git",
"reference": "2f17228c1b98283b779698cefa917f7f4fd0b0d4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/2465fe486c864e30badaa4d005ebdf89dbc503f3",
"reference": "2465fe486c864e30badaa4d005ebdf89dbc503f3",
"url": "https://api.github.com/repos/composer/spdx-licenses/zipball/2f17228c1b98283b779698cefa917f7f4fd0b0d4",
"reference": "2f17228c1b98283b779698cefa917f7f4fd0b0d4",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "~2.3"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"Composer\\Spdx\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Bast",
"email": "rob.bast@gmail.com"
},
{
"name": "Nils Adermann",
"email": "naderman@naderman.de",
"homepage": "http://www.naderman.de"
},
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "SPDX licenses list and validation library.",
"keywords": [
"license",
"spdx",
"validator"
],
"time": "2015-07-17 06:17:03"
},
{
"name": "justinrainbow/json-schema",
"version": "1.4.4",
"source": {
"type": "git",
"url": "https://github.com/justinrainbow/json-schema.git",
"reference": "8dc9b9d85ab639ca60ab4608b34c1279d6ae7bce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/8dc9b9d85ab639ca60ab4608b34c1279d6ae7bce",
"reference": "8dc9b9d85ab639ca60ab4608b34c1279d6ae7bce",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"json-schema/json-schema-test-suite": "1.1.0",
@ -70,7 +130,7 @@
"json",
"schema"
],
"time": "2015-03-27 16:41:39"
"time": "2015-07-14 16:29:50"
},
{
"name": "seld/cli-prompt",

View File

@ -1,29 +0,0 @@
{
"Autoconf-exception-2.0": [
"Autoconf exception 2.0"
],
"Autoconf-exception-3.0": [
"Autoconf exception 3.0"
],
"Bison-exception-2.2": [
"Bison exception 2.2"
],
"Classpath-exception-2.0": [
"Classpath exception 2.0"
],
"eCos-exception-2.0": [
"eCos exception 2.0"
],
"Font-exception-2.0": [
"Font exception 2.0"
],
"GCC-exception-2.0": [
"GCC Runtime Library exception 2.0"
],
"GCC-exception-3.1": [
"GCC Runtime Library exception 3.1"
],
"WxWindows-exception-3.1": [
"WxWindows Library Exception 3.1"
]
}

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@ use Composer\Repository\CompositeRepository;
use Composer\Repository\ComposerRepository;
use Composer\Repository\PlatformRepository;
use Composer\Repository\RepositoryInterface;
use Composer\Util\SpdxLicense;
use Composer\Spdx\SpdxLicenses;
/**
* @author Robert Schönthal <seroscho@googlemail.com>
@ -390,12 +390,12 @@ EOT
*/
protected function printLicenses(CompletePackageInterface $package)
{
$spdxLicense = new SpdxLicense;
$spdxLicenses = new SpdxLicenses();
$licenses = $package->getLicense();
foreach ($licenses as $licenseId) {
$license = $spdxLicense->getLicenseByIdentifier($licenseId); // keys: 0 fullname, 1 osi, 2 url
$license = $spdxLicenses->getLicenseByIdentifier($licenseId); // keys: 0 fullname, 1 osi, 2 url
if (!$license) {
$out = $licenseId;

View File

@ -13,6 +13,7 @@
namespace Composer;
use Composer\Json\JsonFile;
use Composer\Spdx\SpdxLicenses;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\Process;
use Seld\PharUtils\Timestamps;
@ -95,7 +96,8 @@ class Compiler
$finder = new Finder();
$finder->files()
->name('*.json')
->in(__DIR__ . '/../../res')
->in(__DIR__.'/../../res')
->in(SpdxLicenses::getResourcesDir())
->sort($finderSort)
;
@ -116,6 +118,7 @@ class Compiler
->in(__DIR__.'/../../vendor/seld/jsonlint/')
->in(__DIR__.'/../../vendor/seld/cli-prompt/')
->in(__DIR__.'/../../vendor/justinrainbow/json-schema/')
->in(__DIR__.'/../../vendor/composer/spdx-licenses/')
->sort($finderSort)
;

View File

@ -18,6 +18,7 @@ use Composer\Package\Loader\InvalidPackageException;
use Composer\Json\JsonValidationException;
use Composer\IO\IOInterface;
use Composer\Json\JsonFile;
use Composer\Spdx\SpdxLicenses;
/**
* Validates a composer configuration.
@ -82,7 +83,7 @@ class ConfigValidator
}
}
$licenseValidator = new SpdxLicense();
$licenseValidator = new SpdxLicenses();
if ('proprietary' !== $manifest['license'] && array() !== $manifest['license'] && !$licenseValidator->validate($manifest['license'])) {
$warnings[] = sprintf(
'License %s is not a valid SPDX license identifier, see http://www.spdx.org/licenses/ if you use an open license.'

View File

@ -12,295 +12,13 @@
namespace Composer\Util;
use Composer\Spdx\SpdxLicenses;
@trigger_error('The ' . __NAMESPACE__ . '\SpdxLicense class is deprecated, use Composer\Spdx\SpdxLicenses instead.', E_USER_DEPRECATED);
/**
* Supports composer array and SPDX tag notation for disjunctive/conjunctive
* licenses.
*
* @author Tom Klingenberg <tklingenberg@lastflood.net>
* @deprecated use Composer\Spdx\SpdxLicenses instead
*/
class SpdxLicense
class SpdxLicense extends SpdxLicenses
{
/** @var array */
private $licenses;
/** @var array */
private $exceptions;
public function __construct()
{
$this->loadLicenses();
$this->loadExceptions();
}
/**
* Returns license metadata by license identifier.
*
* @param string $identifier
*
* @return array|null
*/
public function getLicenseByIdentifier($identifier)
{
if (!isset($this->licenses[$identifier])) {
return;
}
$license = $this->licenses[$identifier];
$license[] = 'http://spdx.org/licenses/' . $identifier . '.html#licenseText';
return $license;
}
/**
* Returns license exception metadata by license exception identifier.
*
* @param string $identifier
*
* @return array|null
*/
public function getExceptionByIdentifier($identifier)
{
if (!isset($this->exceptions[$identifier])) {
return;
}
$license = $this->exceptions[$identifier];
$license[] = 'http://spdx.org/licenses/' . $identifier . '.html#licenseExceptionText';
return $license;
}
/**
* Returns the short identifier of a license (exception) by full name.
*
* @param string $name
*
* @return string
*/
public function getIdentifierByName($name)
{
foreach ($this->licenses as $identifier => $licenseData) {
if ($licenseData[0] === $name) { // key 0 = fullname
return $identifier;
}
}
foreach ($this->exceptions as $identifier => $licenseData) {
if ($licenseData[0] === $name) { // key 0 = fullname
return $identifier;
}
}
}
/**
* Returns the OSI Approved status for a license by identifier.
*
* @param string $identifier
*
* @return bool
*/
public function isOsiApprovedByIdentifier($identifier)
{
return $this->licenses[$identifier][1]; // key 1 = osi approved
}
/**
* Check, if the identifier for a license is valid.
*
* @param string $identifier
*
* @return bool
*/
private function isValidLicenseIdentifier($identifier)
{
$identifiers = array_keys($this->licenses);
return in_array($identifier, $identifiers);
}
/**
* Check, if the identifier for a exception is valid.
*
* @param string $identifier
*
* @return bool
*/
private function isValidExceptionIdentifier($identifier)
{
$identifiers = array_keys($this->exceptions);
return in_array($identifier, $identifiers);
}
/**
* @param array|string $license
*
* @return bool
* @throws \InvalidArgumentException
*/
public function validate($license)
{
if (is_array($license)) {
$count = count($license);
if ($count !== count(array_filter($license, 'is_string'))) {
throw new \InvalidArgumentException('Array of strings expected.');
}
$license = $count > 1 ? '('.implode(' OR ', $license).')' : (string) reset($license);
}
if (!is_string($license)) {
throw new \InvalidArgumentException(sprintf(
'Array or String expected, %s given.',
gettype($license)
));
}
return $this->isValidLicenseString($license);
}
/**
* @return array
*/
private function loadLicenses()
{
if (is_array($this->licenses)) {
return $this->licenses;
}
$jsonFile = file_get_contents(__DIR__ . '/../../../res/spdx-licenses.json');
$this->licenses = json_decode($jsonFile, true);
return $this->licenses;
}
/**
* @return array
*/
private function loadExceptions()
{
if (is_array($this->exceptions)) {
return $this->exceptions;
}
$jsonFile = file_get_contents(__DIR__ . '/../../../res/spdx-exceptions.json');
$this->exceptions = json_decode($jsonFile, true);
return $this->exceptions;
}
/**
* @param string $license
*
* @return bool
* @throws \RuntimeException
*/
private function isValidLicenseString($license)
{
$tokens = array(
'po' => '\(',
'pc' => '\)',
'op' => '(?:or|OR|and|AND)',
'wi' => '(?:with|WITH)',
'lix' => '(?:NONE|NOASSERTION)',
'lir' => 'LicenseRef-\d+',
'lic' => '[-_.a-zA-Z0-9]{3,}\+?',
'ws' => '\s+',
'_' => '.',
);
$next = function () use ($license, $tokens) {
static $offset = 0;
if ($offset >= strlen($license)) {
return null;
}
foreach ($tokens as $name => $token) {
if (false === $r = preg_match('{' . $token . '}', $license, $matches, PREG_OFFSET_CAPTURE, $offset)) {
throw new \RuntimeException('Pattern for token %s failed (regex error).', $name);
}
if ($r === 0) {
continue;
}
if ($matches[0][1] !== $offset) {
continue;
}
$offset += strlen($matches[0][0]);
return array($name, $matches[0][0]);
}
throw new \RuntimeException(
'At least the last pattern needs to match, but it did not (dot-match-all is missing?).'
);
};
$open = 0;
$with = false;
$require = true;
$lastop = null;
while (list($token, $string) = $next()) {
switch ($token) {
case 'po':
if ($open || !$require || $with) {
return false;
}
$open = 1;
break;
case 'pc':
if ($open !== 1 || $require || !$lastop || $with) {
return false;
}
$open = 2;
break;
case 'op':
if ($require || !$open || $with) {
return false;
}
$lastop || $lastop = $string;
if ($lastop !== $string) {
return false;
}
$require = true;
break;
case 'wi':
$with = true;
break;
case 'lix':
if ($open || $with) {
return false;
}
goto lir;
case 'lic':
if ($with && $this->isValidExceptionIdentifier($string)) {
$require = true;
$with = false;
goto lir;
}
if ($with) {
return false;
}
if (!$this->isValidLicenseIdentifier(rtrim($string, '+'))) {
return false;
}
// Fall-through intended
case 'lir':
lir:
if (!$require) {
return false;
}
$require = false;
break;
case 'ws':
break;
case '_':
return false;
default:
throw new \RuntimeException(sprintf('Unparsed token: %s.', print_r($token, true)));
}
}
return !($open % 2 || $require || $with);
}
}

View File

@ -1,139 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Util;
/**
* The SPDX Licenses Updater scrapes licenses from the spdx website
* and updates the "res/spdx-licenses.json" file accordingly.
*
* The class is used by the update script "bin/update-spdx-licenses".
*/
class SpdxLicensesUpdater
{
/**
* @param string $file
* @param string $url
*/
public function dumpLicenses($file, $url = 'http://www.spdx.org/licenses/')
{
$options = 0;
if (defined('JSON_PRETTY_PRINT')) {
$options |= JSON_PRETTY_PRINT;
}
if (defined('JSON_UNESCAPED_SLASHES')) {
$options |= JSON_UNESCAPED_SLASHES;
}
$licenses = json_encode($this->getLicenses($url), $options);
file_put_contents($file, $licenses);
}
/**
* @param string $file
* @param string $url
*/
public function dumpExceptions($file, $url = 'http://www.spdx.org/licenses/exceptions-index.html')
{
$options = 0;
if (defined('JSON_PRETTY_PRINT')) {
$options |= JSON_PRETTY_PRINT;
}
if (defined('JSON_UNESCAPED_SLASHES')) {
$options |= JSON_UNESCAPED_SLASHES;
}
$exceptions = json_encode($this->getExceptions($url), $options);
file_put_contents($file, $exceptions);
}
/**
* @param string $url
*
* @return array
*/
private function getLicenses($url)
{
$licenses = array();
$dom = new \DOMDocument;
@$dom->loadHTMLFile($url);
$xPath = new \DOMXPath($dom);
$trs = $xPath->query('//table//tbody//tr');
// iterate over each row in the table
foreach ($trs as $tr) {
$tds = $tr->getElementsByTagName('td'); // get the columns in this row
if ($tds->length !== 4) {
continue;
}
if (trim($tds->item(3)->nodeValue) == 'License Text') {
$fullname = trim($tds->item(0)->nodeValue);
$identifier = trim($tds->item(1)->nodeValue);
$osiApproved = ((isset($tds->item(2)->nodeValue) && $tds->item(2)->nodeValue === 'Y')) ? true : false;
// The license URL is not scraped intentionally to keep json file size low.
// It's build when requested, see SpdxLicense->getLicenseByIdentifier().
//$licenseURL = $tds->item(3)->getAttribute('href');
$licenses += array($identifier => array($fullname, $osiApproved));
}
}
return $licenses;
}
/**
* @param string $url
*
* @return array
*/
private function getExceptions($url)
{
$exceptions = array();
$dom = new \DOMDocument;
@$dom->loadHTMLFile($url);
$xPath = new \DOMXPath($dom);
$trs = $xPath->query('//table//tbody//tr');
// iterate over each row in the table
foreach ($trs as $tr) {
$tds = $tr->getElementsByTagName('td'); // get the columns in this row
if ($tds->length !== 3) {
continue;
}
if (trim($tds->item(2)->nodeValue) == 'License Exception Text') {
$fullname = trim($tds->item(0)->nodeValue);
$identifier = trim($tds->item(1)->nodeValue);
// The license URL is not scraped intentionally to keep json file size low.
// It's build when requested, see SpdxLicense->getLicenseExceptionByIdentifier().
//$licenseURL = $tds->item(2)->getAttribute('href');
$exceptions += array($identifier => array($fullname));
}
}
return $exceptions;
}
}

View File

@ -23,18 +23,18 @@ class ComposerSchemaTest extends \PHPUnit_Framework_TestCase
{
$json = '{ }';
$this->assertEquals(array(
array('property' => '', 'message' => 'the property name is required'),
array('property' => '', 'message' => 'the property description is required'),
array('property' => 'name', 'message' => 'The property name is required'),
array('property' => 'description', 'message' => 'The property description is required'),
), $this->check($json));
$json = '{ "name": "vendor/package" }';
$this->assertEquals(array(
array('property' => '', 'message' => 'the property description is required'),
array('property' => 'description', 'message' => 'The property description is required'),
), $this->check($json));
$json = '{ "description": "generic description" }';
$this->assertEquals(array(
array('property' => '', 'message' => 'the property name is required'),
array('property' => 'name', 'message' => 'The property name is required'),
), $this->check($json));
}
@ -44,7 +44,7 @@ class ComposerSchemaTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(
array(
'property' => 'minimum-stability',
'message' => 'does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$'
'message' => 'Does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$'
),
), $this->check($json), 'empty string');
@ -52,7 +52,7 @@ class ComposerSchemaTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(array(
array(
'property' => 'minimum-stability',
'message' => 'does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$'
'message' => 'Does not match the regex pattern ^dev|alpha|beta|rc|RC|stable$'
),
), $this->check($json), 'dummy');

View File

@ -54,6 +54,9 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase
public function testParseErrorDetectSingleQuotes()
{
if (defined('JSON_PARSER_NOTSTRICT')) {
$this->markTestSkipped('jsonc issue, see https://github.com/remicollet/pecl-json-c/issues/23');
}
$json = '{
\'foo\': "bar"
}';

View File

@ -1,145 +0,0 @@
<?php
namespace Composer\Test\Util;
use Composer\TestCase;
use Composer\Util\SpdxLicense;
class SpdxLicenseTest extends TestCase
{
/**
* @var object
*/
private $license;
public function setUp()
{
$this->license = new SpdxLicense;
}
public static function provideValidLicenses()
{
$json = file_get_contents(__DIR__ . '/../../../../res/spdx-licenses.json');
$licenses = json_decode($json, true);
$identifiers = array_keys($licenses);
$valid = array_merge(
array(
"MIT",
"MIT+",
"NONE",
"NOASSERTION",
"LicenseRef-3",
array("LGPL-2.0", "GPL-3.0+"),
"(LGPL-2.0 or GPL-3.0+)",
"(LGPL-2.0 OR GPL-3.0+)",
"(EUDatagrid and GPL-3.0+)",
"(EUDatagrid AND GPL-3.0+)",
"GPL-2.0 with Autoconf-exception-2.0",
"GPL-2.0 WITH Autoconf-exception-2.0",
"GPL-2.0+ WITH Autoconf-exception-2.0",
),
$identifiers
);
foreach ($valid as &$r) {
$r = array($r);
}
return $valid;
}
public static function provideInvalidLicenses()
{
return array(
array(""),
array(array()),
array("The system pwns you"),
array("()"),
array("(MIT)"),
array("(MIT"),
array("MIT)"),
array("MIT NONE"),
array("MIT AND NONE"),
array("MIT (MIT and MIT)"),
array("(MIT and MIT) MIT"),
array(array("LGPL-2.0", "The system pwns you")),
array("and GPL-3.0+"),
array("EUDatagrid and GPL-3.0+"),
array("(GPL-3.0 and GPL-2.0 or GPL-3.0+)"),
array("(EUDatagrid and GPL-3.0+ and )"),
array("(EUDatagrid xor GPL-3.0+)"),
array("(MIT Or MIT)"),
array("(NONE or MIT)"),
array("(NOASSERTION or MIT)"),
array("Autoconf-exception-2.0 WITH MIT"),
array("MIT WITH"),
array("MIT OR"),
array("MIT AND"),
);
}
public static function provideInvalidArgument()
{
return array(
array(null),
array(new \stdClass),
array(array(new \stdClass)),
array(array("mixed", new \stdClass)),
array(array(new \stdClass, new \stdClass)),
);
}
/**
* @dataProvider provideValidLicenses
* @param $license
*/
public function testValidate($license)
{
$this->assertTrue($this->license->validate($license));
}
/**
* @dataProvider provideInvalidLicenses
* @param string|array $invalidLicense
*/
public function testInvalidLicenses($invalidLicense)
{
$this->assertFalse($this->license->validate($invalidLicense));
}
/**
* @dataProvider provideInvalidArgument
* @expectedException InvalidArgumentException
*/
public function testInvalidArgument($invalidArgument)
{
$this->license->validate($invalidArgument);
}
public function testGetLicenseByIdentifier()
{
$license = $this->license->getLicenseByIdentifier('AGPL-1.0');
$this->assertEquals($license[0], 'Affero General Public License v1.0'); // fullname
$this->assertFalse($license[1]); // osi approved
}
public function testGetIdentifierByName()
{
$identifier = $this->license->getIdentifierByName('Affero General Public License v1.0');
$this->assertEquals($identifier, 'AGPL-1.0');
$identifier = $this->license->getIdentifierByName('BSD 2-clause "Simplified" License');
$this->assertEquals($identifier, 'BSD-2-Clause');
}
public function testIsOsiApprovedByIdentifier()
{
$osiApproved = $this->license->isOsiApprovedByIdentifier('MIT');
$this->assertTrue($osiApproved);
$osiApproved = $this->license->isOsiApprovedByIdentifier('AGPL-1.0');
$this->assertFalse($osiApproved);
}
}