Subject: [bug#58621] [PATCH 2/3] import/utils: spdx-string->license: Match case-insensitively.

From: Philip McGrath <[email-masked]>
Date: Wed, 19 Oct 2022 01:04:48 -0400

SPDX specifies that license identifiers (unlike the 'AND', 'OR', and
'WITH' operators) are matched case-insensitively.

* guix/import/utils.scm (%spdx-license-identifiers): New variable.
(spdx-string->license): Search in '%spdx-license-identifiers' using
'string-ci=?'.
---
 guix/import/utils.scm | 250 ++++++++++++++++++++++--------------------
 1 file changed, 130 insertions(+), 120 deletions(-)

diff --git a/guix/import/utils.scm b/guix/import/utils.scm
index 6afb009a00..9944b606f3 100644
--- a/guix/import/utils.scm
+++ b/guix/import/utils.scm
@@ -131,132 +131,142 @@ (define (guix-hash-url filename)
   "Return the hash of FILENAME in nix-base32 format."
   (bytevector->nix-base32-string (file-sha256 filename)))
 
-(define (spdx-string->license str)
-  "Convert STR, an SPDX license identifier, to a symbol like 'license:gpl3+
-giving the prefixed name of a license object exported from (guix licenses).
-Return #f if STR does not match any known SPDX license identifiers."
+(define %spdx-license-identifiers
   ;; https://spdx.org/licenses/
   ;; The gfl1.0, nmap, repoze
   ;; licenses doesn't have SPDX identifiers
   ;;
   ;; Please update guix/licenses.scm when modifying
   ;; this list to avoid mismatches.
-  (match str
-    ;; "GPL-N+" has been deprecated in favour of "GPL-N-or-later".
-    ;; "GPL-N" has been deprecated in favour of "GPL-N-only"
-    ;; or "GPL-N-or-later" as appropriate.  Likewise for LGPL
-    ;; and AGPL
-    ("AGPL-1.0"                    'license:agpl1)
-    ("AGPL-1.0-only"               'license:agpl1)
-    ("AGPL-3.0"                    'license:agpl3)
-    ("AGPL-3.0-only"               'license:agpl3)
-    ("AGPL-3.0-or-later"           'license:agpl3+)
-    ("Apache-1.1"                  'license:asl1.1)
-    ("Apache-2.0"                  'license:asl2.0)
-    ("APSL-2.0"                    'license:apsl2)
-    ("BSL-1.0"                     'license:boost1.0)
-    ("0BSD"                        'license:bsd-0)
-    ("BSD-2-Clause"                'license:bsd-2)
-    ("BSD-2-Clause-FreeBSD"        'license:bsd-2)     ;flagged as deprecated on spdx
-    ("BSD-3-Clause"                'license:bsd-3)
-    ("BSD-4-Clause"                'license:bsd-4)
-    ("CC0-1.0"                     'license:cc0)
-    ("CC-BY-2.0"                   'license:cc-by2.0)
-    ("CC-BY-3.0"                   'license:cc-by3.0)
-    ("CC-BY-4.0"                   'license:cc-by4.0)
-    ("CC-BY-SA-2.0"                'license:cc-by-sa2.0)
-    ("CC-BY-SA-3.0"                'license:cc-by-sa3.0)
-    ("CC-BY-SA-4.0"                'license:cc-by-sa4.0)
-    ("CDDL-1.0"                    'license:cddl1.0)
-    ("CDDL-1.1"                    'license:cddl1.1)
-    ("CECILL-2.1"                  'license:cecill)
-    ("CECILL-B"                    'license:cecill-b)
-    ("CECILL-C"                    'license:cecill-c)
-    ("Artistic-2.0"                'license:artistic2.0)
-    ("ClArtistic"                  'license:clarified-artistic)
-    ("copyleft-next-0.3.0"         'license:copyleft-next)
-    ("CPL-1.0"                     'license:cpl1.0)
-    ("EPL-1.0"                     'license:epl1.0)
-    ("EPL-2.0"                     'license:epl2.0)
-    ("EUPL-1.2"                    'license:eupl1.2)
-    ("MIT"                         'license:expat)
-    ("MIT-0"                       'license:expat-0)
-    ("FTL"                         'license:freetype)
-    ("FreeBSD-DOC"                 'license:freebsd-doc)
-    ("Freetype"                    'license:freetype)
-    ("FSFAP"                       'license:fsf-free)
-    ("FSFUL"                       'license:fsf-free)
-    ("GFDL-1.1"                    'license:fdl1.1+)
-    ("GFDL-1.1-or-later"           'license:fdl1.1+)
-    ("GFDL-1.2"                    'license:fdl1.2+)
-    ("GFDL-1.2-or-later"           'license:fdl1.2+)
-    ("GFDL-1.3"                    'license:fdl1.3+)
-    ("GFDL-1.3-or-later"           'license:fdl1.3+)
-    ("Giftware"                    'license:giftware)
-    ("GPL-1.0"                     'license:gpl1)
-    ("GPL-1.0-only"                'license:gpl1)
-    ("GPL-1.0+"                    'license:gpl1+)
-    ("GPL-1.0-or-later"            'license:gpl1+)
-    ("GPL-2.0"                     'license:gpl2)
-    ("GPL-2.0-only"                'license:gpl2)
-    ("GPL-2.0+"                    'license:gpl2+)
-    ("GPL-2.0-or-later"            'license:gpl2+)
-    ("GPL-3.0"                     'license:gpl3)
-    ("GPL-3.0-only"                'license:gpl3)
-    ("GPL-3.0+"                    'license:gpl3+)
-    ("GPL-3.0-or-later"            'license:gpl3+)
-    ("HPND"                        'license:hpnd)
-    ("ISC"                         'license:isc)
-    ("IJG"                         'license:ijg)
-    ("Imlib2"                      'license:imlib2)
-    ("IPA"                         'license:ipa)
-    ("IPL-1.0"                     'license:ibmpl1.0)
-    ("LAL-1.3"                     'license:lal1.3)
-    ("LGPL-2.0"                    'license:lgpl2.0)
-    ("LGPL-2.0-only"               'license:lgpl2.0)
-    ("LGPL-2.0+"                   'license:lgpl2.0+)
-    ("LGPL-2.0-or-later"           'license:lgpl2.0+)
-    ("LGPL-2.1"                    'license:lgpl2.1)
-    ("LGPL-2.1-only"               'license:lgpl2.1)
-    ("LGPL-2.1+"                   'license:lgpl2.1+)
-    ("LGPL-2.1-or-later"           'license:lgpl2.1+)
-    ("LGPL-3.0"                    'license:lgpl3)
-    ("LGPL-3.0-only"               'license:lgpl3)
-    ("LGPL-3.0+"                   'license:lgpl3+)
-    ("LGPL-3.0-or-later"           'license:lgpl3+)
-    ("LPPL-1.0"                    'license:lppl)
-    ("LPPL-1.1"                    'license:lppl)
-    ("LPPL-1.2"                    'license:lppl1.2)
-    ("LPPL-1.3a"                   'license:lppl1.3a)
-    ("LPPL-1.3c"                   'license:lppl1.3c)
-    ("MirOS"                       'license:miros)
-    ("MPL-1.0"                     'license:mpl1.0)
-    ("MPL-1.1"                     'license:mpl1.1)
-    ("MPL-2.0"                     'license:mpl2.0)
-    ("MS-PL"                       'license:ms-pl)
-    ("NCSA"                        'license:ncsa)
-    ("OGL-UK-1.0"                  'license:ogl-psi1.0)
-    ("OpenSSL"                     'license:openssl)
-    ("OLDAP-2.8"                   'license:openldap2.8)
-    ("OPL-1.0"                     'license:opl1.0+)
-    ("CUA-OPL-1.0"                 'license:cua-opl1.0)
-    ("PSF-2.0"                     'license:psfl)
-    ("OSL-2.1"                     'license:osl2.1)
-    ("QPL-1.0"                     'license:qpl)
-    ("Ruby"                        'license:ruby)
-    ("SGI-B-2.0"                   'license:sgifreeb2.0)
-    ("OFL-1.1"                     'license:silofl1.1)
-    ("Sleepycat"                   'license:sleepycat)
-    ("TCL"                         'license:tcl/tk)
-    ("Unlicense"                   'license:unlicense)
-    ("Vim"                         'license:vim)
-    ("W3C"                         'license:w3c)
-    ("WTFPL"                       'license:wtfpl2)
-    ("wxWindow"                    'license:wxwindows3.1+)         ;flagged as deprecated on spdx
-    ("X11"                         'license:x11)
-    ("ZPL-2.1"                     'license:zpl2.1)
-    ("Zlib"                        'license:zlib)
-    (_ #f)))
+  ;;
+  ;; "GPL-N+" has been deprecated in favour of "GPL-N-or-later".
+  ;; "GPL-N" has been deprecated in favour of "GPL-N-only"
+  ;; or "GPL-N-or-later" as appropriate.  Likewise for LGPL
+  ;; and AGPL.
+  '(("AGPL-1.0"                   . license:agpl1)
+    ("AGPL-1.0-only"              . license:agpl1)
+    ("AGPL-3.0"                   . license:agpl3)
+    ("AGPL-3.0-only"              . license:agpl3)
+    ("AGPL-3.0-or-later"          . license:agpl3+)
+    ("Apache-1.1"                 . license:asl1.1)
+    ("Apache-2.0"                 . license:asl2.0)
+    ("APSL-2.0"                   . license:apsl2)
+    ("BSL-1.0"                    . license:boost1.0)
+    ("0BSD"                       . license:bsd-0)
+    ("BSD-2-Clause"               . license:bsd-2)
+    ("BSD-2-Clause-FreeBSD"       . license:bsd-2)     ;flagged as deprecated on spdx
+    ("BSD-3-Clause"               . license:bsd-3)
+    ("BSD-4-Clause"               . license:bsd-4)
+    ("CC0-1.0"                    . license:cc0)
+    ("CC-BY-2.0"                  . license:cc-by2.0)
+    ("CC-BY-3.0"                  . license:cc-by3.0)
+    ("CC-BY-4.0"                  . license:cc-by4.0)
+    ("CC-BY-SA-2.0"               . license:cc-by-sa2.0)
+    ("CC-BY-SA-3.0"               . license:cc-by-sa3.0)
+    ("CC-BY-SA-4.0"               . license:cc-by-sa4.0)
+    ("CDDL-1.0"                   . license:cddl1.0)
+    ("CDDL-1.1"                   . license:cddl1.1)
+    ("CECILL-2.1"                 . license:cecill)
+    ("CECILL-B"                   . license:cecill-b)
+    ("CECILL-C"                   . license:cecill-c)
+    ("Artistic-2.0"               . license:artistic2.0)
+    ("ClArtistic"                 . license:clarified-artistic)
+    ("copyleft-next-0.3.0"        . license:copyleft-next)
+    ("CPL-1.0"                    . license:cpl1.0)
+    ("EPL-1.0"                    . license:epl1.0)
+    ("EPL-2.0"                    . license:epl2.0)
+    ("EUPL-1.2"                   . license:eupl1.2)
+    ("MIT"                        . license:expat)
+    ("MIT-0"                      . license:expat-0)
+    ("FTL"                        . license:freetype)
+    ("FreeBSD-DOC"                . license:freebsd-doc)
+    ("Freetype"                   . license:freetype)
+    ("FSFAP"                      . license:fsf-free)
+    ("FSFUL"                      . license:fsf-free)
+    ("GFDL-1.1"                   . license:fdl1.1+)
+    ("GFDL-1.1-or-later"          . license:fdl1.1+)
+    ("GFDL-1.2"                   . license:fdl1.2+)
+    ("GFDL-1.2-or-later"          . license:fdl1.2+)
+    ("GFDL-1.3"                   . license:fdl1.3+)
+    ("GFDL-1.3-or-later"          . license:fdl1.3+)
+    ("Giftware"                   . license:giftware)
+    ("GPL-1.0"                    . license:gpl1)
+    ("GPL-1.0-only"               . license:gpl1)
+    ("GPL-1.0+"                   . license:gpl1+)
+    ("GPL-1.0-or-later"           . license:gpl1+)
+    ("GPL-2.0"                    . license:gpl2)
+    ("GPL-2.0-only"               . license:gpl2)
+    ("GPL-2.0+"                   . license:gpl2+)
+    ("GPL-2.0-or-later"           . license:gpl2+)
+    ("GPL-3.0"                    . license:gpl3)
+    ("GPL-3.0-only"               . license:gpl3)
+    ("GPL-3.0+"                   . license:gpl3+)
+    ("GPL-3.0-or-later"           . license:gpl3+)
+    ("HPND"                       . license:hpnd)
+    ("ISC"                        . license:isc)
+    ("IJG"                        . license:ijg)
+    ("Imlib2"                     . license:imlib2)
+    ("IPA"                        . license:ipa)
+    ("IPL-1.0"                    . license:ibmpl1.0)
+    ("LAL-1.3"                    . license:lal1.3)
+    ("LGPL-2.0"                   . license:lgpl2.0)
+    ("LGPL-2.0-only"              . license:lgpl2.0)
+    ("LGPL-2.0+"                  . license:lgpl2.0+)
+    ("LGPL-2.0-or-later"          . license:lgpl2.0+)
+    ("LGPL-2.1"                   . license:lgpl2.1)
+    ("LGPL-2.1-only"              . license:lgpl2.1)
+    ("LGPL-2.1+"                  . license:lgpl2.1+)
+    ("LGPL-2.1-or-later"          . license:lgpl2.1+)
+    ("LGPL-3.0"                   . license:lgpl3)
+    ("LGPL-3.0-only"              . license:lgpl3)
+    ("LGPL-3.0+"                  . license:lgpl3+)
+    ("LGPL-3.0-or-later"          . license:lgpl3+)
+    ("LPPL-1.0"                   . license:lppl)
+    ("LPPL-1.1"                   . license:lppl)
+    ("LPPL-1.2"                   . license:lppl1.2)
+    ("LPPL-1.3a"                  . license:lppl1.3a)
+    ("LPPL-1.3c"                  . license:lppl1.3c)
+    ("MirOS"                      . license:miros)
+    ("MPL-1.0"                    . license:mpl1.0)
+    ("MPL-1.1"                    . license:mpl1.1)
+    ("MPL-2.0"                    . license:mpl2.0)
+    ("MS-PL"                      . license:ms-pl)
+    ("NCSA"                       . license:ncsa)
+    ("OGL-UK-1.0"                 . license:ogl-psi1.0)
+    ("OpenSSL"                    . license:openssl)
+    ("OLDAP-2.8"                  . license:openldap2.8)
+    ("OPL-1.0"                    . license:opl1.0+)
+    ("CUA-OPL-1.0"                . license:cua-opl1.0)
+    ("PSF-2.0"                    . license:psfl)
+    ("OSL-2.1"                    . license:osl2.1)
+    ("QPL-1.0"                    . license:qpl)
+    ("Ruby"                       . license:ruby)
+    ("SGI-B-2.0"                  . license:sgifreeb2.0)
+    ("OFL-1.1"                    . license:silofl1.1)
+    ("Sleepycat"                  . license:sleepycat)
+    ("TCL"                        . license:tcl/tk)
+    ("Unlicense"                  . license:unlicense)
+    ("Vim"                        . license:vim)
+    ("W3C"                        . license:w3c)
+    ("WTFPL"                      . license:wtfpl2)
+    ("wxWindow"                   . license:wxwindows3.1+)         ;flagged as deprecated on spdx
+    ("X11"                        . license:x11)
+    ("ZPL-2.1"                    . license:zpl2.1)
+    ("Zlib"                       . license:zlib)))
+
+(define (spdx-string->license str)
+  "Convert STR, an SPDX license identifier, to a symbol like 'license:gpl3+
+giving the prefixed name of a license object exported from (guix licenses).
+Return #f if STR does not match any known SPDX license identifiers.  Per the
+SPDX specification, license identifiers are compared case-insensitively."
+  ;; https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions/#d2-case-sensitivity
+  ;; Operators AND, OR, and WITH are case-sensitive, but identifiers are
+  ;; case-insensitive for matching, though the canonical case is used in URIs.
+  (match (assoc str %spdx-license-identifiers string-ci=?)
+    ((_ . license)
+     license)
+    (#f
+     #f)))
 
 (define (license->symbol license)
   "Convert LICENSE object to a prefixed symbol representing the variable the
-- 
2.38.0