Use of SPDX license identifiers.
parent
e7dc42a8a2
commit
74ca58bcb6
|
@ -0,0 +1,85 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$identifiers = new SPDXLicenseIdentifiersOnline;
|
||||||
|
$printer = new JsonPrinter;
|
||||||
|
$printer->printStringArray($identifiers->getStrings());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPDX Identifier List from the registry.
|
||||||
|
*/
|
||||||
|
class SPDXLicenseIdentifiersOnline
|
||||||
|
{
|
||||||
|
const REGISTRY = 'http://www.spdx.org/licenses/';
|
||||||
|
const EXPRESSION = '//*[@typeof="spdx:License"]/code[@property="spdx:licenseId"]/text()';
|
||||||
|
|
||||||
|
private $identifiers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
public function getStrings()
|
||||||
|
{
|
||||||
|
if ($this->identifiers) {
|
||||||
|
return $this->identifiers;
|
||||||
|
}
|
||||||
|
$this->identifiers = $this->importNodesFromURL(
|
||||||
|
self::REGISTRY,
|
||||||
|
self::EXPRESSION
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->identifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function importNodesFromURL($url, $expressionTextNodes)
|
||||||
|
{
|
||||||
|
$doc = new DOMDocument();
|
||||||
|
$doc->loadHTMLFile($url);
|
||||||
|
$xp = new DOMXPath($doc);
|
||||||
|
$codes = $xp->query($expressionTextNodes);
|
||||||
|
if (!$codes) {
|
||||||
|
throw new \Exception(sprintf('XPath query failed: %s', $expressionTextNodes));
|
||||||
|
}
|
||||||
|
if ($codes->length < 20) {
|
||||||
|
throw new \Exception('Obtaining the license table failed, there can not be less than 20 identifiers.');
|
||||||
|
}
|
||||||
|
$identifiers = array();
|
||||||
|
foreach ($codes as $code) {
|
||||||
|
$identifiers[] = $code->nodeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $identifiers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Print an array the way this script needs it.
|
||||||
|
*/
|
||||||
|
class JsonPrinter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param string[] $array
|
||||||
|
*/
|
||||||
|
public function printStringArray(array $array)
|
||||||
|
{
|
||||||
|
$lines = array('');
|
||||||
|
$line = &$lines[0];
|
||||||
|
$last = count($array) - 1;
|
||||||
|
foreach ($array as $item => $code) {
|
||||||
|
$code = sprintf('"%s"%s', $code, $item === $last ? '' : ', ');
|
||||||
|
$length = strlen($line) + strlen($code) - 1;
|
||||||
|
if ($length > 76) {
|
||||||
|
$line = rtrim($line);
|
||||||
|
unset($line);
|
||||||
|
$lines[] = $code;
|
||||||
|
$line = &$lines[count($lines) - 1];
|
||||||
|
} else {
|
||||||
|
$line .= $code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$json = sprintf("[%s]", implode("\n ", $lines));
|
||||||
|
$json = str_replace(array("[\"", "\"]"), array("[\n \"", "\"\n]"), $json);
|
||||||
|
echo $json;
|
||||||
|
}
|
||||||
|
}
|
|
@ -121,20 +121,52 @@ Optional.
|
||||||
|
|
||||||
The license of the package. This can be either a string or an array of strings.
|
The license of the package. This can be either a string or an array of strings.
|
||||||
|
|
||||||
The recommended notation for the most common licenses is:
|
The recommended notation for the most common licenses is (alphabetical):
|
||||||
|
|
||||||
|
Apache-2.0
|
||||||
|
BSD-2-Clause
|
||||||
|
BSD-3-Clause
|
||||||
|
BSD-4-Clause
|
||||||
|
GPL-2.0
|
||||||
|
GPL-2.0+
|
||||||
|
GPL-3.0
|
||||||
|
GPL-3.0+
|
||||||
|
LGPL-2.0
|
||||||
|
LGPL-2.0+
|
||||||
|
LGPL-3.0
|
||||||
|
LGPL-3.0+
|
||||||
MIT
|
MIT
|
||||||
BSD-2
|
|
||||||
BSD-3
|
|
||||||
BSD-4
|
|
||||||
GPLv2
|
|
||||||
GPLv3
|
|
||||||
LGPLv2
|
|
||||||
LGPLv3
|
|
||||||
Apache2
|
|
||||||
WTFPL
|
|
||||||
|
|
||||||
Optional, but it is highly recommended to supply this.
|
Optional, but it is highly recommended to supply this. More identifiers are
|
||||||
|
listed at the [SPDX Open Source License Registry](http://www.spdx.org/licenses/).
|
||||||
|
|
||||||
|
An Example:
|
||||||
|
|
||||||
|
{
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
For a package, when there is a choice between licenses (“disjunctive license”),
|
||||||
|
multiple can be specified as array.
|
||||||
|
|
||||||
|
An Example for disjunctive licenses:
|
||||||
|
|
||||||
|
{
|
||||||
|
"license": [
|
||||||
|
"LGPL-2.0",
|
||||||
|
"GPL-3.0+"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Alternatively they can be separated with “or” and enclosed in brackets;
|
||||||
|
|
||||||
|
{
|
||||||
|
"license": "(LGPL-2.0 or GPL-3.0+)"
|
||||||
|
}
|
||||||
|
|
||||||
|
Similarly when multiple licenses need to be applied (“conjunctive license”),
|
||||||
|
they should be separated with “and” and enclosed in brackets.
|
||||||
|
|
||||||
### authors
|
### authors
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
[
|
||||||
|
"AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0", "APL-1.0",
|
||||||
|
"ANTLR-PD", "Apache-1.0", "Apache-1.1", "Apache-2.0", "APSL-1.0",
|
||||||
|
"APSL-1.1", "APSL-1.2", "APSL-2.0", "Artistic-1.0", "Artistic-2.0", "AAL",
|
||||||
|
"BSL-1.0", "BSD-2-Clause", "BSD-2-Clause-NetBSD", "BSD-2-Clause-FreeBSD",
|
||||||
|
"BSD-3-Clause", "BSD-4-Clause", "BSD-4-Clause-UC", "CECILL-1.0",
|
||||||
|
"CECILL-1.1", "CECILL-2.0", "CECILL-B", "CECILL-C", "ClArtistic",
|
||||||
|
"CNRI-Python-GPL-Compatible", "CNRI-Python", "CDDL-1.0", "CDDL-1.1",
|
||||||
|
"CPAL-1.0", "CPL-1.0", "CATOSL-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5",
|
||||||
|
"CC-BY-3.0", "CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0",
|
||||||
|
"CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5", "CC-BY-NC-3.0",
|
||||||
|
"CC-BY-NC-ND-1.0", "CC-BY-NC-ND-2.0", "CC-BY-NC-ND-2.5", "CC-BY-NC-ND-3.0",
|
||||||
|
"CC-BY-NC-SA-1.0", "CC-BY-NC-SA-2.0", "CC-BY-NC-SA-2.5", "CC-BY-NC-SA-3.0",
|
||||||
|
"CC-BY-SA-1.0", "CC-BY-SA-2.0", "CC-BY-SA-2.5", "CC-BY-SA-3.0", "CC0-1.0",
|
||||||
|
"CUA-OPL-1.0", "EPL-1.0", "eCos-2.0", "ECL-1.0", "ECL-2.0", "EFL-1.0",
|
||||||
|
"EFL-2.0", "Entessa", "ErlPL-1.1", "EUDatagrid", "EUPL-1.0", "EUPL-1.1",
|
||||||
|
"Fair", "Frameworx-1.0", "AGPL-3.0", "GFDL-1.1", "GFDL-1.2", "GFDL-1.3",
|
||||||
|
"GPL-1.0", "GPL-1.0+", "GPL-2.0", "GPL-2.0+",
|
||||||
|
"GPL-2.0-with-autoconf-exception", "GPL-2.0-with-bison-exception",
|
||||||
|
"GPL-2.0-with-classpath-exception", "GPL-2.0-with-font-exception",
|
||||||
|
"GPL-2.0-with-GCC-exception", "GPL-3.0", "GPL-3.0+",
|
||||||
|
"GPL-3.0-with-autoconf-exception", "GPL-3.0-with-GCC-exception", "LGPL-2.1",
|
||||||
|
"LGPL-2.1+", "LGPL-3.0", "LGPL-3.0+", "LGPL-2.0", "LGPL-2.0+", "gSOAP-1.3b",
|
||||||
|
"HPND", "IPL-1.0", "IPA", "ISC", "LPPL-1.0", "LPPL-1.1", "LPPL-1.2",
|
||||||
|
"LPPL-1.3c", "Libpng", "LPL-1.0", "LPL-1.02", "MS-PL", "MS-RL", "MirOS",
|
||||||
|
"MIT", "Motosoto", "MPL-1.0", "MPL-1.1", "MPL-2.0", "Multics", "NASA-1.3",
|
||||||
|
"Naumen", "NGPL", "Nokia", "NPOSL-3.0", "NTP", "OCLC-2.0", "ODbL-1.0",
|
||||||
|
"PDDL-1.0", "OGTSL", "OSL-1.0", "OSL-2.0", "OSL-2.1", "OSL-3.0",
|
||||||
|
"OLDAP-2.8", "OpenSSL", "PHP-3.0", "PHP-3.01", "PostgreSQL", "Python-2.0",
|
||||||
|
"QPL-1.0", "RPSL-1.0", "RPL-1.5", "RHeCos-1.1", "RSCPL", "Ruby", "SAX-PD",
|
||||||
|
"OFL-1.0", "OFL-1.1", "SimPL-2.0", "Sleepycat", "SugarCRM-1.1.3", "SPL-1.0",
|
||||||
|
"Watcom-1.0", "NCSA", "VSL-1.0", "W3C", "WXwindows", "Xnet", "XFree86-1.1",
|
||||||
|
"YPL-1.0", "YPL-1.1", "Zimbra-1.3", "Zlib", "ZPL-1.1", "ZPL-2.0", "ZPL-2.1"
|
||||||
|
]
|
|
@ -18,67 +18,97 @@ use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
use Composer\Json\JsonValidationException;
|
use Composer\Json\JsonValidationException;
|
||||||
use Composer\Util\RemoteFilesystem;
|
use Composer\Util\RemoteFilesystem;
|
||||||
|
use Composer\Util\SPDXLicenseIdentifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* ValidateCommand
|
||||||
|
*
|
||||||
* @author Robert Schönthal <seroscho@googlemail.com>
|
* @author Robert Schönthal <seroscho@googlemail.com>
|
||||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||||
*/
|
*/
|
||||||
class ValidateCommand extends Command
|
class ValidateCommand extends Command
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* configure
|
||||||
|
*/
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this
|
$this
|
||||||
->setName('validate')
|
->setName('validate')
|
||||||
->setDescription('Validates a composer.json')
|
->setDescription('Validates a composer.json')
|
||||||
->setDefinition(array(
|
->setDefinition(array(
|
||||||
new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file', './composer.json')
|
new InputArgument('file', InputArgument::OPTIONAL, 'path to composer.json file', './composer.json')
|
||||||
))
|
))
|
||||||
->setHelp(<<<EOT
|
->setHelp(<<<EOT
|
||||||
The validate command validates a given composer.json
|
The validate command validates a given composer.json
|
||||||
|
|
||||||
EOT
|
EOT
|
||||||
)
|
);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||||
|
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
{
|
{
|
||||||
$file = $input->getArgument('file');
|
$file = $input->getArgument('file');
|
||||||
|
|
||||||
if (!file_exists($file)) {
|
if (!file_exists($file)) {
|
||||||
$output->writeln('<error>'.$file.' not found.</error>');
|
$output->writeln('<error>' . $file . ' not found.</error>');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (!is_readable($file)) {
|
if (!is_readable($file)) {
|
||||||
$output->writeln('<error>'.$file.' is not readable.</error>');
|
$output->writeln('<error>' . $file . ' is not readable.</error>');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$laxValid = false;
|
$laxValid = false;
|
||||||
try {
|
try {
|
||||||
$json = new JsonFile($file, new RemoteFilesystem($this->getIO()));
|
$json = new JsonFile($file, new RemoteFilesystem($this->getIO()));
|
||||||
$json->read();
|
$manifest = $json->read();
|
||||||
|
|
||||||
$json->validateSchema(JsonFile::LAX_SCHEMA);
|
$json->validateSchema(JsonFile::LAX_SCHEMA);
|
||||||
$laxValid = true;
|
$laxValid = true;
|
||||||
$json->validateSchema();
|
$json->validateSchema();
|
||||||
} catch (JsonValidationException $e) {
|
} catch (JsonValidationException $e) {
|
||||||
if ($laxValid) {
|
if ($laxValid) {
|
||||||
$output->writeln('<info>'.$file.' is valid for simple usage with composer but has</info>');
|
$output->writeln('<info>' . $file . ' is valid for simple usage with composer but has</info>');
|
||||||
$output->writeln('<info>strict errors that make it unable to be published as a package:</info>');
|
$output->writeln('<info>strict errors that make it unable to be published as a package:</info>');
|
||||||
} else {
|
} else {
|
||||||
$output->writeln('<error>'.$file.' is invalid, the following errors were found:</error>');
|
$output->writeln('<error>' . $file . ' is invalid, the following errors were found:</error>');
|
||||||
}
|
}
|
||||||
foreach ($e->getErrors() as $message) {
|
foreach ($e->getErrors() as $message) {
|
||||||
$output->writeln('<error>'.$message.'</error>');
|
$output->writeln('<error>' . $message . '</error>');
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$output->writeln('<error>'.$file.' contains a JSON Syntax Error:</error>');
|
$output->writeln('<error>' . $file . ' contains a JSON Syntax Error:</error>');
|
||||||
$output->writeln('<error>'.$e->getMessage().'</error>');
|
$output->writeln('<error>' . $e->getMessage() . '</error>');
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
$output->writeln('<info>'.$file.' is valid</info>');
|
if (isset($manifest['license'])) {
|
||||||
|
try {
|
||||||
|
$identifier = new SPDXLicenseIdentifier($manifest['license']);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
$output->writeln(sprintf(
|
||||||
|
'<warning>License "%s" is not a SPDX license identifier.</warning>',
|
||||||
|
print_r($manifest['license'], true)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$output->writeln('<warning>No license specified.</warning>');
|
||||||
|
}
|
||||||
|
|
||||||
|
$output->writeln('<info>' . $file . ' is valid</info>');
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,9 +63,18 @@ class Compiler
|
||||||
foreach ($finder as $file) {
|
foreach ($finder as $file) {
|
||||||
$this->addFile($phar, $file);
|
$this->addFile($phar, $file);
|
||||||
}
|
}
|
||||||
$this->addFile($phar, new \SplFileInfo(__DIR__.'/Autoload/ClassLoader.php'), false);
|
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/Autoload/ClassLoader.php'), false);
|
||||||
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../res/composer-schema.json'), false);
|
|
||||||
$this->addFile($phar, new \SplFileInfo(__DIR__.'/../../src/Composer/IO/hiddeninput.exe'), false);
|
$finder = new Finder();
|
||||||
|
$finder->files()
|
||||||
|
->name('*.json')
|
||||||
|
->in(__DIR__ . '/../../res')
|
||||||
|
;
|
||||||
|
|
||||||
|
foreach ($finder as $file) {
|
||||||
|
$this->addFile($phar, $file, false);
|
||||||
|
}
|
||||||
|
$this->addFile($phar, new \SplFileInfo(__DIR__ . '/../../src/Composer/IO/hiddeninput.exe'), false);
|
||||||
|
|
||||||
$finder = new Finder();
|
$finder = new Finder();
|
||||||
$finder->files()
|
$finder->files()
|
||||||
|
|
|
@ -0,0 +1,228 @@
|
||||||
|
<?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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPDX License Identifier
|
||||||
|
*
|
||||||
|
* Supports composer array and SPDX tag notation for disjunctive/conjunctive
|
||||||
|
* licenses.
|
||||||
|
*
|
||||||
|
* @author Tom Klingenberg <tklingenberg@lastflood.net>
|
||||||
|
*/
|
||||||
|
class SPDXLicenseIdentifier
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $identifiers;
|
||||||
|
/**
|
||||||
|
* @var array|string
|
||||||
|
*/
|
||||||
|
private $license;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string|string[] $license
|
||||||
|
*/
|
||||||
|
public function __construct($license)
|
||||||
|
{
|
||||||
|
$this->initIdentifiers();
|
||||||
|
$this->setLicense($license);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->getLicense();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLicense()
|
||||||
|
{
|
||||||
|
return $this->license;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array|string $license
|
||||||
|
*
|
||||||
|
* @throws \InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function setLicense($license)
|
||||||
|
{
|
||||||
|
if (is_array($license)) {
|
||||||
|
$license = $this->getLicenseFromArray($license);
|
||||||
|
}
|
||||||
|
if (!is_string($license)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf(
|
||||||
|
'Array or String expected, %s given.', gettype($license)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if (!$this->isValidLicenseString($license)) {
|
||||||
|
throw new \InvalidArgumentException(sprintf(
|
||||||
|
'Invalid license: "%s"', $license
|
||||||
|
));
|
||||||
|
}
|
||||||
|
$this->license = $license;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $licenses
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getLicenseFromArray(array $licenses)
|
||||||
|
{
|
||||||
|
$buffer = '';
|
||||||
|
foreach ($licenses as $license) {
|
||||||
|
$buffer .= ($buffer ? ' or ' : '(') . (string)$license;
|
||||||
|
}
|
||||||
|
$buffer .= $buffer ? ')' : '';
|
||||||
|
|
||||||
|
return $buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init SPDX identifiers
|
||||||
|
*/
|
||||||
|
private function initIdentifiers()
|
||||||
|
{
|
||||||
|
$jsonFile = __DIR__ . '/../../../res/spdx-identifier.json';
|
||||||
|
$this->identifiers = $this->arrayFromJSONFile($jsonFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $file
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
private function arrayFromJSONFile($file)
|
||||||
|
{
|
||||||
|
$data = json_decode(file_get_contents($file));
|
||||||
|
if (!$data || !is_array($data)) {
|
||||||
|
throw new \RuntimeException(sprintf('Not a json array in file "%s"', $file));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $identifier
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
private function isValidLicenseIdentifier($identifier)
|
||||||
|
{
|
||||||
|
return in_array($identifier, $this->identifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $license
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
private function isValidLicenseString($license)
|
||||||
|
{
|
||||||
|
$tokens = array(
|
||||||
|
'po' => '\(',
|
||||||
|
'pc' => '\)',
|
||||||
|
'op' => '(?:or|and)',
|
||||||
|
'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;
|
||||||
|
$require = 1;
|
||||||
|
$lastop = null;
|
||||||
|
while (list ($token, $string) = $next()) {
|
||||||
|
switch ($token) {
|
||||||
|
case 'po':
|
||||||
|
if ($open || !$require) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$open = 1;
|
||||||
|
break;
|
||||||
|
case 'pc':
|
||||||
|
if ($open !== 1 || $require || !$lastop) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$open = 2;
|
||||||
|
break;
|
||||||
|
case 'op':
|
||||||
|
if ($require || !$open) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$lastop || $lastop = $string;
|
||||||
|
if ($lastop !== $string) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$require = 1;
|
||||||
|
break;
|
||||||
|
case 'lix':
|
||||||
|
if ($open) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
goto lir;
|
||||||
|
case 'lic':
|
||||||
|
if (!$this->isValidLicenseIdentifier($string)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Fall-through intended
|
||||||
|
case 'lir':
|
||||||
|
lir:
|
||||||
|
if (!$require) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$require = 0;
|
||||||
|
break;
|
||||||
|
case 'ws':
|
||||||
|
break;
|
||||||
|
case '_':
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
throw new \RuntimeException(sprintf('Unparsed token: %s.', print_r($token, true)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !($open % 2 || $require);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
namespace Composer\Test\Util;
|
||||||
|
|
||||||
|
use Composer\Test\TestCase;
|
||||||
|
use Composer\Util\SPDXLicenseIdentifier;
|
||||||
|
|
||||||
|
class SPDXLicenseIdentifierTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
public static function provideValidLicenses()
|
||||||
|
{
|
||||||
|
$valid = array_merge(
|
||||||
|
array(
|
||||||
|
"MIT",
|
||||||
|
"NONE",
|
||||||
|
"NOASSERTION",
|
||||||
|
"LicenseRef-3",
|
||||||
|
array("LGPL-2.0", "GPL-3.0+"),
|
||||||
|
"(LGPL-2.0 or GPL-3.0+)",
|
||||||
|
"(EUDatagrid and GPL-3.0+)",
|
||||||
|
),
|
||||||
|
json_decode(file_get_contents(__DIR__ . '/../../../../res/spdx-identifier.json'))
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($valid as &$r) {
|
||||||
|
$r = array($r);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function provideInvalidLicenses()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array(NULL),
|
||||||
|
array(""),
|
||||||
|
array("The system pwns you"),
|
||||||
|
array("()"),
|
||||||
|
array("(MIT)"),
|
||||||
|
array("MIT 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)"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideValidLicenses
|
||||||
|
* @param $license
|
||||||
|
*/
|
||||||
|
public function testConstructor($license)
|
||||||
|
{
|
||||||
|
$identifier = new SPDXLicenseIdentifier($license);
|
||||||
|
$this->assertInstanceOf('Composer\Util\SPDXLicenseIdentifier', $identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideInvalidLicenses
|
||||||
|
* @expectedException InvalidArgumentException
|
||||||
|
* @param string|array $invalidLicense
|
||||||
|
*/
|
||||||
|
public function testInvalidLicenses($invalidLicense)
|
||||||
|
{
|
||||||
|
$identifier = new SPDXLicenseIdentifier($invalidLicense);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetLicense()
|
||||||
|
{
|
||||||
|
$license = new SPDXLicenseIdentifier('NONE');
|
||||||
|
$string = $license->getLicense();
|
||||||
|
$this->assertInternalType('string', $string);
|
||||||
|
$string = (string)$license;
|
||||||
|
$this->assertInternalType('string', $string);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue