]> Savannah Git Hosting - gnulib.git/commitdiff
gnulib-tool.py: Allow verifying license compatibility with GPLv2+.
authorBruno Haible <bruno@clisp.org>
Thu, 29 Aug 2024 16:32:35 +0000 (18:32 +0200)
committerBruno Haible <bruno@clisp.org>
Thu, 29 Aug 2024 16:32:35 +0000 (18:32 +0200)
* pygnulib/GLInfo.py (GLInfo.usage): Document the --gpl option.
* pygnulib/main.py (main): Accept a --gpl option. Pass it to the
GLConfig.
* pygnulib/GLConfig.py (GLConfig): Add 'gpl' field and constructor
argument. Add getGPL, setGPL, resetGPL methods.
* m4/gnulib-tool.m4 (gl_GPL): New macro.
* doc/gnulib-tool.texi (Modified imports): Document the gl_GPL macro.
* pygnulib/GLImport.py (GLImport.__init__): Look for gl_GPL invocations
in gnulib-cache.m4.
(GLImport.actioncmd): Output --gpl option when option --gpl was given.
(GLImport.gnulib_cache): Emit a gl_GPL invocation when option --gpl was
given.
(GLImport.prepare): Do license compatibility checking when option --gpl
was given.
* pygnulib/GLModuleSystem.py: Update a comment.

ChangeLog
doc/gnulib-tool.texi
m4/gnulib-tool.m4
pygnulib/GLConfig.py
pygnulib/GLImport.py
pygnulib/GLInfo.py
pygnulib/GLModuleSystem.py
pygnulib/main.py

index 40e42cc0d0b6680d7c95461d2daaa46ff1cc0242..bf6ae5eba4d4f102057ac48530f36bc27695cedd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2024-08-29  Bruno Haible  <bruno@clisp.org>
+
+       gnulib-tool.py: Allow verifying license compatibility with GPLv2+.
+       * pygnulib/GLInfo.py (GLInfo.usage): Document the --gpl option.
+       * pygnulib/main.py (main): Accept a --gpl option. Pass it to the
+       GLConfig.
+       * pygnulib/GLConfig.py (GLConfig): Add 'gpl' field and constructor
+       argument. Add getGPL, setGPL, resetGPL methods.
+       * m4/gnulib-tool.m4 (gl_GPL): New macro.
+       * doc/gnulib-tool.texi (Modified imports): Document the gl_GPL macro.
+       * pygnulib/GLImport.py (GLImport.__init__): Look for gl_GPL invocations
+       in gnulib-cache.m4.
+       (GLImport.actioncmd): Output --gpl option when option --gpl was given.
+       (GLImport.gnulib_cache): Emit a gl_GPL invocation when option --gpl was
+       given.
+       (GLImport.prepare): Do license compatibility checking when option --gpl
+       was given.
+       * pygnulib/GLModuleSystem.py: Update a comment.
+
 2024-08-29  Bruno Haible  <bruno@clisp.org>
 
        gnulib-tool: Fix description of --lgpl option (missed on 2021-06-04).
index 41eccb30191d1ace87ecb4d824c1fd554eb237fa..470342722df4e0a72d1d281d56fb432bf841a2b1 100644 (file)
@@ -454,6 +454,10 @@ command line argument.  The presence of this macro with an argument (whose
 value must be 2 or 3) corresponds to the @samp{--lgpl=@var{arg}} command line
 argument.
 
+@item gl_GPL
+The presence of this macro with an argument (whose value must be 2 or 3)
+corresponds to the @samp{--gpl=@var{arg}} command line argument.
+
 @item gl_MAKEFILE_NAME
 The argument is the name of the makefile in the source-base and tests-base
 directories.  Corresponds to the @samp{--makefile-name} command line argument.
index ef45f51fc829bca4c5a623931d84eb1306b412ac..2f517f1bbc80f50907fe4bbee0d42c751908b7c4 100644 (file)
@@ -1,5 +1,5 @@
 # gnulib-tool.m4
