From 74a077dd3dd59d5e382ef72a5dbd331d3d06e6fc Mon Sep 17 00:00:00 2001 From: jakoch Date: Sun, 29 Mar 2015 22:46:38 +0200 Subject: [PATCH] updated spdx-license handling to include metadata issue https://github.com/composer/composer/issues/3744 summary of changes - replaced bin script "fetch-spdx-identifiers" by "update-spdx-licenses" - "update-spdx-licenses" uses "Composer/Util/SpdxLicensesUpdater" to update "spdx-licenses.json" file with license identifier, fullname and osi-approved-status - dropped "spdx-identifiers.json" (identifiers only) - dropped "SpdxLicenseIdentifier", it's just "SpdxLicense" now - modified "ShowCommand" to output the license with metadata and removed some unused method arguments (cleanup) --- bin/fetch-spdx-identifiers | 85 -- bin/update-spdx-licenses | 9 + res/spdx-identifier.json | 59 - res/spdx-licenses.json | 1226 +++++++++++++++++ src/Composer/Command/ShowCommand.php | 50 +- src/Composer/Util/ConfigValidator.php | 2 +- ...xLicenseIdentifier.php => SpdxLicense.php} | 407 +++--- src/Composer/Util/SpdxLicensesUpdater.php | 67 + ...IdentifierTest.php => SpdxLicenseTest.php} | 56 +- 9 files changed, 1616 insertions(+), 345 deletions(-) delete mode 100755 bin/fetch-spdx-identifiers create mode 100644 bin/update-spdx-licenses delete mode 100644 res/spdx-identifier.json create mode 100644 res/spdx-licenses.json rename src/Composer/Util/{SpdxLicenseIdentifier.php => SpdxLicense.php} (71%) create mode 100644 src/Composer/Util/SpdxLicensesUpdater.php rename tests/Composer/Test/Util/{SpdxLicenseIdentifierTest.php => SpdxLicenseTest.php} (57%) diff --git a/bin/fetch-spdx-identifiers b/bin/fetch-spdx-identifiers deleted file mode 100755 index d519913c1..000000000 --- a/bin/fetch-spdx-identifiers +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env php -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 array - */ - 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 array $array - */ - public function printStringArray(array $array) - { - $lines = array(''); - $line = &$lines[0]; - $last = count($array) - 1; - foreach ($array as $item => $code) { - $code = sprintf('"%s"%s', trim($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; - } -} \ No newline at end of file diff --git a/bin/update-spdx-licenses b/bin/update-spdx-licenses new file mode 100644 index 000000000..99e9a0268 --- /dev/null +++ b/bin/update-spdx-licenses @@ -0,0 +1,9 @@ +#!/usr/bin/env php +update(); \ No newline at end of file diff --git a/res/spdx-identifier.json b/res/spdx-identifier.json deleted file mode 100644 index b6d8dbc1f..000000000 --- a/res/spdx-identifier.json +++ /dev/null @@ -1,59 +0,0 @@ -[ - "Glide", "Abstyles", "AFL-1.1", "AFL-1.2", "AFL-2.0", "AFL-2.1", "AFL-3.0", - "AMPAS", "APL-1.0", "Adobe-Glyph", "APAFML", "Adobe-2006", "AGPL-1.0", - "Afmparse", "Aladdin", "ADSL", "AMDPLPA", "ANTLR-PD", "Apache-1.0", - "Apache-1.1", "Apache-2.0", "AML", "APSL-1.0", "APSL-1.1", "APSL-1.2", - "APSL-2.0", "Artistic-1.0", "Artistic-1.0-Perl", "Artistic-1.0-cl8", - "Artistic-2.0", "AAL", "Bahyph", "Barr", "Beerware", "BitTorrent-1.0", - "BitTorrent-1.1", "BSL-1.0", "Borceux", "BSD-2-Clause", - "BSD-2-Clause-FreeBSD", "BSD-2-Clause-NetBSD", "BSD-3-Clause", - "BSD-3-Clause-Clear", "BSD-4-Clause", "BSD-Protection", - "BSD-3-Clause-Attribution", "BSD-4-Clause-UC", "bzip2-1.0.5", "bzip2-1.0.6", - "Caldera", "CECILL-1.0", "CECILL-1.1", "CECILL-2.0", "CECILL-B", "CECILL-C", - "ClArtistic", "MIT-CMU", "CNRI-Python", "CNRI-Python-GPL-Compatible", - "CPOL-1.02", "CDDL-1.0", "CDDL-1.1", "CPAL-1.0", "CPL-1.0", "CATOSL-1.1", - "Condor-1.1", "CC-BY-1.0", "CC-BY-2.0", "CC-BY-2.5", "CC-BY-3.0", - "CC-BY-4.0", "CC-BY-ND-1.0", "CC-BY-ND-2.0", "CC-BY-ND-2.5", "CC-BY-ND-3.0", - "CC-BY-ND-4.0", "CC-BY-NC-1.0", "CC-BY-NC-2.0", "CC-BY-NC-2.5", - "CC-BY-NC-3.0", "CC-BY-NC-4.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-ND-4.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-NC-SA-4.0", - "CC-BY-SA-1.0", "CC-BY-SA-2.0", "CC-BY-SA-2.5", "CC-BY-SA-3.0", - "CC-BY-SA-4.0", "CC0-1.0", "Crossword", "CUA-OPL-1.0", "Cube", "D-FSL-1.0", - "diffmark", "WTFPL", "DOC", "Dotseqn", "DSDP", "dvipdfm", "EPL-1.0", - "eCos-2.0", "ECL-1.0", "ECL-2.0", "eGenix", "EFL-1.0", "EFL-2.0", - "MIT-advertising", "MIT-enna", "Entessa", "ErlPL-1.1", "EUDatagrid", - "EUPL-1.0", "EUPL-1.1", "Eurosym", "Fair", "MIT-feh", "Frameworx-1.0", - "FTL", "FSFUL", "FSFULLR", "Giftware", "GL2PS", "Glulxe", "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+", - "gnuplot", "gSOAP-1.3b", "HaskellReport", "HPND", "IBM-pibs", "IPL-1.0", - "ImageMagick", "iMatix", "Imlib2", "IJG", "Intel-ACPI", "Intel", "IPA", - "ISC", "JasPer-2.0", "JSON", "LPPL-1.3a", "LPPL-1.0", "LPPL-1.1", - "LPPL-1.2", "LPPL-1.3c", "Latex2e", "BSD-3-Clause-LBNL", "Leptonica", - "Libpng", "libtiff", "LPL-1.02", "LPL-1.0", "MakeIndex", "MTLL", "MS-PL", - "MS-RL", "MirOS", "MITNFA", "MIT", "Motosoto", "MPL-1.0", "MPL-1.1", - "MPL-2.0", "MPL-2.0-no-copyleft-exception", "mpich2", "Multics", "Mup", - "NASA-1.3", "Naumen", "NBPL-1.0", "NetCDF", "NGPL", "NOSL", "NPL-1.0", - "NPL-1.1", "Newsletr", "NLPL", "Nokia", "NPOSL-3.0", "Noweb", "NRL", "NTP", - "Nunit", "OCLC-2.0", "ODbL-1.0", "PDDL-1.0", "OGTSL", "OLDAP-2.2.2", - "OLDAP-1.1", "OLDAP-1.2", "OLDAP-1.3", "OLDAP-1.4", "OLDAP-2.0", - "OLDAP-2.0.1", "OLDAP-2.1", "OLDAP-2.2", "OLDAP-2.2.1", "OLDAP-2.3", - "OLDAP-2.4", "OLDAP-2.5", "OLDAP-2.6", "OLDAP-2.7", "OML", "OPL-1.0", - "OSL-1.0", "OSL-1.1", "OSL-2.0", "OSL-2.1", "OSL-3.0", "OLDAP-2.8", - "OpenSSL", "PHP-3.0", "PHP-3.01", "Plexus", "PostgreSQL", "psfrag", - "psutils", "Python-2.0", "QPL-1.0", "Qhull", "Rdisc", "RPSL-1.0", "RPL-1.1", - "RPL-1.5", "RHeCos-1.1", "RSCPL", "Ruby", "SAX-PD", "Saxpath", "SCEA", - "SWL", "SGI-B-1.0", "SGI-B-1.1", "SGI-B-2.0", "OFL-1.0", "OFL-1.1", - "SimPL-2.0", "Sleepycat", "SNIA", "SMLNJ", "StandardML-NJ", - "SugarCRM-1.1.3", "SISSL", "SISSL-1.2", "SPL-1.0", "Watcom-1.0", "TCL", - "Unlicense", "TMate", "TORQUE-1.1", "TOSL", "Unicode-TOU", "NCSA", "Vim", - "VOSTROM", "VSL-1.0", "W3C", "Wsuipa", "WXwindows", "Xnet", "X11", "Xerox", - "XFree86-1.1", "xinetd", "xpp", "XSkat", "YPL-1.0", "YPL-1.1", "Zed", - "Zend-2.0", "Zimbra-1.3", "Zlib", "zlib-acknowledgement", "ZPL-1.1", - "ZPL-2.0", "ZPL-2.1" -] diff --git a/res/spdx-licenses.json b/res/spdx-licenses.json new file mode 100644 index 000000000..3e1d93c35 --- /dev/null +++ b/res/spdx-licenses.json @@ -0,0 +1,1226 @@ +{ + "Glide": [ + "3dfx Glide License", + false + ], + "Abstyles": [ + "Abstyles License", + false + ], + "AFL-1.1": [ + "Academic Free License v1.1", + true + ], + "AFL-1.2": [ + "Academic Free License v1.2", + true + ], + "AFL-2.0": [ + "Academic Free License v2.0", + true + ], + "AFL-2.1": [ + "Academic Free License v2.1", + true + ], + "AFL-3.0": [ + "Academic Free License v3.0", + true + ], + "AMPAS": [ + "Academy of Motion Picture Arts and Sciences BSD", + false + ], + "APL-1.0": [ + "Adaptive Public License 1.0", + true + ], + "Adobe-Glyph": [ + "Adobe Glyph List License", + false + ], + "APAFML": [ + "Adobe Postscript AFM License", + false + ], + "Adobe-2006": [ + "Adobe Systems Incorporated Source Code License Agreement", + false + ], + "AGPL-1.0": [ + "Affero General Public License v1.0", + false + ], + "Afmparse": [ + "Afmparse License", + false + ], + "Aladdin": [ + "Aladdin Free Public License", + false + ], + "ADSL": [ + "Amazon Digital Services License", + false + ], + "AMDPLPA": [ + "AMD's plpa_map.c License", + false + ], + "ANTLR-PD": [ + "ANTLR Software Rights Notice", + false + ], + "Apache-1.0": [ + "Apache License 1.0", + false + ], + "Apache-1.1": [ + "Apache License 1.1", + true + ], + "Apache-2.0": [ + "Apache License 2.0", + true + ], + "AML": [ + "Apple MIT License", + false + ], + "APSL-1.0": [ + "Apple Public Source License 1.0", + true + ], + "APSL-1.1": [ + "Apple Public Source License 1.1", + true + ], + "APSL-1.2": [ + "Apple Public Source License 1.2", + true + ], + "APSL-2.0": [ + "Apple Public Source License 2.0", + true + ], + "Artistic-1.0": [ + "Artistic License 1.0", + true + ], + "Artistic-1.0-Perl": [ + "Artistic License 1.0 (Perl)", + true + ], + "Artistic-1.0-cl8": [ + "Artistic License 1.0 w/clause 8", + true + ], + "Artistic-2.0": [ + "Artistic License 2.0", + true + ], + "AAL": [ + "Attribution Assurance License", + true + ], + "Bahyph": [ + "Bahyph License", + false + ], + "Barr": [ + "Barr License", + false + ], + "Beerware": [ + "Beerware License", + false + ], + "BitTorrent-1.0": [ + "BitTorrent Open Source License v1.0", + false + ], + "BitTorrent-1.1": [ + "BitTorrent Open Source License v1.1", + false + ], + "BSL-1.0": [ + "Boost Software License 1.0", + true + ], + "Borceux": [ + "Borceux license", + false + ], + "BSD-2-Clause": [ + "BSD 2-clause \"Simplified\" License", + true + ], + "BSD-2-Clause-FreeBSD": [ + "BSD 2-clause FreeBSD License", + false + ], + "BSD-2-Clause-NetBSD": [ + "BSD 2-clause NetBSD License", + false + ], + "BSD-3-Clause": [ + "BSD 3-clause \"New\" or \"Revised\" License", + true + ], + "BSD-3-Clause-Clear": [ + "BSD 3-clause Clear License", + false + ], + "BSD-4-Clause": [ + "BSD 4-clause \"Original\" or \"Old\" License", + false + ], + "BSD-Protection": [ + "BSD Protection License", + false + ], + "BSD-3-Clause-Attribution": [ + "BSD with attribution", + false + ], + "BSD-4-Clause-UC": [ + "BSD-4-Clause (University of California-Specific)", + false + ], + "bzip2-1.0.5": [ + "bzip2 and libbzip2 License v1.0.5", + false + ], + "bzip2-1.0.6": [ + "bzip2 and libbzip2 License v1.0.6", + false + ], + "Caldera": [ + "Caldera License", + false + ], + "CECILL-1.0": [ + "CeCILL Free Software License Agreement v1.0", + false + ], + "CECILL-1.1": [ + "CeCILL Free Software License Agreement v1.1", + false + ], + "CECILL-2.0": [ + "CeCILL Free Software License Agreement v2.0", + false + ], + "CECILL-B": [ + "CeCILL-B Free Software License Agreement", + false + ], + "CECILL-C": [ + "CeCILL-C Free Software License Agreement", + false + ], + "ClArtistic": [ + "Clarified Artistic License", + false + ], + "MIT-CMU": [ + "CMU License", + false + ], + "CNRI-Python": [ + "CNRI Python License", + true + ], + "CNRI-Python-GPL-Compatible": [ + "CNRI Python Open Source GPL Compatible License Agreement", + false + ], + "CPOL-1.02": [ + "Code Project Open License 1.02", + false + ], + "CDDL-1.0": [ + "Common Development and Distribution License 1.0", + true + ], + "CDDL-1.1": [ + "Common Development and Distribution License 1.1", + false + ], + "CPAL-1.0": [ + "Common Public Attribution License 1.0", + true + ], + "CPL-1.0": [ + "Common Public License 1.0", + true + ], + "CATOSL-1.1": [ + "Computer Associates Trusted Open Source License 1.1", + true + ], + "Condor-1.1": [ + "Condor Public License v1.1", + false + ], + "CC-BY-1.0": [ + "Creative Commons Attribution 1.0", + false + ], + "CC-BY-2.0": [ + "Creative Commons Attribution 2.0", + false + ], + "CC-BY-2.5": [ + "Creative Commons Attribution 2.5", + false + ], + "CC-BY-3.0": [ + "Creative Commons Attribution 3.0", + false + ], + "CC-BY-4.0": [ + "Creative Commons Attribution 4.0", + false + ], + "CC-BY-ND-1.0": [ + "Creative Commons Attribution No Derivatives 1.0", + false + ], + "CC-BY-ND-2.0": [ + "Creative Commons Attribution No Derivatives 2.0", + false + ], + "CC-BY-ND-2.5": [ + "Creative Commons Attribution No Derivatives 2.5", + false + ], + "CC-BY-ND-3.0": [ + "Creative Commons Attribution No Derivatives 3.0", + false + ], + "CC-BY-ND-4.0": [ + "Creative Commons Attribution No Derivatives 4.0", + false + ], + "CC-BY-NC-1.0": [ + "Creative Commons Attribution Non Commercial 1.0", + false + ], + "CC-BY-NC-2.0": [ + "Creative Commons Attribution Non Commercial 2.0", + false + ], + "CC-BY-NC-2.5": [ + "Creative Commons Attribution Non Commercial 2.5", + false + ], + "CC-BY-NC-3.0": [ + "Creative Commons Attribution Non Commercial 3.0", + false + ], + "CC-BY-NC-4.0": [ + "Creative Commons Attribution Non Commercial 4.0", + false + ], + "CC-BY-NC-ND-1.0": [ + "Creative Commons Attribution Non Commercial No Derivatives 1.0", + false + ], + "CC-BY-NC-ND-2.0": [ + "Creative Commons Attribution Non Commercial No Derivatives 2.0", + false + ], + "CC-BY-NC-ND-2.5": [ + "Creative Commons Attribution Non Commercial No Derivatives 2.5", + false + ], + "CC-BY-NC-ND-3.0": [ + "Creative Commons Attribution Non Commercial No Derivatives 3.0", + false + ], + "CC-BY-NC-ND-4.0": [ + "Creative Commons Attribution Non Commercial No Derivatives 4.0", + false + ], + "CC-BY-NC-SA-1.0": [ + "Creative Commons Attribution Non Commercial Share Alike 1.0", + false + ], + "CC-BY-NC-SA-2.0": [ + "Creative Commons Attribution Non Commercial Share Alike 2.0", + false + ], + "CC-BY-NC-SA-2.5": [ + "Creative Commons Attribution Non Commercial Share Alike 2.5", + false + ], + "CC-BY-NC-SA-3.0": [ + "Creative Commons Attribution Non Commercial Share Alike 3.0", + false + ], + "CC-BY-NC-SA-4.0": [ + "Creative Commons Attribution Non Commercial Share Alike 4.0", + false + ], + "CC-BY-SA-1.0": [ + "Creative Commons Attribution Share Alike 1.0", + false + ], + "CC-BY-SA-2.0": [ + "Creative Commons Attribution Share Alike 2.0", + false + ], + "CC-BY-SA-2.5": [ + "Creative Commons Attribution Share Alike 2.5", + false + ], + "CC-BY-SA-3.0": [ + "Creative Commons Attribution Share Alike 3.0", + false + ], + "CC-BY-SA-4.0": [ + "Creative Commons Attribution Share Alike 4.0", + false + ], + "CC0-1.0": [ + "Creative Commons Zero v1.0 Universal", + false + ], + "Crossword": [ + "Crossword License", + false + ], + "CUA-OPL-1.0": [ + "CUA Office Public License v1.0", + true + ], + "Cube": [ + "Cube License", + false + ], + "D-FSL-1.0": [ + "Deutsche Freie Software Lizenz", + false + ], + "diffmark": [ + "diffmark license", + false + ], + "WTFPL": [ + "Do What The F*ck You Want To Public License", + false + ], + "DOC": [ + "DOC License", + false + ], + "Dotseqn": [ + "Dotseqn License", + false + ], + "DSDP": [ + "DSDP License", + false + ], + "dvipdfm": [ + "dvipdfm License", + false + ], + "EPL-1.0": [ + "Eclipse Public License 1.0", + true + ], + "eCos-2.0": [ + "eCos license version 2.0", + false + ], + "ECL-1.0": [ + "Educational Community License v1.0", + true + ], + "ECL-2.0": [ + "Educational Community License v2.0", + true + ], + "eGenix": [ + "eGenix.com Public License 1.1.0", + false + ], + "EFL-1.0": [ + "Eiffel Forum License v1.0", + true + ], + "EFL-2.0": [ + "Eiffel Forum License v2.0", + true + ], + "MIT-advertising": [ + "Enlightenment License (e16)", + false + ], + "MIT-enna": [ + "enna License", + false + ], + "Entessa": [ + "Entessa Public License v1.0", + true + ], + "ErlPL-1.1": [ + "Erlang Public License v1.1", + false + ], + "EUDatagrid": [ + "EU DataGrid Software License", + true + ], + "EUPL-1.0": [ + "European Union Public License 1.0", + false + ], + "EUPL-1.1": [ + "European Union Public License 1.1", + true + ], + "Eurosym": [ + "Eurosym License", + false + ], + "Fair": [ + "Fair License", + true + ], + "MIT-feh": [ + "feh License", + false + ], + "Frameworx-1.0": [ + "Frameworx Open License 1.0", + true + ], + "FTL": [ + "Freetype Project License", + false + ], + "FSFUL": [ + "FSF Unlimited License", + false + ], + "FSFULLR": [ + "FSF Unlimited License (with License Retention)", + false + ], + "Giftware": [ + "Giftware License", + false + ], + "GL2PS": [ + "GL2PS License", + false + ], + "Glulxe": [ + "Glulxe License", + false + ], + "AGPL-3.0": [ + "GNU Affero General Public License v3.0", + true + ], + "GFDL-1.1": [ + "GNU Free Documentation License v1.1", + false + ], + "GFDL-1.2": [ + "GNU Free Documentation License v1.2", + false + ], + "GFDL-1.3": [ + "GNU Free Documentation License v1.3", + false + ], + "GPL-1.0": [ + "GNU General Public License v1.0 only", + false + ], + "GPL-1.0+": [ + "GNU General Public License v1.0 or later", + false + ], + "GPL-2.0": [ + "GNU General Public License v2.0 only", + true + ], + "GPL-2.0+": [ + "GNU General Public License v2.0 or later", + true + ], + "GPL-2.0-with-autoconf-exception": [ + "GNU General Public License v2.0 w/Autoconf exception", + true + ], + "GPL-2.0-with-bison-exception": [ + "GNU General Public License v2.0 w/Bison exception", + true + ], + "GPL-2.0-with-classpath-exception": [ + "GNU General Public License v2.0 w/Classpath exception", + true + ], + "GPL-2.0-with-font-exception": [ + "GNU General Public License v2.0 w/Font exception", + true + ], + "GPL-2.0-with-GCC-exception": [ + "GNU General Public License v2.0 w/GCC Runtime Library exception", + true + ], + "GPL-3.0": [ + "GNU General Public License v3.0 only", + true + ], + "GPL-3.0+": [ + "GNU General Public License v3.0 or later", + true + ], + "GPL-3.0-with-autoconf-exception": [ + "GNU General Public License v3.0 w/Autoconf exception", + true + ], + "GPL-3.0-with-GCC-exception": [ + "GNU General Public License v3.0 w/GCC Runtime Library exception", + true + ], + "LGPL-2.1": [ + "GNU Lesser General Public License v2.1 only", + true + ], + "LGPL-2.1+": [ + "GNU Lesser General Public License v2.1 or later", + true + ], + "LGPL-3.0": [ + "GNU Lesser General Public License v3.0 only", + true + ], + "LGPL-3.0+": [ + "GNU Lesser General Public License v3.0 or later", + true + ], + "LGPL-2.0": [ + "GNU Library General Public License v2 only", + true + ], + "LGPL-2.0+": [ + "GNU Library General Public License v2 or later", + true + ], + "gnuplot": [ + "gnuplot License", + false + ], + "gSOAP-1.3b": [ + "gSOAP Public License v1.3b", + false + ], + "HaskellReport": [ + "Haskell Language Report License", + false + ], + "HPND": [ + "Historic Permission Notice and Disclaimer", + true + ], + "IBM-pibs": [ + "IBM PowerPC Initialization and Boot Software", + false + ], + "IPL-1.0": [ + "IBM Public License v1.0", + true + ], + "ImageMagick": [ + "ImageMagick License", + false + ], + "iMatix": [ + "iMatix Standard Function Library Agreement", + false + ], + "Imlib2": [ + "Imlib2 License", + false + ], + "IJG": [ + "Independent JPEG Group License", + false + ], + "Intel-ACPI": [ + "Intel ACPI Software License Agreement", + false + ], + "Intel": [ + "Intel Open Source License", + true + ], + "IPA": [ + "IPA Font License", + true + ], + "ISC": [ + "ISC License", + true + ], + "JasPer-2.0": [ + "JasPer License", + false + ], + "JSON": [ + "JSON License", + false + ], + "LPPL-1.3a": [ + "LaTeX Project Public License 1.3a", + false + ], + "LPPL-1.0": [ + "LaTeX Project Public License v1.0", + false + ], + "LPPL-1.1": [ + "LaTeX Project Public License v1.1", + false + ], + "LPPL-1.2": [ + "LaTeX Project Public License v1.2", + false + ], + "LPPL-1.3c": [ + "LaTeX Project Public License v1.3c", + true + ], + "Latex2e": [ + "Latex2e License", + false + ], + "BSD-3-Clause-LBNL": [ + "Lawrence Berkeley National Labs BSD variant license", + false + ], + "Leptonica": [ + "Leptonica License", + false + ], + "Libpng": [ + "libpng License", + false + ], + "libtiff": [ + "libtiff License", + false + ], + "LPL-1.02": [ + "Lucent Public License v1.02", + true + ], + "LPL-1.0": [ + "Lucent Public License Version 1.0", + true + ], + "MakeIndex": [ + "MakeIndex License", + false + ], + "MTLL": [ + "Matrix Template Library License", + false + ], + "MS-PL": [ + "Microsoft Public License", + true + ], + "MS-RL": [ + "Microsoft Reciprocal License", + true + ], + "MirOS": [ + "MirOS Licence", + true + ], + "MITNFA": [ + "MIT +no-false-attribs license", + false + ], + "MIT": [ + "MIT License", + true + ], + "Motosoto": [ + "Motosoto License", + true + ], + "MPL-1.0": [ + "Mozilla Public License 1.0", + true + ], + "MPL-1.1": [ + "Mozilla Public License 1.1", + true + ], + "MPL-2.0": [ + "Mozilla Public License 2.0", + true + ], + "MPL-2.0-no-copyleft-exception": [ + "Mozilla Public License 2.0 (no copyleft exception)", + true + ], + "mpich2": [ + "mpich2 License", + false + ], + "Multics": [ + "Multics License", + true + ], + "Mup": [ + "Mup License", + false + ], + "NASA-1.3": [ + "NASA Open Source Agreement 1.3", + true + ], + "Naumen": [ + "Naumen Public License", + true + ], + "NBPL-1.0": [ + "Net Boolean Public License v1", + false + ], + "NetCDF": [ + "NetCDF license", + false + ], + "NGPL": [ + "Nethack General Public License", + true + ], + "NOSL": [ + "Netizen Open Source License", + false + ], + "NPL-1.0": [ + "Netscape Public License v1.0", + false + ], + "NPL-1.1": [ + "Netscape Public License v1.1", + false + ], + "Newsletr": [ + "Newsletr License", + false + ], + "NLPL": [ + "No Limit Public License", + false + ], + "Nokia": [ + "Nokia Open Source License", + true + ], + "NPOSL-3.0": [ + "Non-Profit Open Software License 3.0", + true + ], + "Noweb": [ + "Noweb License", + false + ], + "NRL": [ + "NRL License", + false + ], + "NTP": [ + "NTP License", + true + ], + "Nunit": [ + "Nunit License", + false + ], + "OCLC-2.0": [ + "OCLC Research Public License 2.0", + true + ], + "ODbL-1.0": [ + "ODC Open Database License v1.0", + false + ], + "PDDL-1.0": [ + "ODC Public Domain Dedication & License 1.0", + false + ], + "OGTSL": [ + "Open Group Test Suite License", + true + ], + "OLDAP-2.2.2": [ + "Open LDAP Public License 2.2.2", + false + ], + "OLDAP-1.1": [ + "Open LDAP Public License v1.1", + false + ], + "OLDAP-1.2": [ + "Open LDAP Public License v1.2", + false + ], + "OLDAP-1.3": [ + "Open LDAP Public License v1.3", + false + ], + "OLDAP-1.4": [ + "Open LDAP Public License v1.4", + false + ], + "OLDAP-2.0": [ + "Open LDAP Public License v2.0 (or possibly 2.0A and 2.0B)", + false + ], + "OLDAP-2.0.1": [ + "Open LDAP Public License v2.0.1", + false + ], + "OLDAP-2.1": [ + "Open LDAP Public License v2.1", + false + ], + "OLDAP-2.2": [ + "Open LDAP Public License v2.2", + false + ], + "OLDAP-2.2.1": [ + "Open LDAP Public License v2.2.1", + false + ], + "OLDAP-2.3": [ + "Open LDAP Public License v2.3", + false + ], + "OLDAP-2.4": [ + "Open LDAP Public License v2.4", + false + ], + "OLDAP-2.5": [ + "Open LDAP Public License v2.5", + false + ], + "OLDAP-2.6": [ + "Open LDAP Public License v2.6", + false + ], + "OLDAP-2.7": [ + "Open LDAP Public License v2.7", + false + ], + "OML": [ + "Open Market License", + false + ], + "OPL-1.0": [ + "Open Public License v1.0", + false + ], + "OSL-1.0": [ + "Open Software License 1.0", + true + ], + "OSL-1.1": [ + "Open Software License 1.1", + false + ], + "OSL-2.0": [ + "Open Software License 2.0", + true + ], + "OSL-2.1": [ + "Open Software License 2.1", + true + ], + "OSL-3.0": [ + "Open Software License 3.0", + true + ], + "OLDAP-2.8": [ + "OpenLDAP Public License v2.8", + false + ], + "OpenSSL": [ + "OpenSSL License", + false + ], + "PHP-3.0": [ + "PHP License v3.0", + true + ], + "PHP-3.01": [ + "PHP License v3.01", + false + ], + "Plexus": [ + "Plexus Classworlds License", + false + ], + "PostgreSQL": [ + "PostgreSQL License", + true + ], + "psfrag": [ + "psfrag License", + false + ], + "psutils": [ + "psutils License", + false + ], + "Python-2.0": [ + "Python License 2.0", + true + ], + "QPL-1.0": [ + "Q Public License 1.0", + true + ], + "Qhull": [ + "Qhull License", + false + ], + "Rdisc": [ + "Rdisc License", + false + ], + "RPSL-1.0": [ + "RealNetworks Public Source License v1.0", + true + ], + "RPL-1.1": [ + "Reciprocal Public License 1.1", + true + ], + "RPL-1.5": [ + "Reciprocal Public License 1.5", + true + ], + "RHeCos-1.1": [ + "Red Hat eCos Public License v1.1", + false + ], + "RSCPL": [ + "Ricoh Source Code Public License", + true + ], + "Ruby": [ + "Ruby License", + false + ], + "SAX-PD": [ + "Sax Public Domain Notice", + false + ], + "Saxpath": [ + "Saxpath License", + false + ], + "SCEA": [ + "SCEA Shared Source License", + false + ], + "SWL": [ + "Scheme Widget Library (SWL) Software License Agreement", + false + ], + "SGI-B-1.0": [ + "SGI Free Software License B v1.0", + false + ], + "SGI-B-1.1": [ + "SGI Free Software License B v1.1", + false + ], + "SGI-B-2.0": [ + "SGI Free Software License B v2.0", + false + ], + "OFL-1.0": [ + "SIL Open Font License 1.0", + false + ], + "OFL-1.1": [ + "SIL Open Font License 1.1", + true + ], + "SimPL-2.0": [ + "Simple Public License 2.0", + true + ], + "Sleepycat": [ + "Sleepycat License", + true + ], + "SNIA": [ + "SNIA Public License 1.1", + false + ], + "SMLNJ": [ + "Standard ML of New Jersey License", + false + ], + "StandardML-NJ": [ + "Standard ML of New Jersey License", + false + ], + "SugarCRM-1.1.3": [ + "SugarCRM Public License v1.1.3", + false + ], + "SISSL": [ + "Sun Industry Standards Source License v1.1", + true + ], + "SISSL-1.2": [ + "Sun Industry Standards Source License v1.2", + false + ], + "SPL-1.0": [ + "Sun Public License v1.0", + true + ], + "Watcom-1.0": [ + "Sybase Open Watcom Public License 1.0", + true + ], + "TCL": [ + "TCL/TK License", + false + ], + "Unlicense": [ + "The Unlicense", + false + ], + "TMate": [ + "TMate Open Source License", + false + ], + "TORQUE-1.1": [ + "TORQUE v2.5+ Software License v1.1", + false + ], + "TOSL": [ + "Trusster Open Source License", + false + ], + "Unicode-TOU": [ + "Unicode Terms of Use", + false + ], + "NCSA": [ + "University of Illinois/NCSA Open Source License", + true + ], + "Vim": [ + "Vim License", + false + ], + "VOSTROM": [ + "VOSTROM Public License for Open Source", + false + ], + "VSL-1.0": [ + "Vovida Software License v1.0", + true + ], + "W3C": [ + "W3C Software Notice and License", + true + ], + "Wsuipa": [ + "Wsuipa License", + false + ], + "WXwindows": [ + "wxWindows Library License", + true + ], + "Xnet": [ + "X.Net License", + true + ], + "X11": [ + "X11 License", + false + ], + "Xerox": [ + "Xerox License", + false + ], + "XFree86-1.1": [ + "XFree86 License 1.1", + false + ], + "xinetd": [ + "xinetd License", + false + ], + "xpp": [ + "XPP License", + false + ], + "XSkat": [ + "XSkat License", + false + ], + "YPL-1.0": [ + "Yahoo! Public License v1.0", + false + ], + "YPL-1.1": [ + "Yahoo! Public License v1.1", + false + ], + "Zed": [ + "Zed License", + false + ], + "Zend-2.0": [ + "Zend License v2.0", + false + ], + "Zimbra-1.3": [ + "Zimbra Public License v1.3", + false + ], + "Zlib": [ + "zlib License", + true + ], + "zlib-acknowledgement": [ + "zlib/libpng License with Acknowledgement", + false + ], + "ZPL-1.1": [ + "Zope Public License 1.1", + false + ], + "ZPL-2.0": [ + "Zope Public License 2.0", + true + ], + "ZPL-2.1": [ + "Zope Public License 2.1", + false + ] +} \ No newline at end of file diff --git a/src/Composer/Command/ShowCommand.php b/src/Composer/Command/ShowCommand.php index 6f2a1dab6..4a189702e 100644 --- a/src/Composer/Command/ShowCommand.php +++ b/src/Composer/Command/ShowCommand.php @@ -28,6 +28,7 @@ use Composer\Repository\CompositeRepository; use Composer\Repository\ComposerRepository; use Composer\Repository\PlatformRepository; use Composer\Repository\RepositoryInterface; +use Composer\Util\SpdxLicense; /** * @author Robert Schönthal @@ -115,18 +116,18 @@ EOT $versions = array($package->getPrettyVersion() => $package->getVersion()); } - $this->printMeta($input, $output, $package, $versions, $installedRepo, $repos); - $this->printLinks($input, $output, $package, 'requires'); - $this->printLinks($input, $output, $package, 'devRequires', 'requires (dev)'); + $this->printMeta($package, $versions, $installedRepo); + $this->printLinks($package, 'requires'); + $this->printLinks($package, 'devRequires', 'requires (dev)'); if ($package->getSuggests()) { $this->getIO()->write("\nsuggests"); foreach ($package->getSuggests() as $suggested => $reason) { $this->getIO()->write($suggested . ' ' . $reason . ''); } } - $this->printLinks($input, $output, $package, 'provides'); - $this->printLinks($input, $output, $package, 'conflicts'); - $this->printLinks($input, $output, $package, 'replaces'); + $this->printLinks($package, 'provides'); + $this->printLinks($package, 'conflicts'); + $this->printLinks($package, 'replaces'); return; } @@ -283,14 +284,14 @@ EOT /** * prints package meta data */ - protected function printMeta(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, RepositoryInterface $repos) + protected function printMeta(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo) { $this->getIO()->write('name : ' . $package->getPrettyName()); $this->getIO()->write('descrip. : ' . $package->getDescription()); $this->getIO()->write('keywords : ' . join(', ', $package->getKeywords() ?: array())); - $this->printVersions($input, $output, $package, $versions, $installedRepo, $repos); + $this->printVersions($package, $versions, $installedRepo); $this->getIO()->write('type : ' . $package->getType()); - $this->getIO()->write('license : ' . implode(', ', $package->getLicense())); + $this->printLicenses($package); $this->getIO()->write('source : ' . sprintf('[%s] %s %s', $package->getSourceType(), $package->getSourceUrl(), $package->getSourceReference())); $this->getIO()->write('dist : ' . sprintf('[%s] %s %s', $package->getDistType(), $package->getDistUrl(), $package->getDistReference())); $this->getIO()->write('names : ' . implode(', ', $package->getNames())); @@ -339,7 +340,7 @@ EOT /** * prints all available versions of this package and highlights the installed one if any */ - protected function printVersions(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo, RepositoryInterface $repos) + protected function printVersions(CompletePackageInterface $package, array $versions, RepositoryInterface $installedRepo) { uasort($versions, 'version_compare'); $versions = array_keys(array_reverse($versions)); @@ -361,13 +362,11 @@ EOT /** * print link objects * - * @param InputInterface $input - * @param OutputInterface $output * @param CompletePackageInterface $package * @param string $linkType * @param string $title */ - protected function printLinks(InputInterface $input, OutputInterface $output, CompletePackageInterface $package, $linkType, $title = null) + protected function printLinks(CompletePackageInterface $package, $linkType, $title = null) { $title = $title ?: $linkType; if ($links = $package->{'get'.ucfirst($linkType)}()) { @@ -378,4 +377,29 @@ EOT } } } + + /** + * Prints the licenses of a package with metadata + * + * @param CompletePackageInterface $package + */ + protected function printLicenses(CompletePackageInterface $package) + { + $spdxLicense = new SpdxLicense; + + $licenses = $package->getLicense(); + + foreach($licenses as $licenseId) { + $license = $spdxLicense->getLicenseByIdentifier($licenseId); // keys: 0 fullname, 1 osi, 2 url + + // is license OSI approved? + if($license[1] === true) { + $out = sprintf('%s (%s) (OSI approved) %s', $license[0], $licenseId, $license[2]); + } else { + $out = sprintf('%s (%s) %s', $license[0], $licenseId, $license[2]); + } + + $this->getIO()->write('license : ' . $out); + } + } } diff --git a/src/Composer/Util/ConfigValidator.php b/src/Composer/Util/ConfigValidator.php index 71b0ac418..c4eb645b5 100644 --- a/src/Composer/Util/ConfigValidator.php +++ b/src/Composer/Util/ConfigValidator.php @@ -82,7 +82,7 @@ class ConfigValidator } } - $licenseValidator = new SpdxLicenseIdentifier(); + $licenseValidator = new SpdxLicense(); 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.' diff --git a/src/Composer/Util/SpdxLicenseIdentifier.php b/src/Composer/Util/SpdxLicense.php similarity index 71% rename from src/Composer/Util/SpdxLicenseIdentifier.php rename to src/Composer/Util/SpdxLicense.php index 59584001c..ec9a01bd3 100644 --- a/src/Composer/Util/SpdxLicenseIdentifier.php +++ b/src/Composer/Util/SpdxLicense.php @@ -1,178 +1,229 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Util; - -use Composer\Json\JsonFile; - -/** - * Supports composer array and SPDX tag notation for disjunctive/conjunctive - * licenses. - * - * @author Tom Klingenberg - */ -class SpdxLicenseIdentifier -{ - /** - * @var array - */ - private $identifiers; - - public function __construct() - { - $this->initIdentifiers(); - } - - /** - * @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); - } - - /** - * Loads SPDX identifiers - */ - private function initIdentifiers() - { - $jsonFile = new JsonFile(__DIR__ . '/../../../res/spdx-identifier.json'); - $this->identifiers = $jsonFile->read(); - } - - /** - * @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); - } -} + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Util; + +use Composer\Json\JsonFile; + +/** + * Supports composer array and SPDX tag notation for disjunctive/conjunctive + * licenses. + * + * @author Tom Klingenberg + */ +class SpdxLicense +{ + /** + * @var array + */ + private $licenses; + + public function __construct() + { + $this->loadLicenses(); + } + + private function loadLicenses() + { + if(is_array($this->licenses)) { + return $this->licenses; + } + + $jsonFile = new JsonFile(__DIR__ . '/../../../res/spdx-licenses.json'); + $this->licenses = $jsonFile->read(); + + return $this->licenses; + } + + /** + * Returns license metadata by license identifier. + * + * @param string $identifier + * + * @return array + */ + public function getLicenseByIdentifier($identifier) + { + $license = $this->licenses[$identifier]; + + // add URL for the license text (it's not included in the json) + $license[2] = 'http://spdx.org/licenses/' . $identifier . '#licenseText'; + + return $license; + } + + /** + * Returns the short identifier of a license by full name. + * + * @param string $identifier + * + * @return string + */ + public function getIdentifierByName($name) + { + foreach ($this->licenses as $identifier => $licenseData) { + if($licenseData[0] === $name) { // key 0 = fullname + return $identifier; + } + } + } + + /** + * Returns the OSI Approved status for a license by 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); + } + + /** + * @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); + } + + /** + * @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); + } +} diff --git a/src/Composer/Util/SpdxLicensesUpdater.php b/src/Composer/Util/SpdxLicensesUpdater.php new file mode 100644 index 000000000..98796abae --- /dev/null +++ b/src/Composer/Util/SpdxLicensesUpdater.php @@ -0,0 +1,67 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Util; + +use Composer\Json\JsonFormatter; + +/** + * 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 +{ + private $licensesUrl = 'http://www.spdx.org/licenses/'; + + public function update() + { + $json = json_encode($this->getLicenses(), true); + $prettyJson = JsonFormatter::format($json, true, true); + file_put_contents(__DIR__ . '/../../../res/spdx-licenses.json', $prettyJson); + } + + private function getLicenses() + { + $licenses = array(); + + $dom = new \DOMDocument; + $dom->loadHTMLFile($this->licensesUrl); + + $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) { + throw new \Exception('Obtaining the license table failed. Wrong table format. Found less than 4 cells in a row.'); + } + + 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; + } +} \ No newline at end of file diff --git a/tests/Composer/Test/Util/SpdxLicenseIdentifierTest.php b/tests/Composer/Test/Util/SpdxLicenseTest.php similarity index 57% rename from tests/Composer/Test/Util/SpdxLicenseIdentifierTest.php rename to tests/Composer/Test/Util/SpdxLicenseTest.php index b6cee4ec5..d4665954e 100644 --- a/tests/Composer/Test/Util/SpdxLicenseIdentifierTest.php +++ b/tests/Composer/Test/Util/SpdxLicenseTest.php @@ -2,12 +2,28 @@ namespace Composer\Test\Util; use Composer\TestCase; -use Composer\Util\SpdxLicenseIdentifier; +use Composer\Util\SpdxLicense; -class SpdxLicenseIdentifierTest extends TestCase +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", @@ -18,7 +34,7 @@ class SpdxLicenseIdentifierTest extends TestCase "(LGPL-2.0 or GPL-3.0+)", "(EUDatagrid and GPL-3.0+)", ), - json_decode(file_get_contents(__DIR__ . '/../../../../res/spdx-identifier.json')) + $identifiers ); foreach ($valid as &$r) { @@ -68,8 +84,7 @@ class SpdxLicenseIdentifierTest extends TestCase */ public function testValidate($license) { - $validator = new SpdxLicenseIdentifier(); - $this->assertTrue($validator->validate($license)); + $this->assertTrue($this->license->validate($license)); } /** @@ -78,8 +93,7 @@ class SpdxLicenseIdentifierTest extends TestCase */ public function testInvalidLicenses($invalidLicense) { - $validator = new SpdxLicenseIdentifier(); - $this->assertFalse($validator->validate($invalidLicense)); + $this->assertFalse($this->license->validate($invalidLicense)); } /** @@ -88,7 +102,31 @@ class SpdxLicenseIdentifierTest extends TestCase */ public function testInvalidArgument($invalidArgument) { - $validator = new SpdxLicenseIdentifier(); - $validator->validate($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); } }