setup.py revision 3313
1516N/A#!/usr/bin/python2.7
20N/A#
20N/A# CDDL HEADER START
20N/A#
20N/A# The contents of this file are subject to the terms of the
20N/A# Common Development and Distribution License (the "License").
20N/A# You may not use this file except in compliance with the License.
20N/A#
20N/A# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
20N/A# or http://www.opensolaris.org/os/licensing.
20N/A# See the License for the specific language governing permissions
20N/A# and limitations under the License.
20N/A#
20N/A# When distributing Covered Code, include this CDDL HEADER in each
20N/A# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
20N/A# If applicable, add the following below this CDDL HEADER, with the
20N/A# fields enclosed by brackets "[]" replaced with your own identifying
20N/A# information: Portions Copyright [yyyy] [name of copyright owner]
20N/A#
20N/A# CDDL HEADER END
20N/A#
2951N/A# Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
20N/A#
20N/A
22N/Afrom __future__ import print_function
0N/Aimport errno
50N/Aimport fnmatch
50N/Aimport os
50N/Aimport platform
50N/Aimport six
50N/Aimport stat
50N/Aimport sys
50N/Aimport shutil
50N/Aimport re
50N/Aimport subprocess
50N/Aimport tarfile
50N/Aimport tempfile
50N/Aimport py_compile
50N/Aimport hashlib
50N/Aimport time
589N/A
589N/Afrom distutils.errors import DistutilsError, DistutilsFileError
965N/Afrom distutils.core import setup
965N/Afrom distutils.cmd import Command
965N/Afrom distutils.command.install import install as _install
965N/Afrom distutils.command.install_data import install_data as _install_data
965N/Afrom distutils.command.install_lib import install_lib as _install_lib
2951N/Afrom distutils.command.build import build as _build
1836N/Afrom distutils.command.build_ext import build_ext as _build_ext
1836N/Afrom distutils.command.build_py import build_py as _build_py
382N/Afrom distutils.command.bdist import bdist as _bdist
812N/Afrom distutils.command.clean import clean as _clean
382N/Afrom distutils.dist import Distribution
382N/Afrom distutils import log
382N/A
1963N/Afrom distutils.sysconfig import get_python_inc
382N/Aimport distutils.dep_util as dep_util
1963N/Aimport distutils.dir_util as dir_util
382N/Aimport distutils.file_util as file_util
382N/Aimport distutils.util as util
382N/Aimport distutils.ccompiler
382N/Afrom distutils.unixccompiler import UnixCCompiler
382N/A
26N/Aosname = platform.uname()[0].lower()
689N/Aostype = arch = 'unknown'
689N/Aif osname == 'sunos':
466N/A arch = platform.processor()
0N/A ostype = "posix"
468N/Aelif osname == 'linux':
812N/A arch = "linux_" + platform.machine()
812N/A ostype = "posix"
52N/Aelif osname == 'windows':
812N/A arch = osname
451N/A ostype = "windows"
0N/Aelif osname == 'darwin':
382N/A arch = osname
382N/A ostype = "posix"
382N/Aelif osname == 'aix':
452N/A arch = "aix"
382N/A ostype = "posix"
452N/A
382N/Apwd = os.path.normpath(sys.path[0])
382N/A
751N/A# the version of pylint that we must have in order to run the pylint checks.
751N/Areq_pylint_version = "1.4.3"
382N/A
22N/A#
1836N/A# Unbuffer stdout and stderr. This helps to ensure that subprocess output
2507N/A# is properly interleaved with output from this program.
1836N/A#
1836N/Asys.stdout = os.fdopen(sys.stdout.fileno(), "w", 0)
2962N/Asys.stderr = os.fdopen(sys.stderr.fileno(), "w", 0)
2962N/A
2962N/Adist_dir = os.path.normpath(os.path.join(pwd, os.pardir, "proto", "dist_" + arch))
1431N/Abuild_dir = os.path.normpath(os.path.join(pwd, os.pardir, "proto", "build_" + arch))
1968N/Aif "ROOT" in os.environ and os.environ["ROOT"] != "":
873N/A root_dir = os.environ["ROOT"]
812N/Aelse:
1431N/A root_dir = os.path.normpath(os.path.join(pwd, os.pardir, "proto", "root_" + arch))
873N/Apkgs_dir = os.path.normpath(os.path.join(pwd, os.pardir, "packages", arch))
1431N/Aextern_dir = os.path.normpath(os.path.join(pwd, "extern"))
466N/Acffi_dir = os.path.normpath(os.path.join(pwd, "cffi_src"))
1431N/A
466N/A# Extract Python minor version.
466N/Apy_version = '.'.join(platform.python_version_tuple()[:2])
466N/Aassert py_version in ('2.7', '3.4')
23N/Apy_install_dir = 'usr/lib/python' + py_version + '/vendor-packages'
466N/A
466N/Apy64_executable = None
466N/A#Python 3 is always 64 bit and located in /usr/bin.
466N/Aif float(py_version) < 3 and osname == 'sunos':
466N/A if arch == 'sparc':
466N/A py64_executable = '/usr/bin/sparcv9/python' + py_version
466N/A elif arch == 'i386':
466N/A py64_executable = '/usr/bin/amd64/python' + py_version
1431N/A
1633N/Ascripts_dir = 'usr/bin'
1633N/Alib_dir = 'usr/lib'
1633N/Asvc_method_dir = 'lib/svc/method'
1633N/Asvc_share_dir = 'lib/svc/share'
466N/A
466N/Aman1_dir = 'usr/share/man/man1'
466N/Aman1m_dir = 'usr/share/man/man1m'
1633N/Aman5_dir = 'usr/share/man/man5'
1633N/Aman1_ja_JP_dir = 'usr/share/man/ja_JP.UTF-8/man1'
1633N/Aman1m_ja_JP_dir = 'usr/share/man/ja_JP.UTF-8/man1m'
1633N/Aman5_ja_JP_dir = 'usr/share/man/ja_JP.UTF-8/man5'
1633N/Aman1_zh_CN_dir = 'usr/share/man/zh_CN.UTF-8/man1'
1633N/Aman1m_zh_CN_dir = 'usr/share/man/zh_CN.UTF-8/man1m'
26N/Aman5_zh_CN_dir = 'usr/share/man/zh_CN.UTF-8/man5'
2230N/A
1968N/Aresource_dir = 'usr/share/lib/pkg'
1633N/Arad_dir = 'usr/share/lib/pkg'
2515N/Atransform_dir = 'usr/share/pkg/transforms'
2816N/Aignored_deps_dir = 'usr/share/pkg/ignored_deps'
2816N/Asmf_app_dir = 'lib/svc/manifest/application/pkg'
1937N/Aexecattrd_dir = 'etc/security/exec_attr.d'
382N/Aauthattrd_dir = 'etc/security/auth_attr.d'
2230N/Auserattrd_dir = 'etc/user_attr.d'
2230N/Asysrepo_dir = 'etc/pkg/sysrepo'
2230N/Asysrepo_dir_22 = 'etc/pkg/sysrepo/apache22'
2230N/Asysrepo_logs_dir = 'var/log/pkg/sysrepo'
2028N/Asysrepo_cache_dir = 'var/cache/pkg/sysrepo'
1968N/Adepot_dir = 'etc/pkg/depot'
1968N/Adepot_dir_22 = 'etc/pkg/depot/apache22'
2028N/Adepot_conf_dir = 'etc/pkg/depot/conf.d'
1968N/Adepot_logs_dir = 'var/log/pkg/depot'
1968N/Adepot_cache_dir = 'var/cache/pkg/depot'
1968N/Alocale_dir = 'usr/share/locale'
2028N/Amirror_logs_dir = 'var/log/pkg/mirror'
2028N/Amirror_cache_dir = 'var/cache/pkg/mirror'
2028N/A
1968N/A
1968N/A# A list of source, destination tuples of modules which should be hardlinked
1968N/A# together if the os supports it and otherwise copied.
1968N/Ahardlink_modules = []
1968N/A
1968N/Ascripts_sunos = {
589N/A scripts_dir: [
589N/A ['client.py', 'pkg'],
589N/A ['pkgdep.py', 'pkgdepend'],
589N/A ['pkgrepo.py', 'pkgrepo'],
1431N/A ['util/publish/pkgdiff.py', 'pkgdiff'],
1431N/A ['util/publish/pkgfmt.py', 'pkgfmt'],
1431N/A ['util/publish/pkglint.py', 'pkglint'],
1431N/A ['util/publish/pkgmerge.py', 'pkgmerge'],
1431N/A ['util/publish/pkgmogrify.py', 'pkgmogrify'],
858N/A ['util/publish/pkgsurf.py', 'pkgsurf'],
1633N/A ['publish.py', 'pkgsend'],
2962N/A ['pull.py', 'pkgrecv'],
2962N/A ['sign.py', 'pkgsign'],
2515N/A ],
2515N/A lib_dir: [
466N/A ['depot.py', 'pkg.depotd'],
466N/A ['sysrepo.py', 'pkg.sysrepo'],
466N/A ['depot-config.py', "pkg.depot-config"]
466N/A ],
466N/A svc_method_dir: [
466N/A ['svc/svc-pkg-depot', 'svc-pkg-depot'],
466N/A ['svc/svc-pkg-mdns', 'svc-pkg-mdns'],
466N/A ['svc/svc-pkg-mirror', 'svc-pkg-mirror'],
466N/A ['svc/svc-pkg-repositories-setup',
589N/A 'svc-pkg-repositories-setup'],
589N/A ['svc/svc-pkg-server', 'svc-pkg-server'],
589N/A ['svc/svc-pkg-sysrepo', 'svc-pkg-sysrepo'],
1191N/A ['svc/svc-pkg-sysrepo-cache',
1191N/A 'svc-pkg-sysrepo-cache'],
1191N/A ],
1191N/A svc_share_dir: [
1191N/A ['svc/pkg5_include.sh', 'pkg5_include.sh'],
2816N/A ],
2816N/A rad_dir: [
589N/A ["rad-invoke.py", "rad-invoke"],
589N/A ],
589N/A }
589N/A
812N/Ascripts_windows = {
812N/A scripts_dir: [
812N/A ['client.py', 'client.py'],
812N/A ['pkgrepo.py', 'pkgrepo.py'],
812N/A ['publish.py', 'publish.py'],
812N/A ['pull.py', 'pull.py'],
812N/A ['scripts/pkg.bat', 'pkg.bat'],
1968N/A ['scripts/pkgsend.bat', 'pkgsend.bat'],
1968N/A ['scripts/pkgrecv.bat', 'pkgrecv.bat'],
1968N/A ],
812N/A lib_dir: [
812N/A ['depot.py', 'depot.py'],
812N/A ['scripts/pkg.depotd.bat', 'pkg.depotd.bat'],
812N/A ],
1475N/A }
1475N/A
1475N/Ascripts_other_unix = {
1475N/A scripts_dir: [
975N/A ['client.py', 'client.py'],
975N/A ['pkgdep.py', 'pkgdep'],
975N/A ['util/publish/pkgdiff.py', 'pkgdiff'],
975N/A ['util/publish/pkgfmt.py', 'pkgfmt'],
1633N/A ['util/publish/pkgmogrify.py', 'pkgmogrify'],
1633N/A ['pull.py', 'pull.py'],
1633N/A ['publish.py', 'publish.py'],
1633N/A ['scripts/pkg.sh', 'pkg'],
2028N/A ['scripts/pkgsend.sh', 'pkgsend'],
1633N/A ['scripts/pkgrecv.sh', 'pkgrecv'],
1633N/A ],
1633N/A lib_dir: [
14N/A ['depot.py', 'depot.py'],
382N/A ['scripts/pkg.depotd.sh', 'pkg.depotd'],
429N/A ],
14N/A rad_dir: [
404N/A ["rad-invoke.py", "rad-invoke"],
404N/A ],
30N/A }
382N/A
30N/A# indexed by 'osname'
791N/Ascripts = {
2728N/A "sunos": scripts_sunos,
2728N/A "linux": scripts_other_unix,
689N/A "windows": scripts_windows,
1968N/A "darwin": scripts_other_unix,
1968N/A "aix" : scripts_other_unix,
1968N/A "unknown": scripts_sunos,
1968N/A }
1191N/A
258N/AMANPAGE_SRC_ROOT = "man"
1968N/AMANPAGE_OUTPUT_ROOT = MANPAGE_SRC_ROOT + "/nroff"
2816N/A
382N/Aman1_files = [
1968N/A MANPAGE_OUTPUT_ROOT + '/man1/' + f
30N/A for f in [
589N/A 'pkg.1',
589N/A 'pkgdepend.1',
1968N/A 'pkgdiff.1',
589N/A 'pkgfmt.1',
589N/A 'pkglint.1',
589N/A 'pkgmerge.1',
589N/A 'pkgmogrify.1',
1968N/A 'pkgrecv.1',
589N/A 'pkgrepo.1',
1968N/A 'pkgsend.1',
466N/A 'pkgsign.1',
466N/A 'pkgsurf.1',
2230N/A ]
1968N/A]
1968N/Aman1m_files = [
1431N/A MANPAGE_OUTPUT_ROOT + '/man1m/' + f
1968N/A for f in [
1968N/A 'pkg.depotd.1m',
54N/A 'pkg.depot-config.1m',
1968N/A 'pkg.sysrepo.1m',
1968N/A ]
2515N/A]
2816N/Aman5_files = [
2816N/A MANPAGE_OUTPUT_ROOT + '/man5/' + f
2816N/A for f in [
2816N/A 'pkg.5'
1475N/A ]
2230N/A]
466N/A
1633N/Aman1_ja_files = [
1633N/A MANPAGE_OUTPUT_ROOT + '/ja_JP.UTF-8/man1/' + f
135N/A for f in [
2230N/A 'pkg.1',
2230N/A 'pkgdepend.1',
2230N/A 'pkgdiff.1',
135N/A 'pkgfmt.1',
135N/A 'pkglint.1',
1968N/A 'pkgmerge.1',
135N/A 'pkgmogrify.1',
1968N/A 'pkgrecv.1',
382N/A 'pkgrepo.1',
382N/A 'pkgsend.1',
382N/A 'pkgsign.1',
382N/A ]
382N/A]
382N/Aman1m_ja_files = [
382N/A MANPAGE_OUTPUT_ROOT + '/ja_JP.UTF-8/man1m/' + f
382N/A for f in [
1968N/A 'pkg.depotd.1m',
382N/A 'pkg.sysrepo.1m',
1968N/A ]
1542N/A]
1542N/Aman5_ja_files = [
1968N/A MANPAGE_OUTPUT_ROOT + '/ja_JP.UTF-8/man5/' + f
1968N/A for f in [
812N/A 'pkg.5'
1968N/A ]
589N/A]
1968N/A
858N/Aman1_zh_CN_files = [
858N/A MANPAGE_OUTPUT_ROOT + '/zh_CN.UTF-8/man1/' + f
1968N/A for f in [
858N/A 'pkg.1',
858N/A 'pkgdepend.1',
858N/A 'pkgdiff.1',
858N/A 'pkgfmt.1',
858N/A 'pkglint.1',
858N/A 'pkgmerge.1',
858N/A 'pkgmogrify.1',
1968N/A 'pkgrecv.1',
2962N/A 'pkgrepo.1',
2962N/A 'pkgsend.1',
2962N/A 'pkgsign.1',
2962N/A ]
2962N/A]
2962N/Aman1m_zh_CN_files = [
2962N/A MANPAGE_OUTPUT_ROOT + '/zh_CN.UTF-8/man1m/' + f
2962N/A for f in [
2962N/A 'pkg.depotd.1m',
2962N/A 'pkg.sysrepo.1m',
1431N/A ]
1431N/A]
1431N/Aman5_zh_CN_files = [
1431N/A MANPAGE_OUTPUT_ROOT + '/zh_CN.UTF-8/man5/' + f
1431N/A for f in [
1431N/A 'pkg.5'
1431N/A ]
1431N/A]
1431N/A
1431N/Apackages = [
1431N/A 'pkg',
1431N/A 'pkg.actions',
1431N/A 'pkg.bundle',
1431N/A 'pkg.client',
1431N/A 'pkg.client.linkedimage',
1431N/A 'pkg.client.transport',
1431N/A 'pkg.file_layout',
1431N/A 'pkg.flavor',
1968N/A 'pkg.lint',
1542N/A 'pkg.portable',
1542N/A 'pkg.publish',
2515N/A 'pkg.server'
2515N/A ]
1968N/A
1968N/Apylint_targets = [
1968N/A 'pkg.altroot',
1633N/A 'pkg.client.__init__',
1633N/A 'pkg.client.api',
589N/A 'pkg.client.linkedimage',
1968N/A 'pkg.client.pkg_solver',
1902N/A 'pkg.client.pkgdefs',
1968N/A 'pkg.client.pkgremote',
1968N/A 'pkg.client.plandesc',
1968N/A 'pkg.client.printengine',
1191N/A 'pkg.client.progress',
2816N/A 'pkg.misc',
2816N/A 'pkg.pipeutils',
2816N/A ]
1191N/A
1191N/Aweb_files = []
1191N/Afor entry in os.walk("web"):
1191N/A web_dir, dirs, files = entry
2816N/A if not files:
2816N/A continue
2816N/A web_files.append((os.path.join(resource_dir, web_dir), [
2816N/A os.path.join(web_dir, f) for f in files
2816N/A if f != "Makefile"
589N/A ]))
589N/A # install same set of files in "en/" in "__LOCALE__/ as well"
589N/A # for localizable file package (regarding themes, install
589N/A # theme "oracle.com" only)
589N/A if os.path.basename(web_dir) == "en" and \
589N/A os.path.dirname(web_dir) in ("web", "web/_themes/oracle.com"):
589N/A web_files.append((os.path.join(resource_dir,
765N/A os.path.dirname(web_dir), "__LOCALE__"), [
765N/A os.path.join(web_dir, f) for f in files
765N/A if f != "Makefile"
765N/A ]))
765N/A
765N/Asmf_app_files = [
765N/A 'svc/pkg-depot.xml',
589N/A 'svc/pkg-mdns.xml',
765N/A 'svc/pkg-mirror.xml',
765N/A 'svc/pkg-repositories-setup.xml',
765N/A 'svc/pkg-server.xml',
765N/A 'svc/pkg-system-repository.xml',
765N/A 'svc/pkg-sysrepo-cache.xml',
765N/A 'svc/zoneproxy-client.xml',
765N/A 'svc/zoneproxyd.xml'
1968N/A ]
1968N/Aresource_files = [
1968N/A 'util/opensolaris.org.sections',
135N/A 'util/pkglintrc',
1968N/A ]
157N/Atransform_files = [
382N/A 'util/publish/transforms/developer',
429N/A 'util/publish/transforms/documentation',
429N/A 'util/publish/transforms/locale',
2028N/A 'util/publish/transforms/smf-manifests'
2028N/A ]
429N/Asysrepo_files = [
429N/A 'util/apache2/sysrepo/sysrepo_p5p.py',
429N/A 'util/apache2/sysrepo/sysrepo_httpd.conf.mako',
429N/A 'util/apache2/sysrepo/sysrepo_publisher_response.mako',
429N/A ]
429N/Asysrepo_files_22 = [
429N/A 'util/apache22/sysrepo/sysrepo_httpd.conf.mako',
2028N/A 'util/apache22/sysrepo/sysrepo_publisher_response.mako',
1968N/A ]
1968N/Asysrepo_log_stubs = [
1968N/A 'util/apache2/sysrepo/logs/access_log',
1968N/A 'util/apache2/sysrepo/logs/error_log',
1968N/A 'util/apache2/sysrepo/logs/rewrite.log',
1968N/A ]
1968N/Adepot_files = [
1968N/A 'util/apache2/depot/depot.conf.mako',
1968N/A 'util/apache2/depot/depot_httpd.conf.mako',
1968N/A 'util/apache2/depot/depot_index.py',
812N/A 'util/apache2/depot/depot_httpd_ssl_protocol.conf',
1968N/A ]
1968N/Adepot_files_22 = [
1968N/A 'util/apache22/depot/depot.conf.mako',
1968N/A 'util/apache22/depot/depot_httpd.conf.mako',
1968N/A 'util/apache22/depot/depot_httpd_ssl_protocol.conf',
812N/A ]
812N/Adepot_log_stubs = [
812N/A 'util/apache2/depot/logs/access_log',
1968N/A 'util/apache2/depot/logs/error_log',
812N/A 'util/apache2/depot/logs/rewrite.log',
812N/A ]
1968N/Aignored_deps_files = []
812N/A
812N/A# The apache-based depot includes an shtml file we add to the resource dir
1968N/Aweb_files.append((os.path.join(resource_dir, "web"),
812N/A ["util/apache2/depot/repos.shtml"]))
1968N/Aexecattrd_files = [
1968N/A 'util/misc/exec_attr.d/package:pkg',
1968N/A]
1968N/Aauthattrd_files = ['util/misc/auth_attr.d/package:pkg']
1968N/Auserattrd_files = ['util/misc/user_attr.d/package:pkg']
812N/Apkg_locales = \
812N/A 'ar ca cs de es fr he hu id it ja ko nl pl pt_BR ru sk sv zh_CN zh_HK zh_TW'.split()
812N/A
1968N/Asha512_t_srcs = [
812N/A 'cffi_src/_sha512_t.c'
812N/A ]
1968N/Asysattr_srcs = [
812N/A 'cffi_src/_sysattr.c'
812N/A ]
1968N/Asyscallat_srcs = [
812N/A 'cffi_src/_syscallat.c'
1968N/A ]
1968N/Apspawn_srcs = [
812N/A 'cffi_src/_pspawn.c'
1968N/A ]
812N/Aelf_srcs = [
812N/A 'modules/elf.c',
1968N/A 'modules/elfextract.c',
1968N/A 'modules/liblist.c',
812N/A ]
1968N/Aarch_srcs = [
812N/A 'cffi_src/_arch.c'
812N/A ]
873N/A_actions_srcs = [
873N/A 'modules/actions/_actions.c'
873N/A ]
873N/A_actcomm_srcs = [
873N/A 'modules/actions/_common.c'
873N/A ]
873N/A_varcet_srcs = [
812N/A 'modules/_varcet.c'
1968N/A ]
812N/Asolver_srcs = [
812N/A 'modules/solver/solver.c',
812N/A 'modules/solver/py_solver.c'
812N/A ]
812N/Asolver_link_args = ["-lm", "-lc"]
1968N/Aif osname == 'sunos':
1475N/A solver_link_args = ["-ztext"] + solver_link_args
1968N/A
975N/A# Runs lint on the extension module source code
1968N/Aclass pylint_func(Command):
1968N/A description = "Runs pylint tools over IPS python source code"
1968N/A user_options = []
1968N/A
1968N/A def initialize_options(self):
1968N/A pass
1968N/A
2230N/A def finalize_options(self):
2230N/A pass
1968N/A
2962N/A # Make string shell-friendly
2962N/A @staticmethod
2962N/A def escape(astring):
1968N/A return astring.replace(' ', '\\ ')
1968N/A
873N/A def run(self, quiet=False, py3k=False):
873N/A
1968N/A def supported_pylint_ver(version):
1968N/A """Compare the installed version against the version
873N/A we require to build with, returning False if the version
873N/A is too old. It's tempting to use pkg.version.Version
382N/A here, but since that's a build artifact, we'll do it
466N/A the long way."""
466N/A inst_pylint_ver = version.split(".")
451N/A req_pylint_ver = req_pylint_version.split(".")
1633N/A
1633N/A # if the lists are of different lengths, we just
1633N/A # compare with the precision we have.
1968N/A vers_comp = zip(inst_pylint_ver, req_pylint_ver)
1968N/A for inst, req in vers_comp:
1968N/A try:
1968N/A if int(inst) < int(req):
1968N/A return False
1968N/A elif int(inst) > int(req):
1968N/A return True
1968N/A except ValueError:
1968N/A # if we somehow get non-numeric version
1968N/A # components, we ignore them.
1968N/A continue
1968N/A return True
2515N/A
2515N/A # it's fine to default to the required version - the build will
1968N/A # break if the installed version is incompatible and $PYLINT_VER
2230N/A # didn't get set, somehow.
1968N/A pylint_ver_str = os.environ.get("PYLINT_VER",
1968N/A req_pylint_version)
1542N/A if pylint_ver_str == "":
1542N/A pylint_ver_str = req_pylint_version
445N/A
466N/A if os.environ.get("PKG_SKIP_PYLINT"):
1542N/A log.warn("WARNING: skipping pylint checks: "
1633N/A "$PKG_SKIP_PYLINT was set")
1633N/A return
1020N/A elif not pylint_ver_str or \
1020N/A not supported_pylint_ver(pylint_ver_str):
1020N/A log.warn("WARNING: skipping pylint checks: the "
1020N/A "installed version {0} is older than version {1}".format(
1020N/A pylint_ver_str, req_pylint_version))
2515N/A return
2515N/A
2515N/A proto = os.path.join(root_dir, py_install_dir)
2515N/A sys.path.insert(0, proto)
2515N/A
2515N/A
2515N/A # Insert tests directory onto sys.path so any custom checkers
2515N/A # can be found.
2515N/A sys.path.insert(0, os.path.join(pwd, 'tests'))
2515N/A # assumes pylint is accessible on the sys.path
2515N/A from pylint import lint
451N/A
1968N/A #
2230N/A # Unfortunately, pylint seems pretty fragile and will crash if
2230N/A # we try to run it over all the current pkg source. Hence for
2230N/A # now we only run it over a subset of the source. As source
2230N/A # files are made pylint clean they should be added to the
2230N/A # pylint_targets list.
2230N/A #
2230N/A if not py3k:
2230N/A args = []
2230N/A if quiet:
2230N/A args += ['--reports=no']
2515N/A args += ['--rcfile={0}'.format(os.path.join(
2515N/A pwd, 'tests', 'pylintrc'))]
1902N/A args += pylint_targets
1968N/A lint.Run(args)
1968N/A else:
1968N/A #
1968N/A # In Python 3 porting mode, all checkers will be
1968N/A # disabled and only messages emitted by the porting
1968N/A # checker will be displayed. Therefore we need to run
1968N/A # this checker separately.
1968N/A #
812N/A args = []
812N/A if quiet:
812N/A args += ['--reports=no']
812N/A args += ['--rcfile={0}'.format(os.path.join(
1968N/A pwd, 'tests', 'pylintrc_py3k'))]
1968N/A # We check all Python files in the gate.
1968N/A for root, dirs, files in os.walk(pwd):
1968N/A for f in files:
1968N/A if f.endswith(".py"):
1968N/A args += [os.path.join(root, f)]
1968N/A lint.Run(args)
1968N/A
1968N/A
1968N/Aclass pylint_func_quiet(pylint_func):
1968N/A
1968N/A def run(self, quiet=False):
1968N/A pylint_func.run(self, quiet=True)
1968N/A
1968N/Aclass pylint_func_py3k(pylint_func):
1968N/A def run(self, quiet=False, py3k=False):
1968N/A pylint_func.run(self, py3k=True)
812N/A
429N/Ainclude_dirs = [ 'modules' ]
429N/Alint_flags = [ '-u', '-axms', '-erroff=E_NAME_DEF_NOT_USED2' ]
2028N/A
1836N/A# Runs lint on the extension module source code
2230N/Aclass clint_func(Command):
1836N/A description = "Runs lint tools over IPS C extension source code"
1836N/A user_options = []
1836N/A
429N/A def initialize_options(self):
612N/A pass
1542N/A
1968N/A def finalize_options(self):
1968N/A pass
1968N/A
1968N/A # Make string shell-friendly
1968N/A @staticmethod
1968N/A def escape(astring):
1968N/A return astring.replace(' ', '\\ ')
1968N/A
1968N/A def run(self):
1968N/A if "LINT" in os.environ and os.environ["LINT"] != "":
1968N/A lint = [os.environ["LINT"]]
1968N/A else:
1968N/A lint = ['lint']
1968N/A if osname == 'sunos' or osname == "linux":
1968N/A archcmd = lint + lint_flags + \
1968N/A ['-D_FILE_OFFSET_BITS=64'] + \
1968N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
1968N/A ['-I' + self.escape(get_python_inc())] + \
1968N/A arch_srcs
1968N/A elfcmd = lint + lint_flags + \
1968N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
1968N/A ['-I' + self.escape(get_python_inc())] + \
1968N/A ["{0}{1}".format("-l", k) for k in elf_libraries] + \
1968N/A elf_srcs
1968N/A _actionscmd = lint + lint_flags + \
1968N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
1968N/A ['-I' + self.escape(get_python_inc())] + \
1968N/A _actions_srcs
1968N/A _actcommcmd = lint + lint_flags + \
1968N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
1968N/A ['-I' + self.escape(get_python_inc())] + \
1968N/A _actcomm_srcs
1968N/A _varcetcmd = lint + lint_flags + \
812N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
1968N/A ['-I' + self.escape(get_python_inc())] + \
2028N/A _varcet_srcs
812N/A pspawncmd = lint + lint_flags + \
812N/A ['-D_FILE_OFFSET_BITS=64'] + \
812N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
812N/A ['-I' + self.escape(get_python_inc())] + \
812N/A pspawn_srcs
812N/A syscallatcmd = lint + lint_flags + \
812N/A ['-D_FILE_OFFSET_BITS=64'] + \
812N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
812N/A ['-I' + self.escape(get_python_inc())] + \
873N/A syscallat_srcs
1836N/A sysattrcmd = lint + lint_flags + \
1836N/A ['-D_FILE_OFFSET_BITS=64'] + \
1836N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
1836N/A ['-I' + self.escape(get_python_inc())] + \
812N/A ["{0}{1}".format("-l", k) for k in sysattr_libraries] + \
812N/A sysattr_srcs
812N/A sha512_tcmd = lint + lint_flags + \
812N/A ['-D_FILE_OFFSET_BITS=64'] + \
1968N/A ["{0}{1}".format("-I", k) for k in include_dirs] + \
1968N/A ['-I' + self.escape(get_python_inc())] + \
1968N/A ["{0}{1}".format("-l", k) for k in sha512_t_libraries] + \
1968N/A sha512_t_srcs
1968N/A
1968N/A print(" ".join(archcmd))
1968N/A os.system(" ".join(archcmd))
1968N/A print(" ".join(elfcmd))
1968N/A os.system(" ".join(elfcmd))
1968N/A print(" ".join(_actionscmd))
1968N/A os.system(" ".join(_actionscmd))
1968N/A print(" ".join(_actcommcmd))
812N/A os.system(" ".join(_actcommcmd))
1968N/A print(" ".join(_varcetcmd))
812N/A os.system(" ".join(_varcetcmd))
812N/A print(" ".join(pspawncmd))
812N/A os.system(" ".join(pspawncmd))
812N/A print(" ".join(syscallatcmd))
812N/A os.system(" ".join(syscallatcmd))
1968N/A print(" ".join(sysattrcmd))
1968N/A os.system(" ".join(sysattrcmd))
1968N/A print(" ".join(sha512_tcmd))
1968N/A os.system(" ".join(sha512_tcmd))
812N/A
812N/A
812N/A# Runs both C and Python lint
812N/Aclass lint_func(Command):
812N/A description = "Runs C and Python lint checkers"
873N/A user_options = []
1836N/A
1836N/A def initialize_options(self):
812N/A pass
873N/A
1836N/A def finalize_options(self):
1836N/A pass
1836N/A
812N/A # Make string shell-friendly
812N/A @staticmethod
812N/A def escape(astring):
812N/A return astring.replace(' ', '\\ ')
812N/A
452N/A def run(self):
466N/A clint_func(Distribution()).run()
858N/A pylint_func(Distribution()).run()
382N/A
466N/Aclass install_func(_install):
965N/A def initialize_options(self):
858N/A _install.initialize_options(self)
2230N/A
382N/A # PRIVATE_BUILD set in the environment tells us to put the build
858N/A # directory into the .pyc files, rather than the final
858N/A # installation directory.
858N/A private_build = os.getenv("PRIVATE_BUILD", None)
382N/A
742N/A if private_build is None:
858N/A self.install_lib = py_install_dir
466N/A self.install_data = os.path.sep
466N/A self.root = root_dir
1968N/A else:
858N/A self.install_lib = os.path.join(root_dir, py_install_dir)
858N/A self.install_data = root_dir
858N/A
858N/A # This is used when installing scripts, below, but it isn't a
858N/A # standard distutils variable.
858N/A self.root_dir = root_dir
858N/A
858N/A def run(self):
858N/A """At the end of the install function, we need to rename some
858N/A files because distutils provides no way to rename files as they
858N/A are placed in their install locations.
466N/A """
466N/A
466N/A _install.run(self)
466N/A
466N/A for o_src, o_dest in hardlink_modules:
466N/A for e in [".py", ".pyc"]:
466N/A src = util.change_root(self.root_dir, o_src + e)
466N/A dest = util.change_root(
466N/A self.root_dir, o_dest + e)
466N/A if ostype == "posix":
466N/A if os.path.exists(dest) and \
466N/A os.stat(src)[stat.ST_INO] != \
1968N/A os.stat(dest)[stat.ST_INO]:
466N/A os.remove(dest)
466N/A file_util.copy_file(src, dest,
466N/A link="hard", update=1)
466N/A else:
466N/A file_util.copy_file(src, dest, update=1)
466N/A
466N/A # XXX Uncomment it when we need to deliver python 3.4 version
466N/A # of modules.
466N/A # Don't install the scripts for python 3.4.
466N/A # if py_version == '3.4':
466N/A # return
466N/A for d, files in six.iteritems(scripts[osname]):
466N/A for (srcname, dstname) in files:
466N/A dst_dir = util.change_root(self.root_dir, d)
466N/A dst_path = util.change_root(self.root_dir,
1968N/A os.path.join(d, dstname))
1968N/A dir_util.mkpath(dst_dir, verbose=True)
1968N/A file_util.copy_file(srcname, dst_path,
466N/A update=True)
382N/A # make scripts executable
612N/A os.chmod(dst_path,
612N/A os.stat(dst_path).st_mode
612N/A | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
612N/A
1431N/Aclass install_lib_func(_install_lib):
1431N/A """Remove the target files prior to the standard install_lib procedure
2028N/A if the build_py module has determined that they've actually changed.
2028N/A This may be needed when a module's timestamp goes backwards in time, if
2028N/A a working-directory change is reverted, or an older changeset is checked
2028N/A out.
2028N/A """
2028N/A
2028N/A def install(self):
2028N/A build_py = self.get_finalized_command("build_py")
2028N/A prefix_len = len(self.build_dir) + 1
2028N/A for p in build_py.copied:
2028N/A id_p = os.path.join(self.install_dir, p[prefix_len:])
1431N/A rm_f(id_p)
1968N/A if self.compile:
1968N/A rm_f(id_p + "c")
1968N/A if self.optimize > 0:
2028N/A rm_f(id_p + "o")
2515N/A return _install_lib.install(self)
2515N/A
2515N/Aclass install_data_func(_install_data):
1431N/A """Enhance the standard install_data subcommand to take not only a list
1895N/A of filenames, but a list of source and destination filename tuples, for
1431N/A the cases where a filename needs to be renamed between the two
1431N/A locations."""
1672N/A
1672N/A def run(self):
1672N/A self.mkpath(self.install_dir)
1968N/A for f in self.data_files:
1672N/A dir, files = f
1431N/A dir = util.convert_path(dir)
1431N/A if not os.path.isabs(dir):
2028N/A dir = os.path.join(self.install_dir, dir)
2028N/A elif self.root:
2028N/A dir = change_root(self.root, dir)
2028N/A self.mkpath(dir)
2028N/A
2028N/A if not files:
612N/A self.outfiles.append(dir)
617N/A else:
2065N/A for file in files:
2065N/A if isinstance(file, six.string_types):
2065N/A infile = file
2065N/A outfile = os.path.join(dir,
2028N/A os.path.basename(file))
2028N/A else:
2028N/A infile, outfile = file
2028N/A infile = util.convert_path(infile)
2028N/A outfile = util.convert_path(outfile)
2028N/A if os.path.sep not in outfile:
2028N/A outfile = os.path.join(dir,
2028N/A outfile)
1431N/A self.copy_file(infile, outfile)
1431N/A self.outfiles.append(outfile)
1431N/A
975N/Adef run_cmd(args, swdir, updenv=None, ignerr=False, savestderr=None):
1779N/A if updenv:
1431N/A # use temp environment modified with the given dict
1431N/A env = os.environ.copy()
617N/A env.update(updenv)
1542N/A else:
1542N/A # just use environment of this (parent) process as is
1542N/A env = os.environ
2028N/A if ignerr:
1542N/A # send stderr to devnull
1542N/A stderr = open(os.devnull)
1542N/A elif savestderr:
1542N/A stderr = savestderr
1779N/A else:
1542N/A # just use stderr of this (parent) process
1542N/A stderr = None
1542N/A ret = subprocess.Popen(args, cwd=swdir, env=env,
1542N/A stderr=stderr).wait()
2028N/A if ret != 0:
1542N/A if stderr:
1542N/A stderr.close()
1542N/A print("install failed and returned {0:d}.".format(ret),
1431N/A file=sys.stderr)
1431N/A print("Command was: {0}".format(" ".join(args)),
1968N/A file=sys.stderr)
1431N/A
1968N/A sys.exit(1)
612N/A if stderr:
451N/A stderr.close()
382N/A
452N/Adef _copy_file_contents(src, dst, buffer_size=16*1024):
452N/A """A clone of distutils.file_util._copy_file_contents() that strips the
452N/A CDDL text. For Python files, we replace the CDDL text with an equal
452N/A number of empty comment lines so that line numbers match between the
873N/A source and destination files."""
452N/A
382N/A # Match the lines between and including the CDDL header signposts, as
382N/A # well as empty comment lines before and after, if they exist.
1431N/A cddl_re = re.compile("\n(#\s*\n)?^[^\n]*CDDL HEADER START.+"
382N/A "CDDL HEADER END[^\n]*$(\n#\s*$)?", re.MULTILINE|re.DOTALL)
382N/A
382N/A # Look for shebang line to replace with arch-specific Python executable.
145N/A shebang_re = re.compile('^#!.*python[0-9]\.[0-9]')
1968N/A first_buf = True
451N/A
451N/A with open(src, "r") as sfp:
451N/A try:
451N/A os.unlink(dst)
451N/A except EnvironmentError as e:
451N/A if e.errno != errno.ENOENT:
451N/A raise DistutilsFileError("could not delete "
451N/A "'{0}': {1}".format(dst, e))
451N/A
451N/A with open(dst, "w") as dfp:
451N/A while True:
451N/A buf = sfp.read(buffer_size)
451N/A if not buf:
451N/A break
451N/A if src.endswith(".py"):
451N/A match = cddl_re.search(buf)
451N/A if match:
451N/A # replace the CDDL expression
1902N/A # with the same number of empty
2230N/A # comment lines as the cddl_re
1902N/A # matched.
2065N/A substr = buf[
2065N/A match.start():match.end()]
2065N/A count = len(
2065N/A substr.split("\n")) - 2
2065N/A blanks = "#\n" * count
2065N/A buf = cddl_re.sub("\n" + blanks,
2065N/A buf)
2507N/A
2507N/A if not first_buf or not py64_executable:
2507N/A dfp.write(buf)
2507N/A continue
2507N/A
2507N/A fl = buf[:buf.find(os.linesep) + 1]
814N/A sb_match = shebang_re.search(fl)
1431N/A if sb_match:
466N/A buf = shebang_re.sub(
873N/A "#!" + py64_executable,
812N/A buf)
812N/A else:
873N/A buf = cddl_re.sub("", buf)
812N/A dfp.write(buf)
first_buf = False
# Make file_util use our version of _copy_file_contents
file_util._copy_file_contents = _copy_file_contents
def intltool_update_maintain():
"""Check if scope of localization looks up-to-date or possibly not,
by comparing file set described in po/POTFILES.{in,skip} and
actual source files (e.g. .py) detected.
"""
rm_f("po/missing")
rm_f("po/notexist")
args = [
"/usr/bin/intltool-update", "--maintain"
]
print(" ".join(args))
podir = os.path.join(os.getcwd(), "po")
run_cmd(args, podir, updenv={"LC_ALL": "C"}, ignerr=True)
if os.path.exists("po/missing"):
print("New file(s) with translatable strings detected:",
file=sys.stderr)
missing = open("po/missing", "r")
print("--------", file=sys.stderr)
for fn in missing:
print("{0}".format(fn.strip()), file=sys.stderr)
print("--------", file=sys.stderr)
missing.close()
print("""\
Please evaluate whether any of the above file(s) needs localization.
If so, please add its name to po/POTFILES.in. If not (e.g., it's not
delivered), please add its name to po/POTFILES.skip.
Please be sure to maintain alphabetical ordering in both files.""", file=sys.stderr)
sys.exit(1)
if os.path.exists("po/notexist"):
print("""\
The following files are listed in po/POTFILES.in, but no longer exist
in the workspace:""", file=sys.stderr)
notexist = open("po/notexist", "r")
print("--------", file=sys.stderr)
for fn in notexist:
print("{0}".format(fn.strip()), file=sys.stderr)
print("--------", file=sys.stderr)
notexist.close()
print("Please remove the file names from po/POTFILES.in",
file=sys.stderr)
sys.exit(1)
def intltool_update_pot():
"""Generate pkg.pot by extracting localizable strings from source
files (e.g. .py)
"""
rm_f("po/pkg.pot")
args = [
"/usr/bin/intltool-update", "--pot"
]
print(" ".join(args))
podir = os.path.join(os.getcwd(), "po")
run_cmd(args, podir,
updenv={"LC_ALL": "C", "XGETTEXT": "/usr/gnu/bin/xgettext"})
if not os.path.exists("po/pkg.pot"):
print("Failed in generating pkg.pot.", file=sys.stderr)
sys.exit(1)
def intltool_merge(src, dst):
if not dep_util.newer(src, dst):
return
args = [
"/usr/bin/intltool-merge", "-d", "-u",
"-c", "po/.intltool-merge-cache", "po", src, dst
]
print(" ".join(args))
run_cmd(args, os.getcwd(), updenv={"LC_ALL": "C"})
def i18n_check():
"""Checks for common i18n messaging bugs in the source."""
src_files = []
# A list of the i18n errors we check for in the code
common_i18n_errors = [
# This checks that messages with multiple parameters are always
# written using "{name}" format, rather than just "{0}"
"format string with unnamed arguments cannot be properly localized"
]
for line in open("po/POTFILES.in", "r").readlines():
if line.startswith("["):
continue
if line.startswith("#"):
continue
src_files.append(line.rstrip())
args = [
"/usr/gnu/bin/xgettext", "--from-code=UTF-8", "-o", "/dev/null"]
args += src_files
xgettext_output_path = tempfile.mkstemp()[1]
xgettext_output = open(xgettext_output_path, "w")
run_cmd(args, os.getcwd(), updenv={"LC_ALL": "C"},
savestderr=xgettext_output)
found_errs = False
i18n_errs = open("po/i18n_errs.txt", "w")
for line in open(xgettext_output_path, "r").readlines():
for err in common_i18n_errors:
if err in line:
i18n_errs.write(line)
found_errs = True
i18n_errs.close()
if found_errs:
print("""\
The following i18n errors were detected and should be corrected:
(this list is saved in po/i18n_errs.txt)
""", file=sys.stderr)
for line in open("po/i18n_errs.txt", "r"):
print(line.rstrip(), file=sys.stderr)
sys.exit(1)
os.remove(xgettext_output_path)
def msgfmt(src, dst):
if not dep_util.newer(src, dst):
return
args = ["/usr/bin/msgfmt", "-o", dst, src]
print(" ".join(args))
run_cmd(args, os.getcwd())
def localizablexml(src, dst):
"""create XML help for localization, where French part of legalnotice
is stripped off
"""
if not dep_util.newer(src, dst):
return
fsrc = open(src, "r")
fdst = open(dst, "w")
# indicates currently in French part of legalnotice
in_fr = False
for l in fsrc:
if in_fr: # in French part
if l.startswith('</legalnotice>'):
# reached end of legalnotice
print(l, file=fdst)
in_fr = False
elif l.startswith('<para lang="fr"/>') or \
l.startswith('<para lang="fr"></para>'):
in_fr = True
else:
# not in French part
print(l, file=fdst)
fsrc.close()
fdst.close()
def xml2po_gen(src, dst):
"""Input is English XML file. Output is pkg_help.pot, message
source for next translation update.
"""
if not dep_util.newer(src, dst):
return
args = ["/usr/bin/xml2po", "-o", dst, src]
print(" ".join(args))
run_cmd(args, os.getcwd())
def xml2po_merge(src, dst, mofile):
"""Input is English XML file and <lang>.po file (which contains
translations). Output is translated XML file.
"""
msgfmt(mofile[:-3] + ".po", mofile)
monewer = dep_util.newer(mofile, dst)
srcnewer = dep_util.newer(src, dst)
if not srcnewer and not monewer:
return
args = ["/usr/bin/xml2po", "-t", mofile, "-o", dst, src]
print(" ".join(args))
run_cmd(args, os.getcwd())
class installfile(Command):
user_options = [
("file=", "f", "source file to copy"),
("dest=", "d", "destination directory"),
("mode=", "m", "file mode"),
]
description = "De-CDDLing file copy"
def initialize_options(self):
self.file = None
self.dest = None
self.mode = None
def finalize_options(self):
if self.mode is None:
self.mode = 0o644
elif isinstance(self.mode, six.string_types):
try:
self.mode = int(self.mode, 8)
except ValueError:
self.mode = 0o644
def run(self):
dest_file = os.path.join(self.dest, os.path.basename(self.file))
ret = self.copy_file(self.file, dest_file)
os.chmod(dest_file, self.mode)
os.utime(dest_file, None)
return ret
class build_func(_build):
sub_commands = _build.sub_commands + [('build_data', None)]
def initialize_options(self):
_build.initialize_options(self)
self.build_base = build_dir
def get_hg_version():
try:
p = subprocess.Popen(['hg', 'id', '-i'], stdout = subprocess.PIPE)
return p.communicate()[0].strip()
except OSError:
print("ERROR: unable to obtain mercurial version",
file=sys.stderr)
return "unknown"
def syntax_check(filename):
""" Run python's compiler over the file, and discard the results.
Arrange to generate an exception if the file does not compile.
This is needed because distutil's own use of pycompile (in the
distutils.utils module) is broken, and doesn't stop on error. """
try:
py_compile.compile(filename, os.devnull, doraise=True)
except py_compile.PyCompileError as e:
res = ""
for err in e.exc_value:
if isinstance(err, six.string_types):
res += err + "\n"
continue
# Assume it's a tuple of (filename, lineno, col, code)
fname, line, col, code = err
res += "line {0:d}, column {1}, in {2}:\n{3}".format(
line, col or "unknown", fname, code)
raise DistutilsError(res)
# On Solaris, ld inserts the full argument to the -o option into the symbol
# table. This means that the resulting object will be different depending on
# the path at which the workspace lives, and not just on the interesting content
# of the object.
#
# In order to work around that bug (7076871), we create a new compiler class
# that looks at the argument indicating the output file, chdirs to its
# directory, and runs the real link with the output file set to just the base
# name of the file.
#
# Unfortunately, distutils isn't too customizable in this regard, so we have to
# twiddle with a couple of the names in the distutils.ccompiler namespace: we
# have to add a new entry to the compiler_class dict, and we have to override
# the new_compiler() function to point to our own. Luckily, our copy of
# new_compiler() gets to be very simple, since we always know what we want to
# return.
class MyUnixCCompiler(UnixCCompiler):
def link(self, *args, **kwargs):
output_filename = args[2]
output_dir = kwargs.get('output_dir')
cwd = os.getcwd()
assert(not output_dir)
output_dir = os.path.join(cwd, os.path.dirname(output_filename))
output_filename = os.path.basename(output_filename)
nargs = args[:2] + (output_filename,) + args[3:]
if not os.path.exists(output_dir):
os.mkdir(output_dir, 0o755)
os.chdir(output_dir)
UnixCCompiler.link(self, *nargs, **kwargs)
os.chdir(cwd)
distutils.ccompiler.compiler_class['myunix'] = (
'unixccompiler', 'MyUnixCCompiler',
'standard Unix-style compiler with a link stage modified for Solaris'
)
def my_new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
return MyUnixCCompiler(None, dry_run, force)
if osname == 'sunos':
distutils.ccompiler.new_compiler = my_new_compiler
class build_ext_func(_build_ext):
def initialize_options(self):
_build_ext.initialize_options(self)
self.build64 = False
if osname == 'sunos':
self.compiler = 'myunix'
def build_extension(self, ext):
# Build 32-bit
_build_ext.build_extension(self, ext)
if not ext.build_64:
return
# Set up for 64-bit
old_build_temp = self.build_temp
d, f = os.path.split(self.build_temp)
# store our 64-bit extensions elsewhere
self.build_temp = d + "/temp64.{0}".format(
os.path.basename(self.build_temp).replace("temp.", ""))
ext.extra_compile_args += ["-m64"]
ext.extra_link_args += ["-m64"]
self.build64 = True
# Build 64-bit
_build_ext.build_extension(self, ext)
# Reset to 32-bit
self.build_temp = old_build_temp
ext.extra_compile_args.remove("-m64")
ext.extra_link_args.remove("-m64")
self.build64 = False
def get_ext_fullpath(self, ext_name):
path = _build_ext.get_ext_fullpath(self, ext_name)
if not self.build64:
return path
dpath, fpath = os.path.split(path)
return os.path.join(dpath, "64", fpath)
class build_py_func(_build_py):
def __init__(self, dist):
ret = _build_py.__init__(self, dist)
self.copied = []
# Gather the timestamps of the .py files in the gate, so we can
# force the mtimes of the built and delivered copies to be
# consistent across builds, causing their corresponding .pyc
# files to be unchanged unless the .py file content changed.
self.timestamps = {}
p = subprocess.Popen(
[sys.executable, os.path.join(pwd, "pydates")],
stdout=subprocess.PIPE)
for line in p.stdout:
stamp, path = line.split()
stamp = float(stamp)
self.timestamps[path] = stamp
if p.wait() != 0:
print("ERROR: unable to gather .py timestamps",
file=sys.stderr)
sys.exit(1)
# Before building extensions, we need to generate .c files
# for the C extension modules by running the CFFI build
# script files.
for path in os.listdir(cffi_dir):
if not path.startswith("build_"):
continue
path = os.path.join(cffi_dir, path)
# make scripts executable
os.chmod(path,
os.stat(path).st_mode
| stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
# run the scripts
p = subprocess.Popen(
[sys.executable, path])
return ret
# override the build_module method to do VERSION substitution on
# pkg/__init__.py
def build_module (self, module, module_file, package):
if module == "__init__" and package == "pkg":
versionre = '(?m)^VERSION[^"]*"([^"]*)"'
# Grab the previously-built version out of the build
# tree.
try:
ocontent = \
open(self.get_module_outfile(self.build_lib,
[package], module)).read()
ov = re.search(versionre, ocontent).group(1)
except IOError:
ov = None
v = get_hg_version()
vstr = 'VERSION = "{0}"'.format(v)
# If the versions haven't changed, there's no need to
# recompile.
if v == ov:
return
mcontent = open(module_file).read()
mcontent = re.sub(versionre, vstr, mcontent)
tmpfd, tmp_file = tempfile.mkstemp()
os.write(tmpfd, mcontent)
os.close(tmpfd)
print("doing version substitution: ", v)
rv = _build_py.build_module(self, module, tmp_file, package)
os.unlink(tmp_file)
return rv
# Will raise a DistutilsError on failure.
syntax_check(module_file)
return _build_py.build_module(self, module, module_file, package)
def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1,
link=None, level=1):
# If the timestamp on the source file (coming from mercurial if
# unchanged, or from the filesystem if changed) doesn't match
# the filesystem timestamp on the destination, then force the
# copy to make sure the right data is in place.
try:
dst_mtime = os.stat(outfile).st_mtime
except OSError as e:
if e.errno != errno.ENOENT:
raise
dst_mtime = time.time()
# The timestamp for __init__.py is the timestamp for the
# workspace itself.
if outfile.endswith("/pkg/__init__.py"):
src_mtime = self.timestamps["."]
else:
src_mtime = self.timestamps.get(
os.path.join("src", infile), self.timestamps["."])
# Force a copy of the file if the source timestamp is different
# from that of the destination, not just if it's newer. This
# allows timestamps in the working directory to regress (for
# instance, following the reversion of a change).
if dst_mtime != src_mtime:
f = self.force
self.force = True
dst, copied = _build_py.copy_file(self, infile, outfile,
preserve_mode, preserve_times, link, level)
self.force = f
else:
dst, copied = outfile, 0
# If we copied the file, then we need to go and readjust the
# timestamp on the file to match what we have in our database.
# Save the filename aside for our version of install_lib.
if copied and dst.endswith(".py"):
os.utime(dst, (src_mtime, src_mtime))
self.copied.append(dst)
return dst, copied
def manpage_input_dir(path):
"""Convert a manpage output path to the directory where its source lives."""
patharr = path.split("/")
if len(patharr) == 4:
loc = ""
elif len(patharr) == 5:
loc = patharr[-3].split(".")[0]
else:
raise RuntimeError("bad manpage path")
return os.path.join(patharr[0], loc).rstrip("/")
def xml2roff(files):
"""Convert XML manpages to ROFF for delivery.
The input should be a list of the output file paths. The corresponding
inputs will be generated from this. We do it in this way so that we can
share the paths with the install code.
All paths should have a common manpath root. In particular, pages
belonging to different localizations should be run through this function
separately.
"""
input_dir = manpage_input_dir(files[0])
do_files = [
os.path.join(input_dir, os.path.basename(f))
for f in files
if dep_util.newer(os.path.join(input_dir, os.path.basename(f)), f)
]
if do_files:
# Get the output dir by removing the filename and the manX
# directory
output_dir = os.path.join(*files[0].split("/")[:-2])
args = ["/usr/share/xml/xsolbook/python/xml2roff.py", "-o", output_dir]
args += do_files
print(" ".join(args))
run_cmd(args, os.getcwd())
class build_data_func(Command):
description = "build data files whose source isn't in deliverable form"
user_options = []
# As a subclass of distutils.cmd.Command, these methods are required to
# be implemented.
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# Anything that gets created here should get deleted in
# clean_func.run() below.
i18n_check()
for l in pkg_locales:
msgfmt("po/{0}.po".format(l), "po/{0}.mo".format(l))
# generate pkg.pot for next translation
intltool_update_maintain()
intltool_update_pot()
xml2roff(man1_files + man1m_files + man5_files)
xml2roff(man1_ja_files + man1m_ja_files + man5_ja_files)
xml2roff(man1_zh_CN_files + man1m_zh_CN_files + man5_zh_CN_files)
def rm_f(filepath):
"""Remove a file without caring whether it exists."""
try:
os.unlink(filepath)
except OSError as e:
if e.errno != errno.ENOENT:
raise
class clean_func(_clean):
def initialize_options(self):
_clean.initialize_options(self)
self.build_base = build_dir
def run(self):
_clean.run(self)
rm_f("po/.intltool-merge-cache")
for l in pkg_locales:
rm_f("po/{0}.mo".format(l))
rm_f("po/pkg.pot")
rm_f("po/i18n_errs.txt")
shutil.rmtree(MANPAGE_OUTPUT_ROOT, True)
class clobber_func(Command):
user_options = []
description = "Deletes any and all files created by setup"
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# nuke everything
print("deleting " + dist_dir)
shutil.rmtree(dist_dir, True)
print("deleting " + build_dir)
shutil.rmtree(build_dir, True)
print("deleting " + root_dir)
shutil.rmtree(root_dir, True)
print("deleting " + pkgs_dir)
shutil.rmtree(pkgs_dir, True)
print("deleting " + extern_dir)
shutil.rmtree(extern_dir, True)
# These files generated by the CFFI build scripts are useless
# at this point, therefore clean them up.
print("deleting temporary files generated by CFFI")
for path in os.listdir(cffi_dir):
if not path.startswith("_"):
continue
path = os.path.join(cffi_dir, path)
rm_f(path)
class test_func(Command):
# NOTE: these options need to be in sync with tests/run.py and the
# list of options stored in initialize_options below. The first entry
# in each tuple must be the exact name of a member variable.
user_options = [
("archivedir=", 'a', "archive failed tests <dir>"),
("baselinefile=", 'b', "baseline file <file>"),
("coverage", "c", "collect code coverage data"),
("genbaseline", 'g', "generate test baseline"),
("only=", "o", "only <regex>"),
("parseable", 'p', "parseable output"),
("port=", "z", "lowest port to start a depot on"),
("timing", "t", "timing file <file>"),
("verbosemode", 'v', "run tests in verbose mode"),
("stoponerr", 'x', "stop when a baseline mismatch occurs"),
("debugoutput", 'd', "emit debugging output"),
("showonexpectedfail", 'f',
"show all failure info, even for expected fails"),
("startattest=", 's', "start at indicated test"),
("jobs=", 'j', "number of parallel processes to use"),
("quiet", "q", "use the dots as the output format"),
("livesystem", 'l', "run tests on live system"),
]
description = "Runs unit and functional tests"
def initialize_options(self):
self.only = ""
self.baselinefile = ""
self.verbosemode = 0
self.parseable = 0
self.genbaseline = 0
self.timing = 0
self.coverage = 0
self.stoponerr = 0
self.debugoutput = 0
self.showonexpectedfail = 0
self.startattest = ""
self.archivedir = ""
self.port = 12001
self.jobs = 1
self.quiet = False
self.livesystem = False
def finalize_options(self):
pass
def run(self):
os.putenv('PYEXE', sys.executable)
os.chdir(os.path.join(pwd, "tests"))
# Reconstruct the cmdline and send that to run.py
cmd = [sys.executable, "run.py"]
args = ""
if "test" in sys.argv:
args = sys.argv[sys.argv.index("test")+1:]
cmd.extend(args)
subprocess.call(cmd)
class dist_func(_bdist):
def initialize_options(self):
_bdist.initialize_options(self)
self.dist_dir = dist_dir
class Extension(distutils.core.Extension):
# This class wraps the distutils Extension class, allowing us to set
# build_64 in the object constructor instead of being forced to add it
# after the object has been created.
def __init__(self, name, sources, build_64=False, **kwargs):
distutils.core.Extension.__init__(self, name, sources, **kwargs)
self.build_64 = build_64
# These are set to real values based on the platform, down below
compile_args = None
if osname in ("sunos", "linux", "darwin"):
compile_args = [ "-O3" ]
if osname == "sunos":
link_args = [ "-zstrip-class=nonalloc" ]
else:
link_args = []
ext_modules = [
Extension(
'actions._actions',
_actions_srcs,
include_dirs = include_dirs,
extra_compile_args = compile_args,
extra_link_args = link_args,
build_64 = True
),
Extension(
'actions._common',
_actcomm_srcs,
include_dirs = include_dirs,
extra_compile_args = compile_args,
extra_link_args = link_args,
build_64 = True
),
Extension(
'_varcet',
_varcet_srcs,
include_dirs = include_dirs,
extra_compile_args = compile_args,
extra_link_args = link_args,
build_64 = True
),
Extension(
'solver',
solver_srcs,
include_dirs = include_dirs + ["."],
extra_compile_args = compile_args,
extra_link_args = link_args + solver_link_args,
define_macros = [('_FILE_OFFSET_BITS', '64')],
build_64 = True
),
]
elf_libraries = None
sysattr_libraries = None
sha512_t_libraries = None
data_files = web_files
cmdclasses = {
'install': install_func,
'install_data': install_data_func,
'install_lib': install_lib_func,
'build': build_func,
'build_data': build_data_func,
'build_ext': build_ext_func,
'build_py': build_py_func,
'bdist': dist_func,
'lint': lint_func,
'clint': clint_func,
'pylint': pylint_func,
'pylint_quiet': pylint_func_quiet,
'pylint_py3k': pylint_func_py3k,
'clean': clean_func,
'clobber': clobber_func,
'test': test_func,
'installfile': installfile,
}
# all builds of IPS should have manpages
english_manpage_files = [
(man1_dir, man1_files),
(man1m_dir, man1m_files),
(man5_dir, man5_files),
]
data_files += english_manpage_files
data_files += [
(man1_ja_JP_dir, man1_ja_files),
(man1m_ja_JP_dir, man1m_ja_files),
(man5_ja_JP_dir, man5_ja_files),
(man1_zh_CN_dir, man1_zh_CN_files),
(man1m_zh_CN_dir, man1m_zh_CN_files),
(man5_zh_CN_dir, man5_zh_CN_files),
]
# add resource files
data_files += [
(resource_dir, resource_files)
]
# add transforms
data_files += [
(transform_dir, transform_files)
]
# add ignored deps
data_files += [
(ignored_deps_dir, ignored_deps_files)
]
if osname == 'sunos':
# Solaris-specific extensions are added here
data_files += [
(smf_app_dir, smf_app_files),
(execattrd_dir, execattrd_files),
(authattrd_dir, authattrd_files),
(userattrd_dir, userattrd_files),
(sysrepo_dir, sysrepo_files),
(sysrepo_dir_22, sysrepo_files_22),
(sysrepo_logs_dir, sysrepo_log_stubs),
(sysrepo_cache_dir, {}),
(depot_dir, depot_files),
(depot_dir_22, depot_files_22),
(depot_conf_dir, {}),
(depot_logs_dir, depot_log_stubs),
(depot_cache_dir, {}),
(mirror_cache_dir, {}),
(mirror_logs_dir, {}),
]
# install localizable .xml and its .pot file to put into localizable file package
data_files += [
(os.path.join(locale_dir, locale, 'LC_MESSAGES'),
[('po/{0}.mo'.format(locale), 'pkg.mo')])
for locale in pkg_locales
]
# install English .pot file to put into localizable file package
data_files += [
(os.path.join(locale_dir, '__LOCALE__', 'LC_MESSAGES'),
[('po/pkg.pot', 'pkg.pot')])
]
# install English manpage sources to put into localizable file package
data_files += [
(dir.replace('usr/share/man/', 'usr/share/man/__LOCALE__/'),
(os.path.join(MANPAGE_SRC_ROOT, os.path.basename(f))
for f in files))
for dir, files in english_manpage_files
]
if osname == 'sunos' or osname == "linux":
# Unix platforms which the elf extension has been ported to
# are specified here, so they are built automatically
elf_libraries = ['elf']
ext_modules += [
Extension(
'elf',
elf_srcs,
include_dirs = include_dirs,
libraries = elf_libraries,
extra_compile_args = compile_args,
extra_link_args = link_args,
build_64 = True
),
]
# Solaris has built-in md library and Solaris-specific arch extension
# All others use OpenSSL and cross-platform arch module
if osname == 'sunos':
elf_libraries += [ 'md' ]
sysattr_libraries = [ 'nvpair' ]
sha512_t_libraries = [ 'md' ]
ext_modules += [
Extension(
'_arch',
arch_srcs,
include_dirs = include_dirs,
extra_compile_args = compile_args,
extra_link_args = link_args,
define_macros = [('_FILE_OFFSET_BITS', '64')],
build_64 = True
),
Extension(
'_pspawn',
pspawn_srcs,
include_dirs = include_dirs,
extra_compile_args = compile_args,
extra_link_args = link_args,
define_macros = [('_FILE_OFFSET_BITS', '64')],
build_64 = True
),
Extension(
'_syscallat',
syscallat_srcs,
include_dirs = include_dirs,
extra_compile_args = compile_args,
extra_link_args = link_args,
define_macros = [('_FILE_OFFSET_BITS', '64')],
build_64 = True
),
Extension(
'_sysattr',
sysattr_srcs,
include_dirs = include_dirs,
libraries = sysattr_libraries,
extra_compile_args = compile_args,
extra_link_args = link_args,
define_macros = [('_FILE_OFFSET_BITS', '64')],
build_64 = True
),
Extension(
'_sha512_t',
sha512_t_srcs,
include_dirs = include_dirs,
libraries = sha512_t_libraries,
extra_compile_args = compile_args,
extra_link_args = link_args,
define_macros = [('_FILE_OFFSET_BITS', '64')],
build_64 = True
),
]
else:
elf_libraries += [ 'ssl' ]
setup(cmdclass = cmdclasses,
name = 'pkg',
version = '0.1',
package_dir = {'pkg':'modules'},
packages = packages,
data_files = data_files,
ext_package = 'pkg',
ext_modules = ext_modules,
classifiers = [
'Programming Language :: Python :: 2 :: Only',
'Programming Language :: Python :: 2.7',
]
)