-# serial 4
+# serial 5
 dnl Copyright (C) 2004-2005, 2009-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -42,6 +42,9 @@ AC_DEFUN([gl_LIB], [])
 dnl Usage: gl_LGPL or gl_LGPL([VERSION])
 AC_DEFUN([gl_LGPL], [])
 
+dnl Usage: gl_GPL([VERSION])
+AC_DEFUN([gl_GPL], [])
+
 dnl Usage: gl_MAKEFILE_NAME([FILENAME])
 AC_DEFUN([gl_MAKEFILE_NAME], [])
 
index b8a7fc5b0baa0feb07286fe1023dca6d3a4f38b8..353701cd3b10cc49b055e90904c8bb90afc4e065 100644 (file)
@@ -60,6 +60,7 @@ class GLConfig:
                  excl_test_categories: list[int] | tuple[int] | None = None,
                  libname: str | None = None,
                  lgpl: str | bool | None = None,
+                 gpl: str | None = None,
                  gnu_make: bool | None = None,
                  makefile_name: str | None = None,
                  tests_makefile_name: str | None = None,
@@ -151,6 +152,10 @@ class GLConfig:
         self.resetLGPL()
         if lgpl != None:
             self.setLGPL(lgpl)
+        # gpl
+        self.resetGPL()
+        if gpl != None:
+            self.setGPL(gpl)
         # gnu-make
         self.resetGnuMake()
         if gnu_make != None:
@@ -318,7 +323,7 @@ class GLConfig:
                 return False
             elif key in ['copymode', 'lcopymode']:
                 return CopyAction.Copy
-            elif key in ['lgpl', 'libtool', 'conddeps', 'vc_files']:
+            elif key in ['lgpl', 'gpl', 'libtool', 'conddeps', 'vc_files']:
                 return None
             elif key == 'errors':
                 return True
@@ -834,6 +839,25 @@ class GLConfig:
         Default value is None, which means that lgpl is disabled.'''
         self.table['lgpl'] = None
 
+    # Define gpl methods.
+    def getGPL(self) -> str | None:
+        '''Check for abort if modules aren't available under the GPL.
+        Default value is None, which means that gpl is disabled.'''
+        return self.table['gpl']
+
+    def setGPL(self, gpl: str | bool | None) -> None:
+        '''Abort if modules aren't available under the GPL.
+        Default value is None, which means that gpl is disabled.'''
+        if gpl in [None, '2', '3']:
+            self.table['gpl'] = gpl
+        else:
+            raise TypeError('invalid GPL version: %s' % repr(gpl))
+
+    def resetGPL(self) -> None:
+        '''Disable abort if modules aren't available under the GPL.
+        Default value is None, which means that gpl is disabled.'''
+        self.table['gpl'] = None
+
     # Define gnu-make methods.
     def getGnuMake(self) -> bool:
         '''Return a boolean value describing whether the --gnu-make argument
index 5f090d4ea118ca625d36180fa85e18495d7e52a1..32ab54b29a53de297d7f2294c015de881452ddb1 100644 (file)
@@ -175,7 +175,8 @@ class GLImport:
                 [
                     'gl_LOCAL_DIR', 'gl_MODULES', 'gl_AVOID', 'gl_SOURCE_BASE',
                     'gl_M4_BASE', 'gl_PO_BASE', 'gl_DOC_BASE', 'gl_TESTS_BASE',
-                    'gl_LIB', 'gl_LGPL', 'gl_MAKEFILE_NAME', 'gl_TESTS_MAKEFILE_NAME',
+                    'gl_LIB', 'gl_LGPL', 'gl_GPL',
+                    'gl_MAKEFILE_NAME', 'gl_TESTS_MAKEFILE_NAME',
                     'gl_MACRO_PREFIX', 'gl_PO_DOMAIN', 'gl_WITNESS_C_MACRO',
                     'gl_VC_FILES',
                 ]
@@ -191,6 +192,8 @@ class GLImport:
                 self.cache.setLGPL(None)
             if tempdict['gl_LIB']:
                 self.cache.setLibName(cleaner(tempdict['gl_LIB']))
