Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package waf for openSUSE:Factory checked in at 2023-02-04 14:10:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/waf (Old) and /work/SRC/openSUSE:Factory/.waf.new.4462 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "waf" Sat Feb 4 14:10:59 2023 rev:2 rq:1062688 version:2.0.25 Changes: -------- --- /work/SRC/openSUSE:Factory/waf/waf.changes 2022-08-15 20:00:52.317503739 +0200 +++ /work/SRC/openSUSE:Factory/.waf.new.4462/waf.changes 2023-02-04 14:33:00.007649133 +0100 @@ -1,0 +2,12 @@ +Thu Jan 5 07:52:51 UTC 2023 - Dirk Müller <[email protected]> + +- update to 2.0.25: + * Fix invalid characters returned by find_program #2397 + * Prepare for distutils removal (Python 3.12 regression) #2402 + * Improve cp65001 compat in cpython < 3.3 #2346 + * Add Fujitsu Fortran compiler detection on ARM64FX #2348 + * Support multiple Sphinx output formats #2344 + * Improve PyQt5 detection #2343 + * Add asynchronous wafcache uploads + +------------------------------------------------------------------- Old: ---- waf-waf-2.0.24.tar.bz2 New: ---- waf-waf-2.0.25.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ waf.spec ++++++ --- /var/tmp/diff_new_pack.3biMS3/_old 2023-02-04 14:33:00.383651508 +0100 +++ /var/tmp/diff_new_pack.3biMS3/_new 2023-02-04 14:33:00.391651559 +0100 @@ -1,7 +1,7 @@ # # spec file for package waf # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: waf -Version: 2.0.24 +Version: 2.0.25 Release: 0 Summary: The Waf build system License: BSD-3-Clause ++++++ waf-waf-2.0.24.tar.bz2 -> waf-waf-2.0.25.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/ChangeLog new/waf-waf-2.0.25/ChangeLog --- old/waf-waf-2.0.24/ChangeLog 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/ChangeLog 2023-01-01 14:21:19.000000000 +0100 @@ -1,9 +1,19 @@ +NEW IN WAF 2.0.25 +----------------- +* Fix invalid characters returned by find_program #2397 +* Prepare for distutils removal (Python 3.12 regression) #2402 +* Improve cp65001 compat in cpython < 3.3 #2346 +* Add Fujitsu Fortran compiler detection on ARM64FX #2348 +* Support multiple Sphinx output formats #2344 +* Improve PyQt5 detection #2343 +* Add asynchronous wafcache uploads + NEW IN WAF 2.0.24 ----------------- * Use EXT_SUFFIX config var over the deprecated/removed SO (Python 3.11 regression) #2386 * When detecting Visual Studio compilers, prefer the oldest version regardless of compiler type #2352 * Update the MacOS-specific examples #2337 - +* Fix Configure.find_program() invalid character handling in default variable names #2397 NEW IN WAF 2.0.23 ----------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/docs/sphinx/conf.py new/waf-waf-2.0.25/docs/sphinx/conf.py --- old/waf-waf-2.0.24/docs/sphinx/conf.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/docs/sphinx/conf.py 2023-01-01 14:21:19.000000000 +0100 @@ -357,7 +357,7 @@ # General information about the project. project = u'Waf' -copyright = u'2005-2022, Thomas Nagy' +copyright = u'2005-2023, Thomas Nagy' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/playground/pyqt5/wscript new/waf-waf-2.0.25/playground/pyqt5/wscript --- old/waf-waf-2.0.24/playground/pyqt5/wscript 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/playground/pyqt5/wscript 2023-01-01 14:21:19.000000000 +0100 @@ -14,16 +14,19 @@ opt.load('python pyqt5') def configure(conf): + # Recent UIC/RCC versions require explicit python generator selection + conf.env.QT_PYUIC_FLAGS = ['-g', 'python'] + conf.env.QT_PYRCC_FLAGS = ['-g', 'python'] # Load also python to demonstrate mixed calls conf.load('python pyqt5') - conf.check_python_version((2,7,4)) + conf.check_python_version((2,7,4)) def build(bld): # Demonstrates mixed usage of py and pyqt5 module, and tests also install_path and install_from # (since generated files go into build it has to be reset inside the pyqt5 tool) - bld(features="py pyqt5", source="src/sample.py src/firstgui.ui", install_path="${PREFIX}/play/", install_from="src/") + bld(features="py pyqt5", source="src/sample.py src/firstgui.ui", install_path="${PREFIX}/play/", install_from="src/") - # Simple usage on a resource file. If a file referenced inside the resource changes it will be rebuilt + # Simple usage on a resource file. If a file referenced inside the resource changes it will be rebuilt # as the qrc XML is parsed and dependencies are calculated - bld(features="pyqt5", source="sampleRes.qrc") - + bld(features="pyqt5", source="sampleRes.qrc") + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/playground/sphinx/wscript new/waf-waf-2.0.25/playground/sphinx/wscript --- old/waf-waf-2.0.24/playground/sphinx/wscript 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/playground/sphinx/wscript 2023-01-01 14:21:19.000000000 +0100 @@ -7,4 +7,8 @@ def build(bld): - bld(features='sphinx', sphinx_source='src', sphinx_output_format='html') + # When multiple output format are given, the install_path_FMT can specify where to place a specific format, fallback is always on install_path + bld(features='sphinx', sphinx_source='src', sphinx_output_format=['html', 'info', 'man'], install_path_man='${DOCDIR}/man', install_path='${DOCDIR}') + + # Old style syntax, with single format + # bld(features='sphinx', sphinx_source='src', sphinx_output_format='man') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waf-light new/waf-waf-2.0.25/waf-light --- old/waf-waf-2.0.24/waf-light 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waf-light 2023-01-01 14:21:19.000000000 +0100 @@ -32,7 +32,7 @@ import os, sys, inspect -VERSION="2.0.24" +VERSION="2.0.25" REVISION="x" GIT="x" INSTALL="x" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/Configure.py new/waf-waf-2.0.25/waflib/Configure.py --- old/waf-waf-2.0.24/waflib/Configure.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/Configure.py 2023-01-01 14:21:19.000000000 +0100 @@ -439,7 +439,7 @@ var = kw.get('var', '') if not var: - var = re.sub(r'[-.]', '_', filename[0].upper()) + var = re.sub(r'\W', '_', filename[0].upper()) path_list = kw.get('path_list', '') if path_list: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/Context.py new/waf-waf-2.0.25/waflib/Context.py --- old/waf-waf-2.0.24/waflib/Context.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/Context.py 2023-01-01 14:21:19.000000000 +0100 @@ -18,13 +18,13 @@ import imp # the following 3 constants are updated on each new release (do not touch) -HEXVERSION=0x2001800 +HEXVERSION=0x2001900 """Constant updated on new releases""" -WAFVERSION="2.0.24" +WAFVERSION="2.0.25" """Constant updated on new releases""" -WAFREVISION="1af97c71f5a6756abf36d0f78ed8fd551596d7cb" +WAFREVISION="2db0b41b2805cd5db3b55476c06b23c1e46d319f" """Git revision when the waf version is updated""" WAFNAME="waf" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/TaskGen.py new/waf-waf-2.0.25/waflib/TaskGen.py --- old/waf-waf-2.0.24/waflib/TaskGen.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/TaskGen.py 2023-01-01 14:21:19.000000000 +0100 @@ -400,7 +400,7 @@ Decorator that registers a task generator method that will be executed when the object attribute ``feature`` contains the corresponding key(s):: - from waflib.Task import feature + from waflib.TaskGen import feature @feature('myfeature') def myfunction(self): print('that is my feature!') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/Tools/msvc.py new/waf-waf-2.0.25/waflib/Tools/msvc.py --- old/waf-waf-2.0.24/waflib/Tools/msvc.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/Tools/msvc.py 2023-01-01 14:21:19.000000000 +0100 @@ -111,7 +111,7 @@ class MSVCVersion(object): def __init__(self, ver): - m = re.search('^(.*)\s+(\d+[.]\d+)', ver) + m = re.search(r'^(.*)\s+(\d+[.]\d+)', ver) if m: self.name = m.group(1) self.number = float(m.group(2)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/Tools/python.py new/waf-waf-2.0.25/waflib/Tools/python.py --- old/waf-waf-2.0.24/waflib/Tools/python.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/Tools/python.py 2023-01-01 14:21:19.000000000 +0100 @@ -53,7 +53,17 @@ Piece of Python code used in :py:class:`waflib.Tools.python.pyo` and :py:class:`waflib.Tools.python.pyc` for byte-compiling python files """ -DISTUTILS_IMP = ['from distutils.sysconfig import get_config_var, get_python_lib'] +DISTUTILS_IMP = """ +try: + from distutils.sysconfig import get_config_var, get_python_lib +except ImportError: + from sysconfig import get_config_var, get_path + def get_python_lib(*k, **kw): + keyword='platlib' if kw.get('plat_specific') else 'purelib' + if 'prefix' in kw: + return get_path(keyword, vars={'installed_base': kw['prefix'], 'platbase': kw['prefix']}) + return get_path(keyword) +""".splitlines() @before_method('process_source') @feature('py') @@ -219,7 +229,7 @@ try: out = self.cmd_and_log(self.env.PYTHON + ['-c', '\n'.join(program)], env=os_env) except Errors.WafError: - self.fatal('The distutils module is unusable: install "python-devel"?') + self.fatal('Could not run %r' % self.env.PYTHON) self.to_log(out) return_values = [] for s in out.splitlines(): @@ -291,7 +301,8 @@ @conf def check_python_headers(conf, features='pyembed pyext'): """ - Check for headers and libraries necessary to extend or embed python by using the module *distutils*. + Check for headers and libraries necessary to extend or embed python. + It may use the module *distutils* or sysconfig in newer Python versions. On success the environment variables xxx_PYEXT and xxx_PYEMBED are added: * PYEXT: for compiling python extensions @@ -439,7 +450,7 @@ env.LIBPATH_PYEXT = env.LIBPATH_PYEMBED env.LIB_PYEXT = env.LIB_PYEMBED - conf.to_log("Include path for Python extensions (found via distutils module): %r\n" % (dct['INCLUDEPY'],)) + conf.to_log("Found an include path for Python extensions: %r\n" % (dct['INCLUDEPY'],)) env.INCLUDES_PYEXT = [dct['INCLUDEPY']] env.INCLUDES_PYEMBED = [dct['INCLUDEPY']] @@ -452,15 +463,21 @@ env.append_unique('CXXFLAGS_PYEXT', ['-fno-strict-aliasing']) if env.CC_NAME == "msvc": - from distutils.msvccompiler import MSVCCompiler - dist_compiler = MSVCCompiler() - dist_compiler.initialize() - env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options) - env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options) - env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared) + try: + from distutils.msvccompiler import MSVCCompiler + except ImportError: + # From https://github.com/python/cpython/blob/main/Lib/distutils/msvccompiler.py + env.append_value('CFLAGS_PYEXT', [ '/nologo', '/Ox', '/MD', '/W3', '/GX', '/DNDEBUG']) + env.append_value('CXXFLAGS_PYEXT', [ '/nologo', '/Ox', '/MD', '/W3', '/GX', '/DNDEBUG']) + env.append_value('LINKFLAGS_PYEXT', ['/DLL', '/nologo', '/INCREMENTAL:NO']) + else: + dist_compiler = MSVCCompiler() + dist_compiler.initialize() + env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options) + env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options) + env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared) - # See if it compiles - conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', uselib='PYEMBED', fragment=FRAG, errmsg='Distutils not installed? Broken python installation? Get python-config now!') + conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', uselib='PYEMBED', fragment=FRAG, errmsg='Could not build a Python embedded interpreter') @conf def check_python_version(conf, minver=None): @@ -506,17 +523,9 @@ else: # Finally, try to guess if Utils.is_win32: - (python_LIBDEST, pydir) = conf.get_python_variables( - ["get_config_var('LIBDEST') or ''", - "get_python_lib(standard_lib=0) or ''"]) + (pydir,) = conf.get_python_variables(["get_python_lib(standard_lib=0) or ''"]) else: - python_LIBDEST = None - (pydir,) = conf.get_python_variables( ["get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env.PREFIX]) - if python_LIBDEST is None: - if conf.env.LIBDIR: - python_LIBDEST = os.path.join(conf.env.LIBDIR, 'python' + pyver) - else: - python_LIBDEST = os.path.join(conf.env.PREFIX, 'lib', 'python' + pyver) + (pydir,) = conf.get_python_variables(["get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env.PREFIX]) if 'PYTHONARCHDIR' in conf.env: # Check if --pythonarchdir was specified @@ -526,7 +535,7 @@ pyarchdir = conf.environ['PYTHONARCHDIR'] else: # Finally, try to guess - (pyarchdir, ) = conf.get_python_variables( ["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''" % conf.env.PREFIX]) + (pyarchdir, ) = conf.get_python_variables(["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''" % conf.env.PREFIX]) if not pyarchdir: pyarchdir = pydir @@ -585,13 +594,12 @@ if ret == 'unknown version': conf.fatal('Could not check the %s version' % module_name) - from distutils.version import LooseVersion def num(*k): if isinstance(k[0], int): - return LooseVersion('.'.join([str(x) for x in k])) + return Utils.loose_version('.'.join([str(x) for x in k])) else: - return LooseVersion(k[0]) - d = {'num': num, 'ver': LooseVersion(ret)} + return Utils.loose_version(k[0]) + d = {'num': num, 'ver': Utils.loose_version(ret)} ev = eval(condition, {}, d) if not ev: conf.fatal('The %s version does not satisfy the requirements' % module_name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/Utils.py new/waf-waf-2.0.25/waflib/Utils.py --- old/waf-waf-2.0.24/waflib/Utils.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/Utils.py 2023-01-01 14:21:19.000000000 +0100 @@ -452,6 +452,8 @@ pass else: if codepage: + if 65001 == codepage and sys.version_info < (3, 3): + return 'utf-8' return 'cp%d' % codepage return sys.stdout.encoding or ('cp1252' if is_win32 else 'latin-1') @@ -868,6 +870,19 @@ return '64' return '' +def loose_version(ver_str): + # private for the time being! + # see #2402 + lst = re.split(r'([.]|\\d+|[a-zA-Z])', ver_str) + ver = [] + for i, val in enumerate(lst): + try: + ver.append(int(val)) + except ValueError: + if val != '.': + ver.append(val) + return ver + def sane_path(p): # private function for the time being! return os.path.abspath(os.path.expanduser(p)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/extras/cpplint.py new/waf-waf-2.0.25/waflib/extras/cpplint.py --- old/waf-waf-2.0.24/waflib/extras/cpplint.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/extras/cpplint.py 2023-01-01 14:21:19.000000000 +0100 @@ -169,7 +169,7 @@ global critical_errors with cpplint_wrapper(get_cpplint_logger(self.env.CPPLINT_OUTPUT), self.env.CPPLINT_BREAK, self.env.CPPLINT_OUTPUT): params = {key: str(self.env[key]) for key in self.env if 'CPPLINT_' in key} - if params['CPPLINT_OUTPUT'] is 'waf': + if params['CPPLINT_OUTPUT'] == 'waf': params['CPPLINT_OUTPUT'] = 'emacs' params['CPPLINT'] = self.env.get_flat('CPPLINT') cmd = Utils.subst_vars(CPPLINT_STR, params) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/extras/fc_fujitsu.py new/waf-waf-2.0.25/waflib/extras/fc_fujitsu.py --- old/waf-waf-2.0.24/waflib/extras/fc_fujitsu.py 1970-01-01 01:00:00.000000000 +0100 +++ new/waf-waf-2.0.25/waflib/extras/fc_fujitsu.py 2023-01-01 14:21:19.000000000 +0100 @@ -0,0 +1,52 @@ +#! /usr/bin/env python +# encoding: utf-8 +# Detection of the Fujitsu Fortran compiler for ARM64FX + +import re +from waflib.Tools import fc,fc_config,fc_scan +from waflib.Configure import conf +from waflib.Tools.compiler_fc import fc_compiler +fc_compiler['linux'].append('fc_fujitsu') + +@conf +def find_fujitsu(conf): + fc=conf.find_program(['frtpx'],var='FC') + conf.get_fujitsu_version(fc) + conf.env.FC_NAME='FUJITSU' + conf.env.FC_MOD_CAPITALIZATION='lower' + +@conf +def fujitsu_flags(conf): + v=conf.env + v['_FCMODOUTFLAGS']=[] + v['FCFLAGS_DEBUG']=[] + v['FCFLAGS_fcshlib']=[] + v['LINKFLAGS_fcshlib']=[] + v['FCSTLIB_MARKER']='' + v['FCSHLIB_MARKER']='' + +@conf +def get_fujitsu_version(conf,fc): + version_re=re.compile(r"frtpx\s*\(FRT\)\s*(?P<major>\d+)\.(?P<minor>\d+)\.",re.I).search + cmd=fc+['--version'] + out,err=fc_config.getoutput(conf,cmd,stdin=False) + if out: + match=version_re(out) + else: + match=version_re(err) + if not match: + return(False) + conf.fatal('Could not determine the Fujitsu FRT Fortran compiler version.') + else: + k=match.groupdict() + conf.env['FC_VERSION']=(k['major'],k['minor']) + +def configure(conf): + conf.find_fujitsu() + conf.find_program('ar',var='AR') + conf.add_os_flags('ARFLAGS') + if not conf.env.ARFLAGS: + conf.env.ARFLAGS=['rcs'] + conf.fc_flags() + conf.fc_add_flags() + conf.fujitsu_flags() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/extras/gccdeps.py new/waf-waf-2.0.25/waflib/extras/gccdeps.py --- old/waf-waf-2.0.24/waflib/extras/gccdeps.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/extras/gccdeps.py 2023-01-01 14:21:19.000000000 +0100 @@ -17,7 +17,7 @@ import os, re, threading from waflib import Task, Logs, Utils, Errors -from waflib.Tools import c_preproc +from waflib.Tools import asm, c, c_preproc, cxx from waflib.TaskGen import before_method, feature lock = threading.Lock() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/extras/pyqt5.py new/waf-waf-2.0.25/waflib/extras/pyqt5.py --- old/waf-waf-2.0.24/waflib/extras/pyqt5.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/extras/pyqt5.py 2023-01-01 14:21:19.000000000 +0100 @@ -1,6 +1,6 @@ #!/usr/bin/env python # encoding: utf-8 -# Federico Pellegrin, 2016-2019 (fedepell) adapted for Python +# Federico Pellegrin, 2016-2022 (fedepell) adapted for Python """ This tool helps with finding Python Qt5 tools and libraries, @@ -137,7 +137,7 @@ Processes ``.qrc`` files """ color = 'BLUE' - run_str = '${QT_PYRCC} ${SRC} -o ${TGT}' + run_str = '${QT_PYRCC} ${QT_PYRCC_FLAGS} ${SRC} -o ${TGT}' ext_out = ['.py'] def rcname(self): @@ -175,7 +175,7 @@ Processes ``.ui`` files for python """ color = 'BLUE' - run_str = '${QT_PYUIC} ${SRC} -o ${TGT}' + run_str = '${QT_PYUIC} ${QT_PYUIC_FLAGS} ${SRC} -o ${TGT}' ext_out = ['.py'] class ts2qm(Task.Task): @@ -216,17 +216,17 @@ self.find_program(['pyrcc5'], var='QT_PYRCC') self.find_program(['pylupdate5'], var='QT_PYLUPDATE') elif getattr(Options.options, 'want_pyside2', True): - self.find_program(['pyside2-uic'], var='QT_PYUIC') - self.find_program(['pyside2-rcc'], var='QT_PYRCC') - self.find_program(['pyside2-lupdate'], var='QT_PYLUPDATE') + self.find_program(['pyside2-uic','uic-qt5'], var='QT_PYUIC') + self.find_program(['pyside2-rcc','rcc-qt5'], var='QT_PYRCC') + self.find_program(['pyside2-lupdate','lupdate-qt5'], var='QT_PYLUPDATE') elif getattr(Options.options, 'want_pyqt4', True): self.find_program(['pyuic4'], var='QT_PYUIC') self.find_program(['pyrcc4'], var='QT_PYRCC') self.find_program(['pylupdate4'], var='QT_PYLUPDATE') else: - self.find_program(['pyuic5','pyside2-uic','pyuic4'], var='QT_PYUIC') - self.find_program(['pyrcc5','pyside2-rcc','pyrcc4'], var='QT_PYRCC') - self.find_program(['pylupdate5', 'pyside2-lupdate','pylupdate4'], var='QT_PYLUPDATE') + self.find_program(['pyuic5','pyside2-uic','pyuic4','uic-qt5'], var='QT_PYUIC') + self.find_program(['pyrcc5','pyside2-rcc','pyrcc4','rcc-qt5'], var='QT_PYRCC') + self.find_program(['pylupdate5', 'pyside2-lupdate','pylupdate4','lupdate-qt5'], var='QT_PYLUPDATE') if not env.QT_PYUIC: self.fatal('cannot find the uic compiler for python for qt5') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/extras/sphinx.py new/waf-waf-2.0.25/waflib/extras/sphinx.py --- old/waf-waf-2.0.24/waflib/extras/sphinx.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/extras/sphinx.py 2023-01-01 14:21:19.000000000 +0100 @@ -1,7 +1,15 @@ """Support for Sphinx documentation -This is a wrapper for sphinx-build program. Please note that sphinx-build supports only one output format which can -passed to build via sphinx_output_format attribute. The default output format is html. +This is a wrapper for sphinx-build program. Please note that sphinx-build supports only +one output format at a time, but the tool can create multiple tasks to handle more. +The output formats can be passed via the sphinx_output_format, which is an array of +strings. For backwards compatibility if only one output is needed, it can be passed +as a single string. +The default output format is html. + +Specific formats can be installed in different directories by specifying the +install_path_<FORMAT> attribute. If not defined, the standard install_path +will be used instead. Example wscript: @@ -13,7 +21,8 @@ features='sphinx', sphinx_source='sources', # path to source directory sphinx_options='-a -v', # sphinx-build program additional options - sphinx_output_format='man' # output format of sphinx documentation + sphinx_output_format=['html', 'man'], # output format of sphinx documentation + install_path_man='${DOCDIR}/man' # put man pages in a specific directory ) """ @@ -43,30 +52,36 @@ if not self.sphinx_source: self.bld.fatal('Can\'t find sphinx_source: %r' % self.sphinx_source) + # In the taskgen we have the complete list of formats Utils.def_attrs(self, sphinx_output_format='html') - self.env.SPHINX_OUTPUT_FORMAT = self.sphinx_output_format + self.sphinx_output_format = Utils.to_list(self.sphinx_output_format) + self.env.SPHINX_OPTIONS = getattr(self, 'sphinx_options', []) for source_file in self.sphinx_source.ant_glob('**/*'): self.bld.add_manual_dependency(self.sphinx_source, source_file) - sphinx_build_task = self.create_task('SphinxBuildingTask') - sphinx_build_task.set_inputs(self.sphinx_source) - sphinx_build_task.set_outputs(self.path.get_bld()) - - # the sphinx-build results are in <build + output_format> directory - self.sphinx_output_directory = self.path.get_bld().make_node(self.env.SPHINX_OUTPUT_FORMAT) - self.sphinx_output_directory.mkdir() - Utils.def_attrs(self, install_path=get_install_path(self)) - - -def get_install_path(tg): - if tg.env.SPHINX_OUTPUT_FORMAT == 'man': - return tg.env.MANDIR - elif tg.env.SPHINX_OUTPUT_FORMAT == 'info': - return tg.env.INFODIR + for cfmt in self.sphinx_output_format: + sphinx_build_task = self.create_task('SphinxBuildingTask') + sphinx_build_task.set_inputs(self.sphinx_source) + # In task we keep the specific format this task is generating + sphinx_build_task.env.SPHINX_OUTPUT_FORMAT = cfmt + + # the sphinx-build results are in <build + output_format> directory + sphinx_build_task.sphinx_output_directory = self.path.get_bld().make_node(cfmt) + sphinx_build_task.set_outputs(sphinx_build_task.sphinx_output_directory) + sphinx_build_task.sphinx_output_directory.mkdir() + + Utils.def_attrs(sphinx_build_task, install_path=getattr(self, 'install_path_' + cfmt, getattr(self, 'install_path', get_install_path(sphinx_build_task)))) + + +def get_install_path(object): + if object.env.SPHINX_OUTPUT_FORMAT == 'man': + return object.env.MANDIR + elif object.env.SPHINX_OUTPUT_FORMAT == 'info': + return object.env.INFODIR else: - return tg.env.DOCDIR + return object.env.DOCDIR class SphinxBuildingTask(Task.Task): @@ -96,10 +111,10 @@ def add_install(self): - nodes = self.generator.sphinx_output_directory.ant_glob('**/*', quiet=True) + nodes = self.sphinx_output_directory.ant_glob('**/*', quiet=True) self.outputs += nodes - self.generator.add_install_files(install_to=self.generator.install_path, + self.generator.add_install_files(install_to=self.install_path, install_from=nodes, postpone=False, - cwd=self.generator.sphinx_output_directory, + cwd=self.sphinx_output_directory.make_node(self.env.SPHINX_OUTPUT_FORMAT), relative_trick=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/waflib/extras/wafcache.py new/waf-waf-2.0.25/waflib/extras/wafcache.py --- old/waf-waf-2.0.24/waflib/extras/wafcache.py 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/waflib/extras/wafcache.py 2023-01-01 14:21:19.000000000 +0100 @@ -39,7 +39,14 @@ * WAFCACHE_TRIM_MAX_FOLDER: maximum amount of tasks to cache (1M) * WAFCACHE_EVICT_MAX_BYTES: maximum amount of cache size in bytes (10GB) * WAFCACHE_EVICT_INTERVAL_MINUTES: minimum time interval to try - and trim the cache (3 minutess) + and trim the cache (3 minutes) + +Upload specific options: +* WAFCACHE_ASYNC_WORKERS: define a number of workers to upload results asynchronously + this may improve build performance with many/long file uploads + the default is unset (synchronous uploads) +* WAFCACHE_ASYNC_NOWAIT: do not wait for uploads to complete (default: False) + this requires asynchonous uploads to have an effect Usage:: @@ -49,10 +56,10 @@ To troubleshoot:: - waf clean build --zones=wafcache + waf clean build --zone=wafcache """ -import atexit, base64, errno, fcntl, getpass, os, re, shutil, sys, time, traceback, urllib3, shlex +import atexit, base64, errno, fcntl, getpass, os, re, shutil, sys, time, threading, traceback, urllib3, shlex try: import subprocess32 as subprocess except ImportError: @@ -71,6 +78,8 @@ WAFCACHE_NO_PUSH = 1 if os.environ.get('WAFCACHE_NO_PUSH') else 0 WAFCACHE_VERBOSITY = 1 if os.environ.get('WAFCACHE_VERBOSITY') else 0 WAFCACHE_STATS = 1 if os.environ.get('WAFCACHE_STATS') else 0 +WAFCACHE_ASYNC_WORKERS = os.environ.get('WAFCACHE_ASYNC_WORKERS') +WAFCACHE_ASYNC_NOWAIT = os.environ.get('WAFCACHE_ASYNC_NOWAIT') OK = "ok" re_waf_cmd = re.compile('(?P<src>%{SRC})|(?P<tgt>%{TGT})') @@ -99,7 +108,9 @@ self.generator.bld.cache_reqs += 1 files_to = [node.abspath() for node in self.outputs] - err = cache_command(ssig, [], files_to) + proc = get_process() + err = cache_command(proc, ssig, [], files_to) + process_pool.append(proc) if err.startswith(OK): if WAFCACHE_VERBOSITY: Logs.pprint('CYAN', ' Fetched %r from cache' % files_to) @@ -132,23 +143,50 @@ files_from.append(path) bld = self.generator.bld + old_sig = self.signature() + + for node in self.inputs: + try: + del node.ctx.cache_sig[node] + except KeyError: + pass + + delattr(self, 'cache_sig') sig = self.signature() - ssig = Utils.to_hex(self.uid() + sig) - err = cache_command(ssig, files_from, []) + def _async_put_files_cache(bld, ssig, files_from): + proc = get_process() + if WAFCACHE_ASYNC_WORKERS: + with bld.wafcache_lock: + if bld.wafcache_stop: + process_pool.append(proc) + return + bld.wafcache_procs.add(proc) + + err = cache_command(proc, ssig, files_from, []) + process_pool.append(proc) + if err.startswith(OK): + if WAFCACHE_VERBOSITY: + Logs.pprint('CYAN', ' Successfully uploaded %s to cache' % files_from) + else: + Logs.debug('wafcache: Successfully uploaded %r to cache', files_from) + if WAFCACHE_STATS: + bld.cache_puts += 1 + else: + if WAFCACHE_VERBOSITY: + Logs.pprint('RED', ' Error caching step results %s: %s' % (files_from, err)) + else: + Logs.debug('wafcache: Error caching results %s: %s', files_from, err) - if err.startswith(OK): - if WAFCACHE_VERBOSITY: - Logs.pprint('CYAN', ' Successfully uploaded %s to cache' % files_from) + if old_sig == sig: + ssig = Utils.to_hex(self.uid() + sig) + if WAFCACHE_ASYNC_WORKERS: + fut = bld.wafcache_executor.submit(_async_put_files_cache, bld, ssig, files_from) + bld.wafcache_uploads.append(fut) else: - Logs.debug('wafcache: Successfully uploaded %r to cache', files_from) - if WAFCACHE_STATS: - self.generator.bld.cache_puts += 1 + _async_put_files_cache(bld, ssig, files_from) else: - if WAFCACHE_VERBOSITY: - Logs.pprint('RED', ' Error caching step results %s: %s' % (files_from, err)) - else: - Logs.debug('wafcache: Error caching results %s: %s', files_from, err) + Logs.debug('wafcache: skipped %r upload due to late input modifications %r', self.outputs, self.inputs) bld.task_sigs[self.uid()] = self.cache_sig @@ -245,19 +283,45 @@ return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0) def atexit_pool(): - for k in process_pool: - try: - os.kill(k.pid, 9) - except OSError: - pass - else: - k.wait() + for proc in process_pool: + proc.kill() atexit.register(atexit_pool) def build(bld): """ Called during the build process to enable file caching """ + + if WAFCACHE_ASYNC_WORKERS: + try: + num_workers = int(WAFCACHE_ASYNC_WORKERS) + except ValueError: + Logs.warn('Invalid WAFCACHE_ASYNC_WORKERS specified: %r' % WAFCACHE_ASYNC_WORKERS) + else: + from concurrent.futures import ThreadPoolExecutor + bld.wafcache_executor = ThreadPoolExecutor(max_workers=num_workers) + bld.wafcache_uploads = [] + bld.wafcache_procs = set([]) + bld.wafcache_stop = False + bld.wafcache_lock = threading.Lock() + + def finalize_upload_async(bld): + if WAFCACHE_ASYNC_NOWAIT: + with bld.wafcache_lock: + bld.wafcache_stop = True + + for fut in reversed(bld.wafcache_uploads): + fut.cancel() + + for proc in bld.wafcache_procs: + proc.kill() + + bld.wafcache_procs.clear() + else: + Logs.pprint('CYAN', '... waiting for wafcache uploads to complete (%s uploads)' % len(bld.wafcache_uploads)) + bld.wafcache_executor.shutdown(wait=True) + bld.add_post_fun(finalize_upload_async) + if WAFCACHE_STATS: # Init counter for statistics and hook to print results at the end bld.cache_reqs = bld.cache_hits = bld.cache_puts = 0 @@ -266,9 +330,8 @@ hit_ratio = 0 if bld.cache_reqs > 0: hit_ratio = (bld.cache_hits / bld.cache_reqs) * 100 - Logs.pprint('CYAN', ' wafcache stats: requests: %s, hits, %s, ratio: %.2f%%, writes %s' % + Logs.pprint('CYAN', ' wafcache stats: %s requests, %s hits (ratio: %.2f%%), %s writes' % (bld.cache_reqs, bld.cache_hits, hit_ratio, bld.cache_puts) ) - bld.add_post_fun(printstats) if process_pool: @@ -286,15 +349,13 @@ for x in reversed(list(Task.classes.values())): make_cached(x) -def cache_command(sig, files_from, files_to): +def cache_command(proc, sig, files_from, files_to): """ Create a command for cache worker processes, returns a pickled base64-encoded tuple containing the task signature, a list of files to cache and a list of files files to get from cache (one of the lists is assumed to be empty) """ - proc = get_process() - obj = base64.b64encode(cPickle.dumps([sig, files_from, files_to])) proc.stdin.write(obj) proc.stdin.write('\n'.encode()) @@ -302,7 +363,6 @@ obj = proc.stdout.readline() if not obj: raise OSError('Preforked sub-process %r died' % proc.pid) - process_pool.append(proc) return cPickle.loads(base64.b64decode(obj)) try: @@ -456,7 +516,10 @@ class fcache(object): def __init__(self): if not os.path.exists(CACHE_DIR): - os.makedirs(CACHE_DIR) + try: + os.makedirs(CACHE_DIR) + except OSError: + pass if not os.path.exists(CACHE_DIR): raise ValueError('Could not initialize the cache directory') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/waf-waf-2.0.24/wscript new/waf-waf-2.0.25/wscript --- old/waf-waf-2.0.24/wscript 2022-05-22 15:43:52.000000000 +0200 +++ new/waf-waf-2.0.25/wscript 2023-01-01 14:21:19.000000000 +0100 @@ -11,7 +11,7 @@ from __future__ import with_statement -VERSION="2.0.24" +VERSION="2.0.25" APPNAME='waf' REVISION=''
