diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2017-09-29 20:35:09 +0300 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2017-09-29 20:35:09 +0300 |
commit | 377002e7300431b68f3548d9fd2c7f99cf883939 (patch) | |
tree | d167dd4a5d88ebbc3e2d5cea061848d7ee8f6e89 /debian/patches | |
download | python3.8-377002e7300431b68f3548d9fd2c7f99cf883939.tar.gz |
Imported python3.6 3.6.3~rc1debian/3.6.3_rc1
Diffstat (limited to 'debian/patches')
37 files changed, 1879 insertions, 0 deletions
diff --git a/debian/patches/bdist-wininst-notfound.diff b/debian/patches/bdist-wininst-notfound.diff new file mode 100644 index 0000000..27e9024 --- /dev/null +++ b/debian/patches/bdist-wininst-notfound.diff @@ -0,0 +1,19 @@ +# DP: suggest installation of the pythonX.Y-dev package, if bdist_wininst +# DP: cannot find the wininst-* files. + +Index: b/Lib/distutils/command/bdist_wininst.py +=================================================================== +--- a/Lib/distutils/command/bdist_wininst.py ++++ b/Lib/distutils/command/bdist_wininst.py +@@ -358,7 +358,10 @@ class bdist_wininst(Command): + sfix = '' + + filename = os.path.join(directory, "wininst-%s%s.exe" % (bv, sfix)) +- f = open(filename, "rb") ++ try: ++ f = open(filename, "rb") ++ except IOError as e: ++ raise DistutilsFileError(str(e) + ', %s not included in the Debian packages.' % filename) + try: + return f.read() + finally: diff --git a/debian/patches/ctypes-arm.diff b/debian/patches/ctypes-arm.diff new file mode 100644 index 0000000..5be98b6 --- /dev/null +++ b/debian/patches/ctypes-arm.diff @@ -0,0 +1,34 @@ +Index: b/Lib/ctypes/util.py +=================================================================== +--- a/Lib/ctypes/util.py ++++ b/Lib/ctypes/util.py +@@ -247,16 +247,27 @@ elif os.name == "posix": + + def _findSoname_ldconfig(name): + import struct ++ # XXX this code assumes that we know all unames and that a single ++ # ABI is supported per uname; instead we should find what the ++ # ABI is (e.g. check ABI of current process) or simply ask libc ++ # to load the library for us ++ uname = os.uname() ++ # ARM has a variety of unames, e.g. armv7l ++ if uname.machine.startswith("arm"): ++ machine = "arm" + if struct.calcsize('l') == 4: +- machine = os.uname().machine + '-32' ++ machine = uname.machine + '-32' + else: +- machine = os.uname().machine + '-64' ++ machine = uname.machine + '-64' + mach_map = { + 'x86_64-64': 'libc6,x86-64', + 'ppc64-64': 'libc6,64bit', + 'sparc64-64': 'libc6,64bit', + 's390x-64': 'libc6,64bit', + 'ia64-64': 'libc6,IA-64', ++ # this actually breaks on biarch or multiarch as the first ++ # library wins; uname doesn't tell us which ABI we're using ++ 'arm-32': 'libc6(,hard-float)?', + } + abi_type = mach_map.get(machine, 'libc6') + diff --git a/debian/patches/deb-locations.diff b/debian/patches/deb-locations.diff new file mode 100644 index 0000000..b3b2ad9 --- /dev/null +++ b/debian/patches/deb-locations.diff @@ -0,0 +1,30 @@ +# DP: adjust locations of directories to debian policy + +Index: b/Lib/pydoc.py +=================================================================== +--- a/Lib/pydoc.py ++++ b/Lib/pydoc.py +@@ -28,6 +28,10 @@ to a file named "<name>.html". + + Module docs for core modules are assumed to be in + ++ /usr/share/doc/pythonX.Y/html/library ++ ++if the pythonX.Y-doc package is installed or in ++ + https://docs.python.org/X.Y/library/ + + This can be overridden by setting the PYTHONDOCS environment variable +Index: b/Misc/python.man +=================================================================== +--- a/Misc/python.man ++++ b/Misc/python.man +@@ -327,7 +327,7 @@ exception). Error messages are written + These are subject to difference depending on local installation + conventions; ${prefix} and ${exec_prefix} are installation-dependent + and should be interpreted as for GNU software; they may be the same. +-The default for both is \fI/usr/local\fP. ++On Debian GNU/{Hurd,Linux} the default for both is \fI/usr\fP. + .IP \fI${exec_prefix}/bin/python\fP + Recommended location of the interpreter. + .PP diff --git a/debian/patches/deb-setup.diff b/debian/patches/deb-setup.diff new file mode 100644 index 0000000..08ce316 --- /dev/null +++ b/debian/patches/deb-setup.diff @@ -0,0 +1,33 @@ +# DP: Don't include /usr/local/include and /usr/local/lib as gcc search paths + +Index: b/setup.py +=================================================================== +--- a/setup.py ++++ b/setup.py +@@ -262,8 +262,10 @@ class PyBuildExt(build_ext): + # unfortunately, distutils doesn't let us provide separate C and C++ + # compilers + if compiler is not None: +- (ccshared,cflags) = sysconfig.get_config_vars('CCSHARED','CFLAGS') +- args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags ++ (ccshared, cppflags, cflags) = \ ++ sysconfig.get_config_vars('CCSHARED', 'CPPFLAGS', 'CFLAGS') ++ cppflags = ' '.join([f for f in cppflags.split() if not f.startswith('-I')]) ++ args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cppflags + ' ' + cflags + self.compiler.set_executables(**args) + + build_ext.build_extensions(self) +@@ -487,12 +489,7 @@ class PyBuildExt(build_ext): + return ['m'] + + def detect_modules(self): +- # Ensure that /usr/local is always used, but the local build +- # directories (i.e. '.' and 'Include') must be first. See issue +- # 10520. +- if not cross_compiling: +- add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') +- add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') ++ # On Debian /usr/local is always used, so we don't include it twice + # only change this for cross builds for 3.3, issues on Mageia + if cross_compiling: + self.add_gcc_paths() diff --git a/debian/patches/disable-sem-check.diff b/debian/patches/disable-sem-check.diff new file mode 100644 index 0000000..cb1630f --- /dev/null +++ b/debian/patches/disable-sem-check.diff @@ -0,0 +1,38 @@ +# DP: Assume working semaphores, don't rely on running kernel for the check. + +Index: b/configure.ac +=================================================================== +--- a/configure.ac ++++ b/configure.ac +@@ -4496,8 +4496,13 @@ int main(void) { + AC_MSG_RESULT($ac_cv_posix_semaphores_enabled) + if test $ac_cv_posix_semaphores_enabled = no + then +- AC_DEFINE(POSIX_SEMAPHORES_NOT_ENABLED, 1, +- [Define if POSIX semaphores aren't enabled on your system]) ++ case $ac_sys_system in ++ Linux*) # assume yes, see https://launchpad.net/bugs/630511 ++ ;; ++ *) ++ AC_DEFINE(POSIX_SEMAPHORES_NOT_ENABLED, 1, ++ [Define if POSIX semaphores aren't enabled on your system]) ++ esac + fi + + # Multiprocessing check for broken sem_getvalue +@@ -4532,8 +4537,13 @@ int main(void){ + AC_MSG_RESULT($ac_cv_broken_sem_getvalue) + if test $ac_cv_broken_sem_getvalue = yes + then +- AC_DEFINE(HAVE_BROKEN_SEM_GETVALUE, 1, +- [define to 1 if your sem_getvalue is broken.]) ++ case $ac_sys_system in ++ Linux*) # assume yes, see https://launchpad.net/bugs/630511 ++ ;; ++ *) ++ AC_DEFINE(HAVE_BROKEN_SEM_GETVALUE, 1, ++ [define to 1 if your sem_getvalue is broken.]) ++ esac + fi + + AC_CHECK_DECLS([RTLD_LAZY, RTLD_NOW, RTLD_GLOBAL, RTLD_LOCAL, RTLD_NODELETE, RTLD_NOLOAD, RTLD_DEEPBIND], [], [], [[#include <dlfcn.h>]]) diff --git a/debian/patches/disable-some-tests.diff b/debian/patches/disable-some-tests.diff new file mode 100644 index 0000000..ddec2cd --- /dev/null +++ b/debian/patches/disable-some-tests.diff @@ -0,0 +1,14 @@ +# DP: Disable some failing tests we are not interested in + +Index: b/Lib/distutils/tests/test_build_ext.py +=================================================================== +--- a/Lib/distutils/tests/test_build_ext.py ++++ b/Lib/distutils/tests/test_build_ext.py +@@ -102,6 +102,7 @@ class BuildExtTestCase(TempdirManager, + build_ext.USER_BASE = self.old_user_base + super(BuildExtTestCase, self).tearDown() + ++ @unittest.skip('Skipping failing Solaris test') + def test_solaris_enable_shared(self): + dist = Distribution({'name': 'xx'}) + cmd = self.build_ext(dist) diff --git a/debian/patches/distutils-install-layout.diff b/debian/patches/distutils-install-layout.diff new file mode 100644 index 0000000..9ca8b00 --- /dev/null +++ b/debian/patches/distutils-install-layout.diff @@ -0,0 +1,278 @@ +# DP: distutils: Add an option --install-layout=deb, which +# DP: - installs into $prefix/dist-packages instead of $prefix/site-packages. +# DP: - doesn't encode the python version into the egg name. + +Index: b/Lib/distutils/command/install_egg_info.py +=================================================================== +--- a/Lib/distutils/command/install_egg_info.py ++++ b/Lib/distutils/command/install_egg_info.py +@@ -14,18 +14,38 @@ class install_egg_info(Command): + description = "Install package's PKG-INFO metadata as an .egg-info file" + user_options = [ + ('install-dir=', 'd', "directory to install to"), ++ ('install-layout', None, "custom installation layout"), + ] + + def initialize_options(self): + self.install_dir = None ++ self.install_layout = None ++ self.prefix_option = None + + def finalize_options(self): + self.set_undefined_options('install_lib',('install_dir','install_dir')) +- basename = "%s-%s-py%d.%d.egg-info" % ( +- to_filename(safe_name(self.distribution.get_name())), +- to_filename(safe_version(self.distribution.get_version())), +- *sys.version_info[:2] +- ) ++ self.set_undefined_options('install',('install_layout','install_layout')) ++ self.set_undefined_options('install',('prefix_option','prefix_option')) ++ if self.install_layout: ++ if not self.install_layout.lower() in ['deb', 'unix']: ++ raise DistutilsOptionError( ++ "unknown value for --install-layout") ++ no_pyver = (self.install_layout.lower() == 'deb') ++ elif self.prefix_option: ++ no_pyver = False ++ else: ++ no_pyver = True ++ if no_pyver: ++ basename = "%s-%s.egg-info" % ( ++ to_filename(safe_name(self.distribution.get_name())), ++ to_filename(safe_version(self.distribution.get_version())) ++ ) ++ else: ++ basename = "%s-%s-py%d.%d.egg-info" % ( ++ to_filename(safe_name(self.distribution.get_name())), ++ to_filename(safe_version(self.distribution.get_version())), ++ *sys.version_info[:2] ++ ) + self.target = os.path.join(self.install_dir, basename) + self.outputs = [self.target] + +Index: b/Lib/distutils/command/install.py +=================================================================== +--- a/Lib/distutils/command/install.py ++++ b/Lib/distutils/command/install.py +@@ -35,6 +35,20 @@ INSTALL_SCHEMES = { + 'scripts': '$base/bin', + 'data' : '$base', + }, ++ 'unix_local': { ++ 'purelib': '$base/local/lib/python$py_version_short/dist-packages', ++ 'platlib': '$platbase/local/lib/python$py_version_short/dist-packages', ++ 'headers': '$base/local/include/python$py_version_short/$dist_name', ++ 'scripts': '$base/local/bin', ++ 'data' : '$base/local', ++ }, ++ 'deb_system': { ++ 'purelib': '$base/lib/python3/dist-packages', ++ 'platlib': '$platbase/lib/python3/dist-packages', ++ 'headers': '$base/include/python$py_version_short/$dist_name', ++ 'scripts': '$base/bin', ++ 'data' : '$base', ++ }, + 'unix_home': { + 'purelib': '$base/lib/python', + 'platlib': '$base/lib/python', +@@ -131,6 +145,9 @@ class install(Command): + + ('record=', None, + "filename in which to record list of installed files"), ++ ++ ('install-layout=', None, ++ "installation layout to choose (known values: deb, unix)"), + ] + + boolean_options = ['compile', 'force', 'skip-build'] +@@ -151,6 +168,7 @@ class install(Command): + self.exec_prefix = None + self.home = None + self.user = 0 ++ self.prefix_option = None + + # These select only the installation base; it's up to the user to + # specify the installation scheme (currently, that means supplying +@@ -172,6 +190,9 @@ class install(Command): + self.install_userbase = USER_BASE + self.install_usersite = USER_SITE + ++ # enable custom installation, known values: deb ++ self.install_layout = None ++ + self.compile = None + self.optimize = None + +@@ -413,6 +434,7 @@ class install(Command): + self.install_base = self.install_platbase = self.home + self.select_scheme("unix_home") + else: ++ self.prefix_option = self.prefix + if self.prefix is None: + if self.exec_prefix is not None: + raise DistutilsOptionError( +@@ -427,7 +449,26 @@ class install(Command): + + self.install_base = self.prefix + self.install_platbase = self.exec_prefix +- self.select_scheme("unix_prefix") ++ if self.install_layout: ++ if self.install_layout.lower() in ['deb']: ++ self.select_scheme("deb_system") ++ elif self.install_layout.lower() in ['unix']: ++ self.select_scheme("unix_prefix") ++ else: ++ raise DistutilsOptionError( ++ "unknown value for --install-layout") ++ elif ((self.prefix_option and ++ os.path.normpath(self.prefix) != '/usr/local') ++ or sys.base_prefix != sys.prefix ++ or 'PYTHONUSERBASE' in os.environ ++ or 'VIRTUAL_ENV' in os.environ ++ or 'real_prefix' in sys.__dict__): ++ self.select_scheme("unix_prefix") ++ else: ++ if os.path.normpath(self.prefix) == '/usr/local': ++ self.prefix = self.exec_prefix = '/usr' ++ self.install_base = self.install_platbase = '/usr' ++ self.select_scheme("unix_local") + + def finalize_other(self): + """Finalizes options for non-posix platforms""" +Index: b/Lib/distutils/sysconfig.py +=================================================================== +--- a/Lib/distutils/sysconfig.py ++++ b/Lib/distutils/sysconfig.py +@@ -122,6 +122,7 @@ def get_python_lib(plat_specific=0, stan + If 'prefix' is supplied, use it instead of sys.base_prefix or + sys.base_exec_prefix -- i.e., ignore 'plat_specific'. + """ ++ is_default_prefix = not prefix or os.path.normpath(prefix) in ('/usr', '/usr/local') + if prefix is None: + if standard_lib: + prefix = plat_specific and BASE_EXEC_PREFIX or BASE_PREFIX +@@ -133,6 +134,12 @@ def get_python_lib(plat_specific=0, stan + "lib", "python" + get_python_version()) + if standard_lib: + return libpython ++ elif (is_default_prefix and ++ 'PYTHONUSERBASE' not in os.environ and ++ 'VIRTUAL_ENV' not in os.environ and ++ 'real_prefix' not in sys.__dict__ and ++ sys.prefix == sys.base_prefix): ++ return os.path.join(prefix, "lib", "python3", "dist-packages") + else: + return os.path.join(libpython, "site-packages") + elif os.name == "nt": +Index: b/Lib/site.py +=================================================================== +--- a/Lib/site.py ++++ b/Lib/site.py +@@ -7,12 +7,18 @@ + This will append site-specific paths to the module search path. On + Unix (including Mac OSX), it starts with sys.prefix and + sys.exec_prefix (if different) and appends +-lib/python<version>/site-packages. ++lib/python3/dist-packages. + On other platforms (such as Windows), it tries each of the + prefixes directly, as well as with lib/site-packages appended. The + resulting directories, if they exist, are appended to sys.path, and + also inspected for path configuration files. + ++For Debian and derivatives, this sys.path is augmented with directories ++for packages distributed within the distribution. Local addons go ++into /usr/local/lib/python<version>/dist-packages, Debian addons ++install into /usr/lib/python3/dist-packages. ++/usr/lib/python<version>/site-packages is not used. ++ + If a file named "pyvenv.cfg" exists one directory above sys.executable, + sys.prefix and sys.exec_prefix are set to that directory and + it is also checked for site-packages (sys.base_prefix and +@@ -304,9 +310,20 @@ def getsitepackages(prefixes=None): + seen.add(prefix) + + if os.sep == '/': ++ if 'VIRTUAL_ENV' in os.environ or sys.base_prefix != sys.prefix: ++ sitepackages.append(os.path.join(prefix, "lib", ++ "python" + sys.version[:3], ++ "site-packages")) ++ sitepackages.append(os.path.join(prefix, "local/lib", ++ "python" + sys.version[:3], ++ "dist-packages")) ++ sitepackages.append(os.path.join(prefix, "lib", ++ "python3", ++ "dist-packages")) ++ # this one is deprecated for Debian + sitepackages.append(os.path.join(prefix, "lib", +- "python%d.%d" % sys.version_info[:2], +- "site-packages")) ++ "python" + sys.version[:3], ++ "dist-packages")) + else: + sitepackages.append(prefix) + sitepackages.append(os.path.join(prefix, "lib", "site-packages")) +Index: b/Lib/test/test_site.py +=================================================================== +--- a/Lib/test/test_site.py ++++ b/Lib/test/test_site.py +@@ -260,10 +260,10 @@ class HelperFunctionsTests(unittest.Test + self.assertEqual(dirs[1], wanted) + elif os.sep == '/': + # OS X non-framwework builds, Linux, FreeBSD, etc +- self.assertEqual(len(dirs), 1) +- wanted = os.path.join('xoxo', 'lib', ++ self.assertEqual(len(dirs), 3) ++ wanted = os.path.join('xoxo', 'local', 'lib', + 'python%d.%d' % sys.version_info[:2], +- 'site-packages') ++ 'dist-packages') + self.assertEqual(dirs[0], wanted) + else: + # other platforms +Index: b/Lib/distutils/tests/test_bdist_dumb.py +=================================================================== +--- a/Lib/distutils/tests/test_bdist_dumb.py ++++ b/Lib/distutils/tests/test_bdist_dumb.py +@@ -85,7 +85,7 @@ class BuildDumbTestCase(support.TempdirM + fp.close() + + contents = sorted(os.path.basename(fn) for fn in contents) +- wanted = ['foo-0.1-py%s.%s.egg-info' % sys.version_info[:2], 'foo.py'] ++ wanted = ['foo-0.1.egg-info', 'foo.py'] + if not sys.dont_write_bytecode: + wanted.append('foo.%s.pyc' % sys.implementation.cache_tag) + self.assertEqual(contents, sorted(wanted)) +Index: b/Lib/distutils/tests/test_install.py +=================================================================== +--- a/Lib/distutils/tests/test_install.py ++++ b/Lib/distutils/tests/test_install.py +@@ -193,7 +193,7 @@ class InstallTestCase(support.TempdirMan + found = [os.path.basename(line) for line in content.splitlines()] + expected = ['hello.py', 'hello.%s.pyc' % sys.implementation.cache_tag, + 'sayhi', +- 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] ++ 'UNKNOWN-0.0.0.egg-info'] + self.assertEqual(found, expected) + + def test_record_extensions(self): +@@ -226,7 +226,7 @@ class InstallTestCase(support.TempdirMan + + found = [os.path.basename(line) for line in content.splitlines()] + expected = [_make_ext_name('xx'), +- 'UNKNOWN-0.0.0-py%s.%s.egg-info' % sys.version_info[:2]] ++ 'UNKNOWN-0.0.0.egg-info'] + self.assertEqual(found, expected) + + def test_debug_mode(self): +Index: b/Lib/pydoc.py +=================================================================== +--- a/Lib/pydoc.py ++++ b/Lib/pydoc.py +@@ -417,6 +417,7 @@ class Doc: + 'marshal', 'posix', 'signal', 'sys', + '_thread', 'zipimport') or + (file.startswith(basedir) and ++ not file.startswith(os.path.join(basedir, 'dist-packages')) and + not file.startswith(os.path.join(basedir, 'site-packages')))) and + object.__name__ not in ('xml.etree', 'test.pydoc_mod')): + if docloc.startswith(("http://", "https://")): diff --git a/debian/patches/distutils-link.diff b/debian/patches/distutils-link.diff new file mode 100644 index 0000000..b8ad3cf --- /dev/null +++ b/debian/patches/distutils-link.diff @@ -0,0 +1,24 @@ +# DP: Don't add standard library dirs to library_dirs and runtime_library_dirs. + +Index: b/Lib/distutils/unixccompiler.py +=================================================================== +--- a/Lib/distutils/unixccompiler.py ++++ b/Lib/distutils/unixccompiler.py +@@ -155,6 +155,17 @@ class UnixCCompiler(CCompiler): + runtime_library_dirs) + libraries, library_dirs, runtime_library_dirs = fixed_args + ++ # filter out standard library paths, which are not explicitely needed ++ # for linking ++ system_libdirs = ['/lib', '/lib64', '/usr/lib', '/usr/lib64'] ++ multiarch = sysconfig.get_config_var("MULTIARCH") ++ if multiarch: ++ system_libdirs.extend(['/lib/%s' % multiarch, '/usr/lib/%s' % multiarch]) ++ library_dirs = [dir for dir in library_dirs ++ if not dir in system_libdirs] ++ runtime_library_dirs = [dir for dir in runtime_library_dirs ++ if not dir in system_libdirs] ++ + lib_opts = gen_lib_options(self, library_dirs, runtime_library_dirs, + libraries) + if not isinstance(output_dir, (str, type(None))): diff --git a/debian/patches/distutils-sysconfig.diff b/debian/patches/distutils-sysconfig.diff new file mode 100644 index 0000000..c12e6b3 --- /dev/null +++ b/debian/patches/distutils-sysconfig.diff @@ -0,0 +1,45 @@ +# DP: Get CONFIGURE_CFLAGS, CONFIGURE_CPPFLAGS, CONFIGURE_LDFLAGS from +# DP: the python build, when CFLAGS, CPPFLAGS, LDSHARED) are not set +# DP: in the environment. + +Index: b/Lib/distutils/sysconfig.py +=================================================================== +--- a/Lib/distutils/sysconfig.py ++++ b/Lib/distutils/sysconfig.py +@@ -177,9 +177,11 @@ def customize_compiler(compiler): + _osx_support.customize_compiler(_config_vars) + _config_vars['CUSTOMIZED_OSX_COMPILER'] = 'True' + +- (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags) = \ ++ (cc, cxx, opt, cflags, ccshared, ldshared, shlib_suffix, ar, ar_flags, ++ configure_cppflags, configure_cflags, configure_ldflags) = \ + get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS', +- 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS') ++ 'CCSHARED', 'LDSHARED', 'SHLIB_SUFFIX', 'AR', 'ARFLAGS', ++ 'CONFIGURE_CPPFLAGS', 'CONFIGURE_CFLAGS', 'CONFIGURE_LDFLAGS') + + if 'CC' in os.environ: + newcc = os.environ['CC'] +@@ -200,13 +202,22 @@ def customize_compiler(compiler): + cpp = cc + " -E" # not always + if 'LDFLAGS' in os.environ: + ldshared = ldshared + ' ' + os.environ['LDFLAGS'] ++ elif configure_ldflags: ++ ldshared = ldshared + ' ' + configure_ldflags + if 'CFLAGS' in os.environ: + cflags = opt + ' ' + os.environ['CFLAGS'] + ldshared = ldshared + ' ' + os.environ['CFLAGS'] ++ elif configure_cflags: ++ cflags = opt + ' ' + configure_cflags ++ ldshared = ldshared + ' ' + configure_cflags + if 'CPPFLAGS' in os.environ: + cpp = cpp + ' ' + os.environ['CPPFLAGS'] + cflags = cflags + ' ' + os.environ['CPPFLAGS'] + ldshared = ldshared + ' ' + os.environ['CPPFLAGS'] ++ elif configure_cppflags: ++ cpp = cpp + ' ' + configure_cppflags ++ cflags = cflags + ' ' + configure_cppflags ++ ldshared = ldshared + ' ' + configure_cppflags + if 'AR' in os.environ: + ar = os.environ['AR'] + if 'ARFLAGS' in os.environ: diff --git a/debian/patches/ensurepip-disabled.diff b/debian/patches/ensurepip-disabled.diff new file mode 100644 index 0000000..f19b36a --- /dev/null +++ b/debian/patches/ensurepip-disabled.diff @@ -0,0 +1,87 @@ +# DP: Disable ensurepip for the system installation, only enable it for virtual environments. + +Index: b/Lib/ensurepip/__init__.py +=================================================================== +--- a/Lib/ensurepip/__init__.py ++++ b/Lib/ensurepip/__init__.py +@@ -8,6 +8,34 @@ import tempfile + + __all__ = ["version", "bootstrap"] + ++def _ensurepip_is_disabled_in_debian_for_system(): ++ # Detect if ensurepip is being executed inside of a python-virtualenv ++ # environment and return early if so. ++ if hasattr(sys, 'real_prefix'): ++ return ++ ++ # Detect if ensurepip is being executed inside of a stdlib venv ++ # environment and return early if so. ++ if sys.prefix != getattr(sys, "base_prefix", sys.prefix): ++ return ++ ++ # If we've gotten here, then we are running inside of the system Python ++ # and we don't want to use ensurepip to install into the system Python ++ # so instead we'll redirect the user to using dpkg and apt-get. ++ print('''\ ++ensurepip is disabled in Debian/Ubuntu for the system python. ++ ++Python modules for the system python are usually handled by dpkg and apt-get. ++ ++ apt-get install python-<module name> ++ ++Install the python-pip package to use pip itself. Using pip together ++with the system python might have unexpected results for any system installed ++module, so use it on your own risk, or make sure to only use it in virtual ++environments. ++''') ++ sys.exit(1) ++ + + _PROJECTS = [ + "setuptools", +@@ -56,6 +84,11 @@ def bootstrap(*, root=None, upgrade=Fals + + Note that calling this function will alter both sys.path and os.environ. + """ ++ ++ # Ensure that we are only running this inside of a virtual environment ++ # of some kind. ++ _ensurepip_is_disabled_in_debian_for_system() ++ + if altinstall and default_pip: + raise ValueError("Cannot use altinstall and default_pip together") + +Index: b/Lib/venv/__init__.py +=================================================================== +--- a/Lib/venv/__init__.py ++++ b/Lib/venv/__init__.py +@@ -242,7 +242,28 @@ class EnvBuilder: + # intended for the global Python environment + cmd = [context.env_exe, '-Im', 'ensurepip', '--upgrade', + '--default-pip'] +- subprocess.check_output(cmd, stderr=subprocess.STDOUT) ++ # Debian 2015-09-18 barry@debian.org: <python>-venv is a separate ++ # binary package which might not be installed. In that case, the ++ # following command will produce an unhelpful error. Let's make it ++ # more user friendly. ++ try: ++ subprocess.check_output( ++ cmd, stderr=subprocess.STDOUT, ++ universal_newlines=True) ++ except subprocess.CalledProcessError: ++ print("""\ ++The virtual environment was not created successfully because ensurepip is not ++available. On Debian/Ubuntu systems, you need to install the python3-venv ++package using the following command. ++ ++ apt-get install python3-venv ++ ++You may need to use sudo with that command. After installing the python3-venv ++package, recreate your virtual environment. ++ ++Failing command: {} ++""".format(cmd)) ++ sys.exit(1) + + def setup_scripts(self, context): + """ diff --git a/debian/patches/ensurepip-wheels.diff b/debian/patches/ensurepip-wheels.diff new file mode 100644 index 0000000..df5de92 --- /dev/null +++ b/debian/patches/ensurepip-wheels.diff @@ -0,0 +1,121 @@ +Index: b/Lib/ensurepip/__init__.py +=================================================================== +--- a/Lib/ensurepip/__init__.py ++++ b/Lib/ensurepip/__init__.py +@@ -1,3 +1,4 @@ ++import glob + import os + import os.path + import pkgutil +@@ -8,13 +9,10 @@ import tempfile + __all__ = ["version", "bootstrap"] + + +-_SETUPTOOLS_VERSION = "28.8.0" +- +-_PIP_VERSION = "9.0.1" +- + _PROJECTS = [ +- ("setuptools", _SETUPTOOLS_VERSION), +- ("pip", _PIP_VERSION), ++ "setuptools", ++ "pip", ++ "pkg_resources", + ] + + +@@ -32,7 +30,10 @@ def version(): + """ + Returns a string specifying the bundled version of pip. + """ +- return _PIP_VERSION ++ wheel_names = glob.glob('/usr/share/python-wheels/pip-*.whl') ++ assert len(wheel_names) == 1, wheel_names ++ return os.path.basename(wheel_names[0]).split('-')[1] ++ + + def _disable_pip_configuration_settings(): + # We deliberately ignore all pip environment variables +@@ -73,20 +74,44 @@ def bootstrap(*, root=None, upgrade=Fals + # omit pip and easy_install + os.environ["ENSUREPIP_OPTIONS"] = "install" + ++ # Debian: The bundled wheels are useless to us because we must use ones ++ # crafted from source code in the archive. As we build the virtual ++ # environment, copy the wheels from the system location into the virtual ++ # environment, and place those wheels on sys.path. ++ def copy_wheels(wheels, destdir, paths): ++ for project in wheels: ++ wheel_names = glob.glob( ++ '/usr/share/python-wheels/{}-*.whl'.format(project)) ++ if len(wheel_names) == 0: ++ raise RuntimeError('missing dependency wheel %s' % project) ++ assert len(wheel_names) == 1, wheel_names ++ wheel_name = os.path.basename(wheel_names[0]) ++ path = os.path.join('/usr/share/python-wheels', wheel_name) ++ with open(path, 'rb') as fp: ++ whl = fp.read() ++ dest = os.path.join(destdir, wheel_name) ++ with open(dest, 'wb') as fp: ++ fp.write(whl) ++ paths.append(dest) ++ + with tempfile.TemporaryDirectory() as tmpdir: ++ # This directory is a "well known directory" which Debian has patched ++ # pip to look in when attempting to locate wheels to use to satisfy ++ # the dependencies that pip normally bundles but Debian has debundled. ++ # This is critically important and if this directory changes then both ++ # python-pip and python-virtualenv needs updated to match. ++ venv_wheel_dir = os.path.join(sys.prefix, 'share', 'python-wheels') ++ os.makedirs(venv_wheel_dir, exist_ok=True) ++ dependencies = [ ++ os.path.basename(whl).split('-')[0] ++ for whl in glob.glob('/usr/share/python-wheels/*.whl') ++ ] ++ copy_wheels(dependencies, venv_wheel_dir, sys.path) ++ + # Put our bundled wheels into a temporary directory and construct the + # additional paths that need added to sys.path + additional_paths = [] +- for project, version in _PROJECTS: +- wheel_name = "{}-{}-py2.py3-none-any.whl".format(project, version) +- whl = pkgutil.get_data( +- "ensurepip", +- "_bundled/{}".format(wheel_name), +- ) +- with open(os.path.join(tmpdir, wheel_name), "wb") as fp: +- fp.write(whl) +- +- additional_paths.append(os.path.join(tmpdir, wheel_name)) ++ copy_wheels(_PROJECTS, tmpdir, additional_paths) + + # Construct the arguments to be passed to the pip command + args = ["install", "--no-index", "--find-links", tmpdir] +@@ -99,7 +124,7 @@ def bootstrap(*, root=None, upgrade=Fals + if verbosity: + args += ["-" + "v" * verbosity] + +- _run_pip(args + [p[0] for p in _PROJECTS], additional_paths) ++ _run_pip(args + _PROJECTS, additional_paths) + + def _uninstall_helper(*, verbosity=0): + """Helper to support a clean default uninstall process on Windows +@@ -113,7 +138,8 @@ def _uninstall_helper(*, verbosity=0): + return + + # If the pip version doesn't match the bundled one, leave it alone +- if pip.__version__ != _PIP_VERSION: ++ # Disabled for Debian, always using the version from the python3-pip package. ++ if False and pip.__version__ != _PIP_VERSION: + msg = ("ensurepip will only uninstall a matching version " + "({!r} installed, {!r} bundled)") + print(msg.format(pip.__version__, _PIP_VERSION), file=sys.stderr) +@@ -126,7 +152,7 @@ def _uninstall_helper(*, verbosity=0): + if verbosity: + args += ["-" + "v" * verbosity] + +- _run_pip(args + [p[0] for p in reversed(_PROJECTS)]) ++ _run_pip(args + reversed(_PROJECTS)) + + + def _main(argv=None): diff --git a/debian/patches/ext-no-libpython-link.diff b/debian/patches/ext-no-libpython-link.diff new file mode 100644 index 0000000..627d9d1 --- /dev/null +++ b/debian/patches/ext-no-libpython-link.diff @@ -0,0 +1,24 @@ +# DP: Don't link extensions with the shared libpython library. + +Index: b/Lib/distutils/command/build_ext.py +=================================================================== +--- a/Lib/distutils/command/build_ext.py ++++ b/Lib/distutils/command/build_ext.py +@@ -230,7 +230,7 @@ class build_ext(Command): + # For building extensions with a shared Python library, + # Python's library directory must be appended to library_dirs + # See Issues: #1600860, #4366 +- if (sysconfig.get_config_var('Py_ENABLE_SHARED')): ++ if False and (sysconfig.get_config_var('Py_ENABLE_SHARED')): + if not sysconfig.python_build: + # building third party extensions + self.library_dirs.append(sysconfig.get_config_var('LIBDIR')) +@@ -746,7 +746,7 @@ class build_ext(Command): + return ext.libraries + else: + from distutils import sysconfig +- if sysconfig.get_config_var('Py_ENABLE_SHARED'): ++ if False and sysconfig.get_config_var('Py_ENABLE_SHARED'): + pythonlib = 'python{}.{}{}'.format( + sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff, + sysconfig.get_config_var('ABIFLAGS')) diff --git a/debian/patches/gdbm-import.diff b/debian/patches/gdbm-import.diff new file mode 100644 index 0000000..2be2934 --- /dev/null +++ b/debian/patches/gdbm-import.diff @@ -0,0 +1,12 @@ +# DP: suggest installation of python3-gdbm package on failing _gdbm import + +--- a/Lib/dbm/gnu.py ++++ b/Lib/dbm/gnu.py +@@ -1,3 +1,6 @@ + """Provide the _gdbm module as a dbm submodule.""" + +-from _gdbm import * ++try: ++ from _gdbm import * ++except ImportError as msg: ++ raise ImportError(str(msg) + ', please install the python3-gdbm package') diff --git a/debian/patches/git-updates.diff b/debian/patches/git-updates.diff new file mode 100644 index 0000000..f9229ee --- /dev/null +++ b/debian/patches/git-updates.diff @@ -0,0 +1,4 @@ +# DP: updates from the 3.6 branch (until 2017-06-07, ). + +# git diff 69c0db5050f623e8895b72dfe970392b1f9a0e2e 09b6c0c71ea944f7e8b46998f3ebaf5b9fbe15f6 | filterdiff -x ?/.hgignore -x ?/.hgeol -x ?/.hgtags -x ?/.hgtouch -x ?/.gitignore -x ?/.gitattributes -x '?/.github/*' -x '?/.git*' -x ?/.codecov.yml -x ?/.travis.yml -x ?/configure --remove-timestamps + diff --git a/debian/patches/langpack-gettext.diff b/debian/patches/langpack-gettext.diff new file mode 100644 index 0000000..56deb77 --- /dev/null +++ b/debian/patches/langpack-gettext.diff @@ -0,0 +1,36 @@ +# DP: Description: support alternative gettext tree in +# DP: /usr/share/locale-langpack; if a file is present in both trees, +# DP: prefer the newer one +# DP: Upstream status: Ubuntu-Specific + +Index: b/Lib/gettext.py +=================================================================== +--- a/Lib/gettext.py ++++ b/Lib/gettext.py +@@ -491,11 +491,26 @@ def find(domain, localedir=None, languag + if lang == 'C': + break + mofile = os.path.join(localedir, lang, 'LC_MESSAGES', '%s.mo' % domain) ++ mofile_lp = os.path.join("/usr/share/locale-langpack", lang, ++ 'LC_MESSAGES', '%s.mo' % domain) ++ ++ # first look into the standard locale dir, then into the ++ # langpack locale dir ++ ++ # standard mo file + if os.path.exists(mofile): + if all: + result.append(mofile) + else: + return mofile ++ ++ # langpack mofile -> use it ++ if os.path.exists(mofile_lp): ++ if all: ++ result.append(mofile_lp) ++ else: ++ return mofile_lp ++ + return result + + diff --git a/debian/patches/lib-argparse.diff b/debian/patches/lib-argparse.diff new file mode 100644 index 0000000..c9d604a --- /dev/null +++ b/debian/patches/lib-argparse.diff @@ -0,0 +1,22 @@ +# DP: argparse.py: Make the gettext import conditional + +--- a/Lib/argparse.py ++++ b/Lib/argparse.py +@@ -90,7 +90,16 @@ + import sys as _sys + import textwrap as _textwrap + +-from gettext import gettext as _, ngettext ++try: ++ from gettext import gettext as _, ngettext ++except ImportError: ++ def _(message): ++ return message ++ def ngettext(singular,plural,n): ++ if n == 1: ++ return singular ++ else: ++ return plural + + + SUPPRESS = '==SUPPRESS==' diff --git a/debian/patches/lib2to3-no-pickled-grammar.diff b/debian/patches/lib2to3-no-pickled-grammar.diff new file mode 100644 index 0000000..6364384 --- /dev/null +++ b/debian/patches/lib2to3-no-pickled-grammar.diff @@ -0,0 +1,92 @@ +Index: b/Lib/lib2to3/pgen2/driver.py +=================================================================== +--- a/Lib/lib2to3/pgen2/driver.py ++++ b/Lib/lib2to3/pgen2/driver.py +@@ -122,7 +122,10 @@ def load_grammar(gt="Grammar.txt", gp=No + if force or not _newer(gp, gt): + logger.info("Generating grammar tables from %s", gt) + g = pgen.generate_grammar(gt) +- if save: ++ # the pickle files mismatch, when built on different architectures. ++ # don't save these for now. An alternative solution might be to ++ # include the multiarch triplet into the file name ++ if False: + logger.info("Writing grammar tables to %s", gp) + try: + g.dump(gp) +Index: b/Lib/lib2to3/tests/test_parser.py +=================================================================== +--- a/Lib/lib2to3/tests/test_parser.py ++++ b/Lib/lib2to3/tests/test_parser.py +@@ -36,71 +36,6 @@ + self.assertEqual(t.children[1].children[0].type, syms.print_stmt) + + +-class TestPgen2Caching(support.TestCase): +- def test_load_grammar_from_txt_file(self): +- pgen2_driver.load_grammar(support.grammar_path, save=False, force=True) +- +- def test_load_grammar_from_pickle(self): +- # Make a copy of the grammar file in a temp directory we are +- # guaranteed to be able to write to. +- tmpdir = tempfile.mkdtemp() +- try: +- grammar_copy = os.path.join( +- tmpdir, os.path.basename(support.grammar_path)) +- shutil.copy(support.grammar_path, grammar_copy) +- pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) +- +- pgen2_driver.load_grammar(grammar_copy, save=True, force=True) +- self.assertTrue(os.path.exists(pickle_name)) +- +- os.unlink(grammar_copy) # Only the pickle remains... +- pgen2_driver.load_grammar(grammar_copy, save=False, force=False) +- finally: +- shutil.rmtree(tmpdir) +- +- @unittest.skipIf(sys.executable is None, 'sys.executable required') +- def test_load_grammar_from_subprocess(self): +- tmpdir = tempfile.mkdtemp() +- tmpsubdir = os.path.join(tmpdir, 'subdir') +- try: +- os.mkdir(tmpsubdir) +- grammar_base = os.path.basename(support.grammar_path) +- grammar_copy = os.path.join(tmpdir, grammar_base) +- grammar_sub_copy = os.path.join(tmpsubdir, grammar_base) +- shutil.copy(support.grammar_path, grammar_copy) +- shutil.copy(support.grammar_path, grammar_sub_copy) +- pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) +- pickle_sub_name = pgen2_driver._generate_pickle_name( +- grammar_sub_copy) +- self.assertNotEqual(pickle_name, pickle_sub_name) +- +- # Generate a pickle file from this process. +- pgen2_driver.load_grammar(grammar_copy, save=True, force=True) +- self.assertTrue(os.path.exists(pickle_name)) +- +- # Generate a new pickle file in a subprocess with a most likely +- # different hash randomization seed. +- sub_env = dict(os.environ) +- sub_env['PYTHONHASHSEED'] = 'random' +- subprocess.check_call( +- [sys.executable, '-c', """ +-from lib2to3.pgen2 import driver as pgen2_driver +-pgen2_driver.load_grammar(%r, save=True, force=True) +- """ % (grammar_sub_copy,)], +- env=sub_env) +- self.assertTrue(os.path.exists(pickle_sub_name)) +- +- with open(pickle_name, 'rb') as pickle_f_1, \ +- open(pickle_sub_name, 'rb') as pickle_f_2: +- self.assertEqual( +- pickle_f_1.read(), pickle_f_2.read(), +- msg='Grammar caches generated using different hash seeds' +- ' were not identical.') +- finally: +- shutil.rmtree(tmpdir) +- +- +- + class GrammarTest(support.TestCase): + def validate(self, code): + support.parse_string(code) diff --git a/debian/patches/link-opt.diff b/debian/patches/link-opt.diff new file mode 100644 index 0000000..4b4d7b7 --- /dev/null +++ b/debian/patches/link-opt.diff @@ -0,0 +1,26 @@ +# DP: Call the linker with -O1 -Bsymbolic-functions + +Index: b/configure.ac +=================================================================== +--- a/configure.ac ++++ b/configure.ac +@@ -2511,8 +2511,8 @@ then + fi + ;; + Linux*|GNU*|QNX*) +- LDSHARED='$(CC) -shared' +- LDCXXSHARED='$(CXX) -shared';; ++ LDSHARED='$(CC) -shared -Wl,-O1 -Wl,-Bsymbolic-functions' ++ LDCXXSHARED='$(CXX) -shared -Wl,-O1 -Wl,-Bsymbolic-functions';; + BSD/OS*/4*) + LDSHARED="gcc -shared" + LDCXXSHARED="g++ -shared";; +@@ -2612,7 +2612,7 @@ then + # LINKFORSHARED="-Wl,-E -Wl,+s -Wl,+b\$(BINLIBDEST)/lib-dynload";; + BSD/OS/4*) LINKFORSHARED="-Xlinker -export-dynamic";; + Linux-android*) LINKFORSHARED="-pie -Xlinker -export-dynamic";; +- Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic";; ++ Linux*|GNU*) LINKFORSHARED="-Xlinker -export-dynamic -Wl,-O1 -Wl,-Bsymbolic-functions";; + # -u libsys_s pulls in all symbols in libsys + Darwin/*) + LINKFORSHARED="$extra_undefs -framework CoreFoundation" diff --git a/debian/patches/link-timemodule.diff b/debian/patches/link-timemodule.diff new file mode 100644 index 0000000..45e4153 --- /dev/null +++ b/debian/patches/link-timemodule.diff @@ -0,0 +1,13 @@ +Index: b/Modules/Setup.dist +=================================================================== +--- a/Modules/Setup.dist ++++ b/Modules/Setup.dist +@@ -118,7 +118,7 @@ _collections _collectionsmodule.c # Cont + itertools itertoolsmodule.c # Functions creating iterators for efficient looping + atexit atexitmodule.c # Register functions to be run at interpreter-shutdown + _stat _stat.c # stat.h interface +-time timemodule.c # -lm # time operations and variables ++time timemodule.c -lrt # -lm # time operations and variables + + # access to ISO C locale support + _locale _localemodule.c # -lintl diff --git a/debian/patches/locale-module.diff b/debian/patches/locale-module.diff new file mode 100644 index 0000000..76fd849 --- /dev/null +++ b/debian/patches/locale-module.diff @@ -0,0 +1,19 @@ +# DP: * Lib/locale.py: +# DP: - Don't map 'utf8', 'utf-8' to 'utf', which is not a known encoding +# DP: for glibc. + +Index: b/Lib/locale.py +=================================================================== +--- a/Lib/locale.py ++++ b/Lib/locale.py +@@ -1339,8 +1339,8 @@ locale_alias = { + 'ug_cn': 'ug_CN.UTF-8', + 'uk': 'uk_UA.KOI8-U', + 'uk_ua': 'uk_UA.KOI8-U', +- 'univ': 'en_US.utf', +- 'universal': 'en_US.utf', ++ 'univ': 'en_US.UTF-8', ++ 'universal': 'en_US.UTF-8', + 'universal.utf8@ucs4': 'en_US.UTF-8', + 'unm_us': 'unm_US.UTF-8', + 'ur': 'ur_PK.CP1256', diff --git a/debian/patches/lto-link-flags.diff b/debian/patches/lto-link-flags.diff new file mode 100644 index 0000000..afea9c2 --- /dev/null +++ b/debian/patches/lto-link-flags.diff @@ -0,0 +1,22 @@ +Index: b/Makefile.pre.in +=================================================================== +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -146,7 +146,7 @@ CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$ + SHLIB_SUFFIX= @SHLIB_SUFFIX@ + EXT_SUFFIX= @EXT_SUFFIX@ + LDSHARED= @LDSHARED@ $(PY_LDFLAGS) +-BLDSHARED= @BLDSHARED@ $(PY_LDFLAGS) ++BLDSHARED= @BLDSHARED@ $(PY_LDFLAGS) $(PY_CFLAGS) + LDCXXSHARED= @LDCXXSHARED@ + DESTSHARED= $(BINLIBDEST)/lib-dynload + +@@ -544,7 +544,7 @@ clinic: $(BUILDPYTHON) $(srcdir)/Modules + + # Build the interpreter + $(BUILDPYTHON): Programs/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) +- $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) ++ $(LINKCC) $(PY_LDFLAGS) $(PY_CFLAGS) $(LINKFORSHARED) -o $@ Programs/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) + + platform: $(BUILDPYTHON) pybuilddir.txt + $(RUNSHARED) $(PYTHON_FOR_BUILD) -c 'import sys ; from sysconfig import get_platform ; print("%s-%d.%d" % (get_platform(), *sys.version_info[:2]))' >platform diff --git a/debian/patches/mangle-fstack-protector.diff b/debian/patches/mangle-fstack-protector.diff new file mode 100644 index 0000000..19b27f7 --- /dev/null +++ b/debian/patches/mangle-fstack-protector.diff @@ -0,0 +1,26 @@ +# DP: When using GCC versions older than 4.9, automagically mangle +# DP: -fstack-protector-strong to -fstack-protector + +Index: b/Lib/distutils/sysconfig.py +=================================================================== +--- a/Lib/distutils/sysconfig.py ++++ b/Lib/distutils/sysconfig.py +@@ -13,6 +13,7 @@ import _imp + import os + import re + import sys ++import fnmatch + + from .errors import DistutilsPlatformError + +@@ -197,6 +198,10 @@ def customize_compiler(compiler): + cc = newcc + if 'CXX' in os.environ: + cxx = os.environ['CXX'] ++ if fnmatch.filter([cc, cxx], '*-4.[0-8]'): ++ configure_cflags = configure_cflags.replace('-fstack-protector-strong', '-fstack-protector') ++ ldshared = ldshared.replace('-fstack-protector-strong', '-fstack-protector') ++ cflags = cflags.replace('-fstack-protector-strong', '-fstack-protector') + if 'LDSHARED' in os.environ: + ldshared = os.environ['LDSHARED'] + if 'CPP' in os.environ: diff --git a/debian/patches/multiarch-extname.diff b/debian/patches/multiarch-extname.diff new file mode 100644 index 0000000..1ab825d --- /dev/null +++ b/debian/patches/multiarch-extname.diff @@ -0,0 +1,92 @@ +# DP: Make sure to rename extensions to a tag including the MULTIARCH name + +this patch can be dropped for python3.5 final, if the upstream chage is kept. + +Index: b/Lib/distutils/dir_util.py +=================================================================== +--- a/Lib/distutils/dir_util.py ++++ b/Lib/distutils/dir_util.py +@@ -96,6 +96,9 @@ def create_tree(base_dir, files, mode=0o + for dir in sorted(need_dir): + mkpath(dir, mode, verbose=verbose, dry_run=dry_run) + ++import sysconfig ++_multiarch = None ++ + def copy_tree(src, dst, preserve_mode=1, preserve_times=1, + preserve_symlinks=0, update=0, verbose=1, dry_run=0): + """Copy an entire directory tree 'src' to a new location 'dst'. +@@ -131,6 +134,13 @@ def copy_tree(src, dst, preserve_mode=1, + raise DistutilsFileError( + "error listing files in '%s': %s" % (src, e.strerror)) + ++ ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') ++ _multiarch = sysconfig.get_config_var ('MULTIARCH') ++ if ext_suffix.endswith(_multiarch + ext_suffix[-3:]): ++ new_suffix = None ++ else: ++ new_suffix = "%s-%s%s" % (ext_suffix[:-3], _multiarch, ext_suffix[-3:]) ++ + if not dry_run: + mkpath(dst, verbose=verbose) + +@@ -139,6 +149,9 @@ def copy_tree(src, dst, preserve_mode=1, + for n in names: + src_name = os.path.join(src, n) + dst_name = os.path.join(dst, n) ++ if new_suffix and _multiarch and n.endswith(ext_suffix) and not n.endswith(new_suffix): ++ dst_name = os.path.join(dst, n.replace(ext_suffix, new_suffix)) ++ log.info("renaming extension %s -> %s", n, n.replace(ext_suffix, new_suffix)) + + if n.startswith('.nfs'): + # skip NFS rename files +Index: b/Lib/distutils/command/install_lib.py +=================================================================== +--- a/Lib/distutils/command/install_lib.py ++++ b/Lib/distutils/command/install_lib.py +@@ -56,6 +56,7 @@ class install_lib(Command): + self.compile = None + self.optimize = None + self.skip_build = None ++ self.multiarch = None # if we should rename the extensions + + def finalize_options(self): + # Get all the information we need to install pure Python modules +@@ -68,6 +69,7 @@ class install_lib(Command): + ('compile', 'compile'), + ('optimize', 'optimize'), + ('skip_build', 'skip_build'), ++ ('multiarch', 'multiarch'), + ) + + if self.compile is None: +@@ -108,6 +110,8 @@ class install_lib(Command): + + def install(self): + if os.path.isdir(self.build_dir): ++ import distutils.dir_util ++ distutils.dir_util._multiarch = self.multiarch + outfiles = self.copy_tree(self.build_dir, self.install_dir) + else: + self.warn("'%s' does not exist -- no Python modules to install" % +Index: b/Lib/distutils/command/install.py +=================================================================== +--- a/Lib/distutils/command/install.py ++++ b/Lib/distutils/command/install.py +@@ -192,6 +192,7 @@ class install(Command): + + # enable custom installation, known values: deb + self.install_layout = None ++ self.multiarch = None + + self.compile = None + self.optimize = None +@@ -451,6 +452,8 @@ class install(Command): + self.install_platbase = self.exec_prefix + if self.install_layout: + if self.install_layout.lower() in ['deb']: ++ import sysconfig ++ self.multiarch = sysconfig.get_config_var('MULTIARCH') + self.select_scheme("deb_system") + elif self.install_layout.lower() in ['unix']: + self.select_scheme("unix_prefix") diff --git a/debian/patches/multiarch.diff b/debian/patches/multiarch.diff new file mode 100644 index 0000000..dace3f5 --- /dev/null +++ b/debian/patches/multiarch.diff @@ -0,0 +1,52 @@ +Index: b/Lib/sysconfig.py +=================================================================== +--- a/Lib/sysconfig.py ++++ b/Lib/sysconfig.py +@@ -557,6 +557,12 @@ def get_config_vars(*args): + # the init-function. + _CONFIG_VARS['userbase'] = _getuserbase() + ++ multiarch = get_config_var('MULTIARCH') ++ if multiarch: ++ _CONFIG_VARS['multiarchsubdir'] = '/' + multiarch ++ else: ++ _CONFIG_VARS['multiarchsubdir'] = '' ++ + # Always convert srcdir to an absolute path + srcdir = _CONFIG_VARS.get('srcdir', _PROJECT_BASE) + if os.name == 'posix': +Index: b/Lib/distutils/sysconfig.py +=================================================================== +--- a/Lib/distutils/sysconfig.py ++++ b/Lib/distutils/sysconfig.py +@@ -99,6 +99,9 @@ def get_python_inc(plat_specific=0, pref + incdir = os.path.join(get_config_var('srcdir'), 'Include') + return os.path.normpath(incdir) + python_dir = 'python' + get_python_version() + build_flags ++ if not python_build and plat_specific: ++ import sysconfig ++ return sysconfig.get_path('platinclude') + return os.path.join(prefix, "include", python_dir) + elif os.name == "nt": + return os.path.join(prefix, "include") +Index: b/Makefile.pre.in +=================================================================== +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -760,6 +760,7 @@ Modules/signalmodule.o: $(srcdir)/Module + + Python/dynload_shlib.o: $(srcdir)/Python/dynload_shlib.c Makefile + $(CC) -c $(PY_CORE_CFLAGS) \ ++ $(if $(MULTIARCH),-DMULTIARCH='"$(MULTIARCH)"') \ + -DSOABI='"$(SOABI)"' \ + -o $@ $(srcdir)/Python/dynload_shlib.c + +@@ -1404,7 +1405,7 @@ inclinstall: + LIBPL= @LIBPL@ + + # pkgconfig directory +-LIBPC= $(LIBDIR)/pkgconfig ++LIBPC= $(LIBDIR)/$(MULTIARCH)/pkgconfig + + libainstall: @DEF_MAKE_RULE@ python-config + @for i in $(LIBDIR) $(LIBPL) $(LIBPC); \ diff --git a/debian/patches/platform-lsbrelease.diff b/debian/patches/platform-lsbrelease.diff new file mode 100644 index 0000000..271139f --- /dev/null +++ b/debian/patches/platform-lsbrelease.diff @@ -0,0 +1,65 @@ +# DP: Use /etc/lsb-release to identify the platform. + +Index: b/Lib/platform.py +=================================================================== +--- a/Lib/platform.py ++++ b/Lib/platform.py +@@ -267,7 +267,7 @@ _release_version = re.compile(r'([^0-9]+ + _supported_dists = ( + 'SuSE', 'debian', 'fedora', 'redhat', 'centos', + 'mandrake', 'mandriva', 'rocks', 'slackware', 'yellowdog', 'gentoo', +- 'UnitedLinux', 'turbolinux', 'arch', 'mageia') ++ 'UnitedLinux', 'turbolinux', 'arch', 'mageia', 'Ubuntu') + + def _parse_release_file(firstline): + +@@ -296,6 +296,10 @@ def _parse_release_file(firstline): + id = l[1] + return '', version, id + ++_distributor_id_file_re = re.compile("(?:DISTRIB_ID\s*=)\s*(.*)", re.I) ++_release_file_re = re.compile("(?:DISTRIB_RELEASE\s*=)\s*(.*)", re.I) ++_codename_file_re = re.compile("(?:DISTRIB_CODENAME\s*=)\s*(.*)", re.I) ++ + def linux_distribution(distname='', version='', id='', + + supported_dists=_supported_dists, +@@ -328,6 +332,25 @@ def _linux_distribution(distname, versio + args given as parameters. + + """ ++ # check for the Debian/Ubuntu /etc/lsb-release file first, needed so ++ # that the distribution doesn't get identified as Debian. ++ try: ++ with open("/etc/lsb-release", "r") as etclsbrel: ++ for line in etclsbrel: ++ m = _distributor_id_file_re.search(line) ++ if m: ++ _u_distname = m.group(1).strip() ++ m = _release_file_re.search(line) ++ if m: ++ _u_version = m.group(1).strip() ++ m = _codename_file_re.search(line) ++ if m: ++ _u_id = m.group(1).strip() ++ if _u_distname and _u_version: ++ return (_u_distname, _u_version, _u_id) ++ except (EnvironmentError, UnboundLocalError): ++ pass ++ + try: + etc = os.listdir(_UNIXCONFDIR) + except OSError: +Index: b/Lib/test/test_platform.py +=================================================================== +--- a/Lib/test/test_platform.py ++++ b/Lib/test/test_platform.py +@@ -349,6 +349,8 @@ class PlatformTest(unittest.TestCase): + self.assertEqual(version, '19') + self.assertEqual(distid, 'Schr\xf6dinger\u2019s Cat') + ++ # we know we are Debian/Ubuntu ++ test_linux_distribution_encoding.skip = True + + class DeprecationTest(unittest.TestCase): + diff --git a/debian/patches/profiled-build.diff b/debian/patches/profiled-build.diff new file mode 100644 index 0000000..1eb203b --- /dev/null +++ b/debian/patches/profiled-build.diff @@ -0,0 +1,23 @@ +# DP: Ignore errors in the profile task. + +Index: b/Makefile.pre.in +=================================================================== +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -467,6 +467,16 @@ build_all_generate_profile: + run_profile_task: + : # FIXME: can't run for a cross build + $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $(PROFILE_TASK) || true ++ task="$(PROFILE_TASK)"; \ ++ case "$$task" in \ ++ *-s\ *) \ ++ $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $$task; \ ++ while [ -f $(srcdir)/build/pynexttest ]; do \ ++ $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $$task; \ ++ done;; \ ++ *) \ ++ $(LLVM_PROF_FILE) $(RUNSHARED) ./$(BUILDPYTHON) $$task; \ ++ esac + + build_all_merge_profile: + $(LLVM_PROF_MERGER) diff --git a/debian/patches/pydoc-use-pager.diff b/debian/patches/pydoc-use-pager.diff new file mode 100644 index 0000000..a92c245 --- /dev/null +++ b/debian/patches/pydoc-use-pager.diff @@ -0,0 +1,15 @@ +# DP: pydoc: use the pager command if available. + +Index: b/Lib/pydoc.py +=================================================================== +--- a/Lib/pydoc.py ++++ b/Lib/pydoc.py +@@ -1446,6 +1446,8 @@ def getpager(): + return plainpager + if sys.platform == 'win32': + return lambda text: tempfilepager(plain(text), 'more <') ++ if hasattr(os, 'system') and os.system('(pager) 2>/dev/null') == 0: ++ return lambda text: pipepager(text, 'pager') + if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0: + return lambda text: pipepager(text, 'less') + diff --git a/debian/patches/pyhash.diff b/debian/patches/pyhash.diff new file mode 100644 index 0000000..f8ecfda --- /dev/null +++ b/debian/patches/pyhash.diff @@ -0,0 +1,67 @@ +Index: b/Python/pyhash.c +=================================================================== +--- a/Python/pyhash.c ++++ b/Python/pyhash.c +@@ -328,13 +328,14 @@ static PyHash_FuncDef PyHash_Func = {fnv + * the hash values' least significant bits. + */ + #if PY_LITTLE_ENDIAN +-# define _le64toh(x) ((uint64_t)(x)) ++# define _le64toh(v, x) memcpy(&(v), &(x), sizeof(v)) + #elif defined(__APPLE__) +-# define _le64toh(x) OSSwapLittleToHostInt64(x) ++# define _le64toh(v, x) v = OSSwapLittleToHostInt64(x) + #elif defined(HAVE_LETOH64) +-# define _le64toh(x) le64toh(x) ++# define _le64toh(v, x) v = le64toh(x) + #else +-# define _le64toh(x) (((uint64_t)(x) << 56) | \ ++# define _le64toh(v, x) v = \ ++ (((uint64_t)(x) << 56) | \ + (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ + (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ + (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ +@@ -366,22 +367,24 @@ static PyHash_FuncDef PyHash_Func = {fnv + + static Py_hash_t + siphash24(const void *src, Py_ssize_t src_sz) { +- uint64_t k0 = _le64toh(_Py_HashSecret.siphash.k0); +- uint64_t k1 = _le64toh(_Py_HashSecret.siphash.k1); ++ uint64_t k0, k1, v0, v1, v2, v3; + uint64_t b = (uint64_t)src_sz << 56; + const uint64_t *in = (uint64_t*)src; + +- uint64_t v0 = k0 ^ 0x736f6d6570736575ULL; +- uint64_t v1 = k1 ^ 0x646f72616e646f6dULL; +- uint64_t v2 = k0 ^ 0x6c7967656e657261ULL; +- uint64_t v3 = k1 ^ 0x7465646279746573ULL; +- +- uint64_t t; ++ uint64_t t, t2; + uint8_t *pt; + uint8_t *m; + ++ _le64toh(k0, _Py_HashSecret.siphash.k0); ++ _le64toh(k1, _Py_HashSecret.siphash.k1); ++ v0 = k0 ^ 0x736f6d6570736575ULL; ++ v1 = k1 ^ 0x646f72616e646f6dULL; ++ v2 = k0 ^ 0x6c7967656e657261ULL; ++ v3 = k1 ^ 0x7465646279746573ULL; ++ + while (src_sz >= 8) { +- uint64_t mi = _le64toh(*in); ++ uint64_t mi; ++ _le64toh(mi, *in); + in += 1; + src_sz -= 8; + v3 ^= mi; +@@ -401,7 +404,8 @@ siphash24(const void *src, Py_ssize_t sr + case 2: pt[1] = m[1]; /* fall through */ + case 1: pt[0] = m[0]; /* fall through */ + } +- b |= _le64toh(t); ++ _le64toh(t2, t); ++ b |= t2; + + v3 ^= b; + DOUBLE_ROUND(v0,v1,v2,v3); diff --git a/debian/patches/reproducible-buildinfo.diff b/debian/patches/reproducible-buildinfo.diff new file mode 100644 index 0000000..232e43e --- /dev/null +++ b/debian/patches/reproducible-buildinfo.diff @@ -0,0 +1,15 @@ +# DP: Build getbuildinfo.o with DATE/TIME values when defined + +Index: b/Makefile.pre.in +=================================================================== +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -732,6 +732,8 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \ + -DGITVERSION="\"`LC_ALL=C $(GITVERSION)`\"" \ + -DGITTAG="\"`LC_ALL=C $(GITTAG)`\"" \ + -DGITBRANCH="\"`LC_ALL=C $(GITBRANCH)`\"" \ ++ $(if $(BUILD_DATE),-DDATE='"$(BUILD_DATE)"') \ ++ $(if $(BUILD_TIME),-DTIME='"$(BUILD_TIME)"') \ + -o $@ $(srcdir)/Modules/getbuildinfo.c + + Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..9eed915 --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,34 @@ +# git-updates.diff +deb-setup.diff +deb-locations.diff +distutils-install-layout.diff +locale-module.diff +distutils-link.diff +distutils-sysconfig.diff +tkinter-import.diff +gdbm-import.diff +link-opt.diff +setup-modules.diff +platform-lsbrelease.diff +bdist-wininst-notfound.diff +profiled-build.diff +langpack-gettext.diff +disable-sem-check.diff +lib-argparse.diff +ctypes-arm.diff +# link-timemodule.diff +lto-link-flags.diff +multiarch.diff +lib2to3-no-pickled-grammar.diff +ext-no-libpython-link.diff +test-no-random-order.diff +multiarch-extname.diff +tempfile-minimal.diff +disable-some-tests.diff +ensurepip-wheels.diff +ensurepip-disabled.diff +mangle-fstack-protector.diff +reproducible-buildinfo.diff +pydoc-use-pager.diff +pyhash.diff +update-tls-protocol.diff diff --git a/debian/patches/setup-modules.diff b/debian/patches/setup-modules.diff new file mode 100644 index 0000000..8c10c06 --- /dev/null +++ b/debian/patches/setup-modules.diff @@ -0,0 +1,52 @@ +# DP: Modules/Setup.dist: patches to build some extensions statically + +Index: b/Modules/Setup.dist +=================================================================== +--- a/Modules/Setup.dist ++++ b/Modules/Setup.dist +@@ -176,7 +176,7 @@ _symtable symtablemodule.c + #_weakref _weakref.c # basic weak reference support + #_testcapi _testcapimodule.c # Python C API test module + #_random _randommodule.c # Random number generator +-#_elementtree -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI _elementtree.c # elementtree accelerator ++#_elementtree _elementtree.c -lexpat # elementtree accelerator + #_pickle _pickle.c # pickle accelerator + #_datetime _datetimemodule.c # datetime accelerator + #_bisect _bisectmodule.c # Bisection algorithms +@@ -206,10 +206,7 @@ _symtable symtablemodule.c + + # Socket module helper for SSL support; you must comment out the other + # socket line above, and possibly edit the SSL variable: +-#SSL=/usr/local/ssl +-#_ssl _ssl.c \ +-# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ +-# -L$(SSL)/lib -lssl -lcrypto ++#_ssl _ssl.c -lssl -lcrypto + + # The crypt module is now disabled by default because it breaks builds + # on many systems (where -lcrypt is needed), e.g. Linux (I believe). +@@ -244,6 +241,7 @@ _symtable symtablemodule.c + + #_md5 md5module.c + ++#_hashlib _hashopenssl.c -lssl -lcrypto + + # The _sha module implements the SHA checksum algorithms. + # (NIST's Secure Hash Algorithms.) +@@ -342,6 +340,7 @@ _symtable symtablemodule.c + # Fred Drake's interface to the Python parser + #parser parsermodule.c + ++#_ctypes _ctypes/_ctypes.c _ctypes/callbacks.c _ctypes/callproc.c _ctypes/stgdict.c _ctypes/cfield.c _ctypes/malloc_closure.c -lffi + + # Lee Busby's SIGFPE modules. + # The library to link fpectl with is platform specific. +@@ -376,7 +375,7 @@ _symtable symtablemodule.c + # + # More information on Expat can be found at www.libexpat.org. + # +-#pyexpat expat/xmlparse.c expat/xmlrole.c expat/xmltok.c pyexpat.c -I$(srcdir)/Modules/expat -DHAVE_EXPAT_CONFIG_H -DUSE_PYEXPAT_CAPI ++#pyexpat pyexpat.c -lexpat + + # Hye-Shik Chang's CJKCodecs + diff --git a/debian/patches/sysconfig-debian-schemes.diff b/debian/patches/sysconfig-debian-schemes.diff new file mode 100644 index 0000000..d26ee20 --- /dev/null +++ b/debian/patches/sysconfig-debian-schemes.diff @@ -0,0 +1,67 @@ +# DP: Add schemes 'deb_system' and 'posix_local', make the latter the default + +--- a/Lib/sysconfig.py ++++ b/Lib/sysconfig.py +@@ -32,6 +32,30 @@ + 'scripts': '{base}/bin', + 'data': '{base}', + }, ++ 'deb_system': { ++ 'stdlib': '{installed_base}/lib/python{py_version_short}', ++ 'platstdlib': '{platbase}/lib/python{py_version_short}', ++ 'purelib': '{base}/lib/python3/dist-packages', ++ 'platlib': '{platbase}/lib/python3/dist-packages', ++ 'include': ++ '{installed_base}/include/python{py_version_short}{abiflags}', ++ 'platinclude': ++ '{installed_platbase}/include/python{py_version_short}{abiflags}', ++ 'scripts': '{base}/bin', ++ 'data': '{base}', ++ }, ++ 'posix_local': { ++ 'stdlib': '{installed_base}/lib/python{py_version_short}', ++ 'platstdlib': '{platbase}/lib/python{py_version_short}', ++ 'purelib': '{base}/local/lib/python{py_version_short}/dist-packages', ++ 'platlib': '{platbase}/local/lib/python{py_version_short}/dist-packages', ++ 'include': ++ '{installed_base}/local/include/python{py_version_short}{abiflags}', ++ 'platinclude': ++ '{installed_platbase}/local/include/python{py_version_short}{abiflags}', ++ 'scripts': '{base}/local/bin', ++ 'data': '{base}', ++ }, + 'posix_home': { + 'stdlib': '{installed_base}/lib/python', + 'platstdlib': '{base}/lib/python', +@@ -162,7 +186,7 @@ + _PYTHON_BUILD = is_python_build(True) + + if _PYTHON_BUILD: +- for scheme in ('posix_prefix', 'posix_home'): ++ for scheme in ('posix_prefix', 'posix_home', 'posix_local', 'deb_system'): + _INSTALL_SCHEMES[scheme]['include'] = '{srcdir}/Include' + _INSTALL_SCHEMES[scheme]['platinclude'] = '{projectbase}/.' + +@@ -200,7 +224,12 @@ + def _get_default_scheme(): + if os.name == 'posix': + # the default scheme for posix is posix_prefix +- return 'posix_prefix' ++ if 'real_prefix' in sys.__dict__ or 'VIRTUAL_ENV' in os.environ: ++ # virtual environments ++ return 'posix_prefix' ++ else: ++ # Debian default ++ return 'posix_local' + return os.name + + +@@ -485,7 +514,7 @@ + else: + inc_dir = _sys_home or _PROJECT_BASE + else: +- inc_dir = get_path('platinclude') ++ inc_dir = get_path('platinclude', 'posix_prefix') + return os.path.join(inc_dir, 'pyconfig.h') + + diff --git a/debian/patches/tempfile-minimal.diff b/debian/patches/tempfile-minimal.diff new file mode 100644 index 0000000..64f83fc --- /dev/null +++ b/debian/patches/tempfile-minimal.diff @@ -0,0 +1,169 @@ +# DP: Avoid shutil import when it is not available. + +Index: b/Lib/tempfile.py +=================================================================== +--- a/Lib/tempfile.py ++++ b/Lib/tempfile.py +@@ -40,7 +40,146 @@ import functools as _functools + import warnings as _warnings + import io as _io + import os as _os +-import shutil as _shutil ++try: ++ import shutil as _shutil ++ _rmtree = _shutil.rmtree ++except ImportError: ++ import sys as _sys ++ import stat as _stat ++ # version vulnerable to race conditions ++ def _rmtree_unsafe(path, onerror): ++ try: ++ if _os.path.islink(path): ++ # symlinks to directories are forbidden, see bug #1669 ++ raise OSError("Cannot call rmtree on a symbolic link") ++ except OSError: ++ onerror(_os.path.islink, path, _sys.exc_info()) ++ # can't continue even if onerror hook returns ++ return ++ names = [] ++ try: ++ names = _os.listdir(path) ++ except OSError: ++ onerror(_os.listdir, path, _sys.exc_info()) ++ for name in names: ++ fullname = _os.path.join(path, name) ++ try: ++ mode = _os.lstat(fullname).st_mode ++ except OSError: ++ mode = 0 ++ if _stat.S_ISDIR(mode): ++ _rmtree_unsafe(fullname, onerror) ++ else: ++ try: ++ _os.unlink(fullname) ++ except OSError: ++ onerror(_os.unlink, fullname, _sys.exc_info()) ++ try: ++ _os.rmdir(path) ++ except OSError: ++ onerror(_os.rmdir, path, _sys.exc_info()) ++ ++ # Version using fd-based APIs to protect against races ++ def _rmtree_safe_fd(topfd, path, onerror): ++ names = [] ++ try: ++ names = _os.listdir(topfd) ++ except OSError as err: ++ err.filename = path ++ onerror(_os.listdir, path, _sys.exc_info()) ++ for name in names: ++ fullname = _os.path.join(path, name) ++ try: ++ orig_st = _os.stat(name, dir_fd=topfd, follow_symlinks=False) ++ mode = orig_st.st_mode ++ except OSError: ++ mode = 0 ++ if _stat.S_ISDIR(mode): ++ try: ++ dirfd = _os.open(name, _os.O_RDONLY, dir_fd=topfd) ++ except OSError: ++ onerror(_os.open, fullname, _sys.exc_info()) ++ else: ++ try: ++ if _os.path.samestat(orig_st, _os.fstat(dirfd)): ++ _rmtree_safe_fd(dirfd, fullname, onerror) ++ try: ++ _os.rmdir(name, dir_fd=topfd) ++ except OSError: ++ onerror(_os.rmdir, fullname, _sys.exc_info()) ++ else: ++ try: ++ # This can only happen if someone replaces ++ # a directory with a symlink after the call to ++ # stat.S_ISDIR above. ++ raise OSError("Cannot call rmtree on a symbolic " ++ "link") ++ except OSError: ++ onerror(_os.path.islink, fullname, _sys.exc_info()) ++ finally: ++ _os.close(dirfd) ++ else: ++ try: ++ _os.unlink(name, dir_fd=topfd) ++ except OSError: ++ onerror(_os.unlink, fullname, _sys.exc_info()) ++ ++ _use_fd_functions = ({_os.open, _os.stat, _os.unlink, _os.rmdir} <= ++ _os.supports_dir_fd and ++ _os.listdir in _os.supports_fd and ++ _os.stat in _os.supports_follow_symlinks) ++ ++ def _rmtree(path, ignore_errors=False, onerror=None): ++ """Recursively delete a directory tree. ++ ++ If ignore_errors is set, errors are ignored; otherwise, if onerror ++ is set, it is called to handle the error with arguments (func, ++ path, exc_info) where func is platform and implementation dependent; ++ path is the argument to that function that caused it to fail; and ++ exc_info is a tuple returned by sys.exc_info(). If ignore_errors ++ is false and onerror is None, an exception is raised. ++ ++ """ ++ if ignore_errors: ++ def onerror(*args): ++ pass ++ elif onerror is None: ++ def onerror(*args): ++ raise ++ if _use_fd_functions: ++ # While the unsafe rmtree works fine on bytes, the fd based does not. ++ if isinstance(path, bytes): ++ path = _os.fsdecode(path) ++ # Note: To guard against symlink races, we use the standard ++ # lstat()/open()/fstat() trick. ++ try: ++ orig_st = _os.lstat(path) ++ except Exception: ++ onerror(_os.lstat, path, _sys.exc_info()) ++ return ++ try: ++ fd = _os.open(path, _os.O_RDONLY) ++ except Exception: ++ onerror(_os.lstat, path, _sys.exc_info()) ++ return ++ try: ++ if _os.path.samestat(orig_st, _os.fstat(fd)): ++ _rmtree_safe_fd(fd, path, onerror) ++ try: ++ _os.rmdir(path) ++ except OSError: ++ onerror(_os.rmdir, path, _sys.exc_info()) ++ else: ++ try: ++ # symlinks to directories are forbidden, see bug #1669 ++ raise OSError("Cannot call rmtree on a symbolic link") ++ except OSError: ++ onerror(_os.path.islink, path, _sys.exc_info()) ++ finally: ++ _os.close(fd) ++ else: ++ return _rmtree_unsafe(path, onerror) ++ + import errno as _errno + from random import Random as _Random + import weakref as _weakref +@@ -794,7 +933,7 @@ class TemporaryDirectory(object): + + @classmethod + def _cleanup(cls, name, warn_message): +- _shutil.rmtree(name) ++ _rmtree(name) + _warnings.warn(warn_message, ResourceWarning) + + def __repr__(self): +@@ -808,4 +947,4 @@ class TemporaryDirectory(object): + + def cleanup(self): + if self._finalizer.detach(): +- _shutil.rmtree(self.name) ++ _rmtree(self.name) diff --git a/debian/patches/test-no-random-order.diff b/debian/patches/test-no-random-order.diff new file mode 100644 index 0000000..1c98695 --- /dev/null +++ b/debian/patches/test-no-random-order.diff @@ -0,0 +1,14 @@ +# DP: Don't run the test suite in random order. + +Index: b/Tools/scripts/run_tests.py +=================================================================== +--- a/Tools/scripts/run_tests.py ++++ b/Tools/scripts/run_tests.py +@@ -37,7 +37,6 @@ def main(regrtest_args): + args.extend(['-W', 'error::BytesWarning']) + + args.extend(['-m', 'test', # Run the test suite +- '-r', # Randomize test order + '-w', # Re-run failed tests in verbose mode + ]) + if sys.platform == 'win32': diff --git a/debian/patches/tkinter-import.diff b/debian/patches/tkinter-import.diff new file mode 100644 index 0000000..cd0c42e --- /dev/null +++ b/debian/patches/tkinter-import.diff @@ -0,0 +1,18 @@ +# DP: suggest installation of python-tk package on failing _tkinter import + +Index: b/Lib/tkinter/__init__.py +=================================================================== +--- a/Lib/tkinter/__init__.py ++++ b/Lib/tkinter/__init__.py +@@ -33,7 +33,10 @@ tk.mainloop() + import enum + import sys + +-import _tkinter # If this fails your Python may not be configured for Tk ++try: ++ import _tkinter ++except ImportError as msg: ++ raise ImportError(str(msg) + ', please install the python3-tk package') + TclError = _tkinter.TclError + from tkinter.constants import * + import re diff --git a/debian/patches/update-tls-protocol.diff b/debian/patches/update-tls-protocol.diff new file mode 100644 index 0000000..4548a4a --- /dev/null +++ b/debian/patches/update-tls-protocol.diff @@ -0,0 +1,79 @@ +Index: b/Lib/test/test_ftplib.py +=================================================================== +--- a/Lib/test/test_ftplib.py ++++ b/Lib/test/test_ftplib.py +@@ -912,7 +912,7 @@ class TestTLS_FTPClass(TestCase): + + def test_context(self): + self.client.quit() +- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + self.assertRaises(ValueError, ftplib.FTP_TLS, keyfile=CERTFILE, + context=ctx) + self.assertRaises(ValueError, ftplib.FTP_TLS, certfile=CERTFILE, +@@ -941,7 +941,7 @@ class TestTLS_FTPClass(TestCase): + + def test_check_hostname(self): + self.client.quit() +- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.check_hostname = True + ctx.load_verify_locations(CAFILE) +Index: b/Lib/test/test_httplib.py +=================================================================== +--- a/Lib/test/test_httplib.py ++++ b/Lib/test/test_httplib.py +@@ -1620,7 +1620,7 @@ class HTTPSTest(TestCase): + # The (valid) cert validates the HTTP hostname + import ssl + server = self.make_server(CERT_localhost) +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + context.verify_mode = ssl.CERT_REQUIRED + context.load_verify_locations(CERT_localhost) + h = client.HTTPSConnection('localhost', server.port, context=context) +@@ -1634,7 +1634,7 @@ class HTTPSTest(TestCase): + # The (valid) cert doesn't validate the HTTP hostname + import ssl + server = self.make_server(CERT_fakehostname) +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + context.verify_mode = ssl.CERT_REQUIRED + context.check_hostname = True + context.load_verify_locations(CERT_fakehostname) +Index: b/Lib/test/test_poplib.py +=================================================================== +--- a/Lib/test/test_poplib.py ++++ b/Lib/test/test_poplib.py +@@ -352,7 +352,7 @@ class TestPOP3Class(TestCase): + @requires_ssl + def test_stls_context(self): + expected = b'+OK Begin TLS negotiation' +- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.load_verify_locations(CAFILE) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.check_hostname = True +@@ -392,7 +392,7 @@ class TestPOP3_SSLClass(TestPOP3Class): + self.assertIn('POP3_SSL', poplib.__all__) + + def test_context(self): +- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + self.assertRaises(ValueError, poplib.POP3_SSL, self.server.host, + self.server.port, keyfile=CERTFILE, context=ctx) + self.assertRaises(ValueError, poplib.POP3_SSL, self.server.host, +Index: b/Lib/test/test_urllib2_localnet.py +=================================================================== +--- a/Lib/test/test_urllib2_localnet.py ++++ b/Lib/test/test_urllib2_localnet.py +@@ -598,7 +598,7 @@ class TestUrlopen(unittest.TestCase): + def cb_sni(ssl_sock, server_name, initial_context): + nonlocal sni_name + sni_name = server_name +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + context.set_servername_callback(cb_sni) + handler = self.start_https_server(context=context, certfile=CERT_localhost) + context = ssl.create_default_context(cafile=CERT_localhost) diff --git a/debian/patches/update-tls-protocol2.diff b/debian/patches/update-tls-protocol2.diff new file mode 100644 index 0000000..7dbe9d8 --- /dev/null +++ b/debian/patches/update-tls-protocol2.diff @@ -0,0 +1,98 @@ +# Don't apply yet, still test failures .. + +Index: b/Lib/test/test_ssl.py +=================================================================== +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -147,7 +147,7 @@ def skip_if_broken_ubuntu_ssl(func): + needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test") + + +-def test_wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLS, *, ++def test_wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1_2, *, + cert_reqs=ssl.CERT_NONE, ca_certs=None, + ciphers=None, certfile=None, keyfile=None, + **kwargs): +@@ -883,7 +883,7 @@ class ContextTests(unittest.TestCase): + self.assertEqual(ctx.protocol, proto) + + def test_ciphers(self): +- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.set_ciphers("ALL") + ctx.set_ciphers("DEFAULT") + with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"): +@@ -1542,7 +1542,7 @@ class SimpleBackgroundTests(unittest.Tes + + def test_connect_with_context(self): + # Same as test_connect, but with a separately created context +- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s: + s.connect(self.server_addr) + self.assertEqual({}, s.getpeercert()) +@@ -1562,7 +1562,7 @@ class SimpleBackgroundTests(unittest.Tes + # This should fail because we have no verification certs. Connection + # failure crashes ThreadedEchoServer, so run this in an independent + # test method. +- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.verify_mode = ssl.CERT_REQUIRED + s = ctx.wrap_socket(socket.socket(socket.AF_INET)) + self.addCleanup(s.close) +@@ -1595,7 +1595,7 @@ class SimpleBackgroundTests(unittest.Tes + with open(SIGNING_CA) as f: + pem = f.read() + der = ssl.PEM_cert_to_DER_cert(pem) +- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.load_verify_locations(cadata=pem) + with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s: +@@ -1604,7 +1604,7 @@ class SimpleBackgroundTests(unittest.Tes + self.assertTrue(cert) + + # same with DER +- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.load_verify_locations(cadata=der) + with ctx.wrap_socket(socket.socket(socket.AF_INET)) as s: +@@ -1676,7 +1676,7 @@ class SimpleBackgroundTests(unittest.Tes + + def test_get_ca_certs_capath(self): + # capath certs are loaded on request +- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.load_verify_locations(capath=CAPATH) + self.assertEqual(ctx.get_ca_certs(), []) +@@ -1689,8 +1689,8 @@ class SimpleBackgroundTests(unittest.Tes + @needs_sni + def test_context_setget(self): + # Check that the context of a connected socket can be replaced. +- ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- ctx2 = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx1 = ssl.SSLContext(ssl.PROTOCOL_TLSv1_1) ++ ctx2 = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + s = socket.socket(socket.AF_INET) + with ctx1.wrap_socket(s) as ss: + ss.connect(self.server_addr) +@@ -1740,7 +1740,7 @@ class SimpleBackgroundTests(unittest.Tes + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() +- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.verify_mode = ssl.CERT_REQUIRED + ctx.load_verify_locations(SIGNING_CA) + ctx.check_hostname = True +@@ -1773,7 +1773,7 @@ class SimpleBackgroundTests(unittest.Tes + sock.connect(self.server_addr) + incoming = ssl.MemoryBIO() + outgoing = ssl.MemoryBIO() +- ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) + ctx.verify_mode = ssl.CERT_NONE + sslobj = ctx.wrap_bio(incoming, outgoing, False) + self.ssl_io_loop(sock, incoming, outgoing, sslobj.do_handshake) |