+            if tempdict['gl_GPL']:
+                self.cache.setLibName(cleaner(tempdict['gl_GPL']))
             if tempdict['gl_LOCAL_DIR']:
                 self.cache.setLocalPath(cleaner(tempdict['gl_LOCAL_DIR']).split(':'))
             if tempdict['gl_MODULES']:
@@ -331,6 +334,7 @@ class GLImport:
         conddeps = self.config.checkCondDeps()
         libname = self.config.getLibName()
         lgpl = self.config.getLGPL()
+        gpl = self.config.getGPL()
         gnu_make = self.config.getGnuMake()
         makefile_name = self.config.getMakefileName()
         tests_makefile_name = self.config.getTestsMakefileName()
@@ -380,6 +384,8 @@ class GLImport:
                 actioncmd += ' \\\n#  --lgpl'
             else:  # if lgpl != True
                 actioncmd += ' \\\n#  --lgpl=%s' % lgpl
+        if gpl:
+            actioncmd += ' \\\n#  --gpl=%s' % gpl
         if gnu_make:
             actioncmd += ' \\\n#  --gnu-make'
         if makefile_name:
@@ -455,6 +461,7 @@ class GLImport:
         docbase = self.config['docbase']
         testsbase = self.config['testsbase']
         lgpl = self.config['lgpl']
+        gpl = self.config['gpl']
         libname = self.config['libname']
         makefile_name = self.config['makefile_name']
         tests_makefile_name = self.config['tests_makefile_name']
@@ -512,6 +519,8 @@ class GLImport:
                 emit += 'gl_LGPL\n'
             else:  # if lgpl != True
                 emit += 'gl_LGPL([%s])\n' % lgpl
+        if gpl != None:
+            emit += 'gl_GPL([%s])\n' % gpl
         emit += 'gl_MAKEFILE_NAME([%s])\n' % makefile_name
         if tests_makefile_name:
             emit += 'gl_TESTS_MAKEFILE_NAME([%s])\n' % tests_makefile_name
@@ -751,6 +760,7 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix
         modules = list(self.config['modules'])
         m4base = self.config['m4base']
         lgpl = self.config['lgpl']
+        gpl = self.config['gpl']
         verbose = self.config['verbosity']
         base_modules = set()
         for name in modules:
