Selaa lähdekoodia

Revert "apply a regex solution instead of tokenizer"

This reverts commit 33a7305e22c8d4e2ce38586855fd3d4b7b2af3dd.
Rob Bast 10 vuotta sitten
vanhempi
commit
4019f7bb44
2 muutettua tiedostoa jossa 106 lisäystä ja 58 poistoa
  1. 103 57
      src/Composer/Util/SpdxLicense.php
  2. 3 1
      tests/Composer/Test/Util/SpdxLicenseTest.php

+ 103 - 57
src/Composer/Util/SpdxLicense.php

@@ -192,69 +192,115 @@ class SpdxLicense
      * @param string $license
      *
      * @return bool
-     *
      * @throws \RuntimeException
      */
     private function isValidLicenseString($license)
     {
-        $licenses = array_map('preg_quote', array_keys($this->licenses));
-        sort($licenses);
-        $licenses = array_reverse($licenses);
-        $licenses = implode('|', $licenses);
-
-        $exceptions = array_map('preg_quote', array_keys($this->exceptions));
-        sort($exceptions);
-        $exceptions = array_reverse($exceptions);
-        $exceptions = implode('|', $exceptions);
-
-        $regex = "{
-            (?(DEFINE)
-                # idstring: 1*( ALPHA / DIGIT / - / . )
-                (?<idstring>[\pL\pN\-\.]{1,})
-
-                # license-id: taken from list
-                (?<licenseid>${licenses})
-
-                # license-exception-id: taken from list
-                (?<licenseexceptionid>${exceptions})
-
-                # license-ref: [DocumentRef-1*(idstring):]LicenseRef-1*(idstring)
-                (?<licenseref>(?:DocumentRef-(?&idstring):)?LicenseRef-(?&idstring))
-
-                # simple-expresssion: license-id / license-id+ / license-ref
-                (?<simple_expression>(?&licenseid)\+? | (?&licenseid) | (?&licenseref))
-
-                # compound expression: 1*(
-                #   simple-expression /
-                #   simple-expression WITH license-exception-id /
-                #   compound-expression AND compound-expression /
-                #   compound-expression OR compound-expression
-                # ) / ( compound-expression ) )
-                (?<compound_head>
-                    (?&simple_expression) ( \s+ (?:with|WITH) \s+ (?&licenseexceptionid))?
-                        | \( \s* (?&compound_expression) \s*\)
-                )
-                (?<compound_expression>
-                    (?&compound_head) (?: \s+ (?:and|AND|or|OR) \s+ (?&compound_expression))?
-                )
-
-                # license-expression: 1*1(simple-expression / compound-expression)
-                (?<license_expression>NONE | NOASSERTION | (?&compound_expression) | (?&simple_expression))
-            ) # end of define
-
-            ^(?&license_expression)$
-        }x";
-
-        $match = preg_match($regex, $license);
-
-        if (0 === $match) {
-            return false;
-        }
+        $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;
+            }
 
-        if (false === $match) {
-            throw new \RuntimeException('Regex failed to compile/run.');
+            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 true;
+        return !($open % 2 || $require || $with);
     }
 }

+ 3 - 1
tests/Composer/Test/Util/SpdxLicenseTest.php

@@ -39,7 +39,6 @@ class SpdxLicenseTest extends TestCase
                 "GPL-2.0 with Autoconf-exception-2.0",
                 "GPL-2.0 WITH Autoconf-exception-2.0",
                 "GPL-2.0+ WITH Autoconf-exception-2.0",
-                "(GPL-3.0 and GPL-2.0 or GPL-3.0+)",
             ),
             $identifiers
         );
@@ -58,6 +57,7 @@ class SpdxLicenseTest extends TestCase
             array(array()),
             array("The system pwns you"),
             array("()"),
+            array("(MIT)"),
             array("(MIT"),
             array("MIT)"),
             array("MIT NONE"),
@@ -66,6 +66,8 @@ class SpdxLicenseTest extends TestCase
             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)"),