@@ -815,18 +825,23 @@ AC_DEFUN([%s_FILE_LIST], [\n''' % macro_prefix
         compatibilities['all'] = ['GPLv2+ build tool', 'GPLed build tool',
                                   'public domain', 'unlimited',
                                   'unmodifiable license text']
-        compatibilities['3']        = ['LGPLv2+', 'LGPLv3+ or GPLv2+', 'LGPLv3+', 'LGPL']
-        compatibilities['3orGPLv2'] = ['LGPLv2+', 'LGPLv3+ or GPLv2+']
-        compatibilities['2']        = ['LGPLv2+']
-        if lgpl:
+        compatibilities['GPLv3']         = ['LGPLv2+', 'LGPLv3+ or GPLv2+', 'LGPLv3+', 'LGPL', 'GPLv2+', 'GPLv3+', 'GPL']
+        compatibilities['GPLv2']         = ['LGPLv2+', 'LGPLv3+ or GPLv2+', 'GPLv2+']
+        compatibilities['LGPLv3']        = ['LGPLv2+', 'LGPLv3+ or GPLv2+', 'LGPLv3+', 'LGPL']
+        compatibilities['LGPLv3orGPLv2'] = ['LGPLv2+', 'LGPLv3+ or GPLv2+']
+        compatibilities['LGPLv2']        = ['LGPLv2+']
+        if lgpl or gpl:
             for module in main_modules:
                 license = module.getLicense()
                 if license not in compatibilities['all']:
                     if lgpl == True:
-                        if license not in compatibilities['3']:
+                        if license not in compatibilities['LGPLv3']:
+                            listing.append(tuple([module.name, license]))
+                    elif lgpl:
+                        if license not in compatibilities['LGPLv'+lgpl]:
                             listing.append(tuple([module.name, license]))
-                    else:
-                        if license not in compatibilities[lgpl]:
+                    elif gpl:
+                        if license not in compatibilities['GPLv'+gpl]:
                             listing.append(tuple([module.name, license]))
             if listing:
                 raise GLError(11, listing)
index a8277f2471ce133523b5b048af6e522bbd46980f..1ade11a3e1e4b8d1729ccca6ecb553797d20e172 100644 (file)
@@ -276,6 +276,8 @@ Options for --import, --add/remove-import:
                             Abort if modules aren't available under the LGPL.
                             The version number of the LGPL can be specified;
                             the default is currently LGPLv3.
+      --gpl=[2|3]           Abort if modules aren't available under the
+                            specified GPL version.
       --makefile-name=NAME  Name of makefile in the source-base and tests-base
                             directories (default \"Makefile.am\", or
                             \"Makefile.in\" if --gnu-make).
index e9855f775c5cbcac323528e50b166be37e4ecd78..4185765ab220b7929bee33fabbbd909efca778f5 100644 (file)
@@ -1000,7 +1000,9 @@ class GLModuleTable:
         '''Determine main module list and tests-related module list separately.
         The main module list is the transitive closure of the specified modules,
         ignoring tests modules. Its lib/* sources go into $sourcebase/. If lgpl is
-        specified, it will consist only of LGPLed source.
+        specified, it will consist only of LGPLed source; if gpl is specified, it
+        will consist of only source than can be relicensed under the specified GPL
+        version.
         The tests-related module list is the transitive closure of the specified
         modules, including tests modules, minus the main module list excluding
         modules of applicability 'all'. Its lib/* sources (brought in through
index f39a05bfd33f43521b7ae0880038a42434e78f86..f6aa9d47eaa7ff79119f7159a27e97e9ef26a287 100644 (file)
@@ -427,6 +427,12 @@ def main(temp_directory: str) -> None:
                         action='append',
                         choices=['2', '3orGPLv2', '3'],
                         nargs='?')
+    # gpl
+    parser.add_argument('--gpl',
+                        dest='gpl',
+                        default=None,
+                        choices=['2', '3'],
+                        nargs=1)
     # gnu-make
     parser.add_argument('--gnu-make',
                         dest='gnu_make',
@@ -714,7 +720,7 @@ def main(temp_directory: str) -> None:
                  or cmdargs.excl_privileged_tests != None
                  or cmdargs.excl_unportable_tests != None
                  or cmdargs.avoids != None or cmdargs.lgpl != None
-                 or cmdargs.makefile_name != None
+                 or cmdargs.gpl != None or cmdargs.makefile_name != None
                  or cmdargs.tests_makefile_name != None
                  or cmdargs.automake_subdir != None
                  or cmdargs.automake_subdir_tests != None
@@ -733,6 +739,13 @@ def main(temp_directory: str) -> None:
         message += '%s: *** Stop.\n' % APP['name']
         sys.stderr.write(message)
         sys.exit(1)
+    if cmdargs.lgpl != None and cmdargs.gpl != None:
+        message = '%s: *** ' % APP['name']
+        message += 'invalid options: cannot specify both --lgpl and --gpl\n'
+        message += 'Try \'gnulib-tool --help\' for more information.\n'
+        message += '%s: *** Stop.\n' % APP['name']
+        sys.stderr.write(message)
+        sys.exit(1)
     if cmdargs.pobase == None and cmdargs.podomain != None:
         message = 'gnulib-tool: warning: --po-domain has no effect without a --po-base option\n'
         sys.stderr.write(message)
@@ -808,6 +821,9 @@ def main(temp_directory: str) -> None:
         lgpl = lgpl[-1]
         if lgpl == None:
             lgpl = True
+    gpl = cmdargs.gpl
+    if gpl != None:
+        gpl = gpl[0]
     cond_dependencies = cmdargs.cond_dependencies
     libtool = cmdargs.libtool
     gnu_make = cmdargs.gnu_make == True
@@ -856,6 +872,7 @@ def main(temp_directory: str) -> None:
         excl_test_categories=excl_test_categories,
         libname=libname,
         lgpl=lgpl,
+        gpl=gpl,
         gnu_make=gnu_make,
         makefile_name=makefile_name,
         tests_makefile_name=tests_makefile_name,