switch to 64-bit default run paths
[unleashed-pkg5.git] / src / setup.py
blobc4665914f53e9c0bc3c332b0efc4497b0b4a8873
1 #!/usr/bin/python2.7
3 # CDDL HEADER START
5 # The contents of this file are subject to the terms of the
6 # Common Development and Distribution License (the "License").
7 # You may not use this file except in compliance with the License.
9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 # or http://www.opensolaris.org/os/licensing.
11 # See the License for the specific language governing permissions
12 # and limitations under the License.
14 # When distributing Covered Code, include this CDDL HEADER in each
15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 # If applicable, add the following below this CDDL HEADER, with the
17 # fields enclosed by brackets "[]" replaced with your own identifying
18 # information: Portions Copyright [yyyy] [name of copyright owner]
20 # CDDL HEADER END
22 # Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
25 from __future__ import print_function
26 import errno
27 import fnmatch
28 import os
29 import platform
30 import stat
31 import sys
32 import shutil
33 import re
34 import subprocess
35 import tarfile
36 import tempfile
37 import urllib
38 import py_compile
39 import hashlib
40 import time
41 import StringIO
43 from distutils.errors import DistutilsError, DistutilsFileError
44 from distutils.core import setup, Extension
45 from distutils.cmd import Command
46 from distutils.command.install import install as _install
47 from distutils.command.install_data import install_data as _install_data
48 from distutils.command.install_lib import install_lib as _install_lib
49 from distutils.command.build import build as _build
50 from distutils.command.build_ext import build_ext as _build_ext
51 from distutils.command.build_py import build_py as _build_py
52 from distutils.command.bdist import bdist as _bdist
53 from distutils.command.clean import clean as _clean
54 from distutils.dist import Distribution
55 from distutils import log
57 from distutils.sysconfig import get_python_inc
58 import distutils.dep_util as dep_util
59 import distutils.dir_util as dir_util
60 import distutils.file_util as file_util
61 import distutils.util as util
62 import distutils.ccompiler
63 from distutils.unixccompiler import UnixCCompiler
65 osname = platform.uname()[0].lower()
66 ostype = arch = 'unknown'
67 if osname == 'sunos' or osname == 'unleashed':
68 arch = platform.processor()
69 ostype = "posix"
70 elif osname == 'linux':
71 arch = "linux_" + platform.machine()
72 ostype = "posix"
73 elif osname == 'windows':
74 arch = osname
75 ostype = "windows"
76 elif osname == 'darwin':
77 arch = osname
78 ostype = "posix"
79 elif osname == 'aix':
80 arch = "aix"
81 ostype = "posix"
83 pwd = os.path.normpath(sys.path[0])
85 # the version of pylint that we must have in order to run the pylint checks.
86 req_pylint_version = "0.25.2"
89 # Unbuffer stdout and stderr. This helps to ensure that subprocess output
90 # is properly interleaved with output from this program.
92 sys.stdout = os.fdopen(sys.stdout.fileno(), "w", 0)
93 sys.stderr = os.fdopen(sys.stderr.fileno(), "w", 0)
95 dist_dir = os.path.normpath(os.path.join(pwd, os.pardir, "proto", "dist_" + arch))
96 build_dir = os.path.normpath(os.path.join(pwd, os.pardir, "proto", "build_" + arch))
97 if "ROOT" in os.environ and os.environ["ROOT"] != "":
98 root_dir = os.environ["ROOT"]
99 else:
100 root_dir = os.path.normpath(os.path.join(pwd, os.pardir, "proto", "root_" + arch))
101 pkgs_dir = os.path.normpath(os.path.join(pwd, os.pardir, "packages", arch))
102 extern_dir = os.path.normpath(os.path.join(pwd, "extern"))
104 # Extract Python minor version.
105 py_version = '.'.join(platform.python_version_tuple()[:2])
106 assert py_version in ('2.6', '2.7')
107 py_install_dir = 'usr/lib/python' + py_version + '/vendor-packages'
109 scripts_dir = 'usr/bin'
110 lib_dir = 'usr/lib'
111 svc_method_dir = 'lib/svc/method'
112 svc_share_dir = 'lib/svc/share'
114 man1_dir = 'usr/share/man/man1'
115 man1m_dir = 'usr/share/man/man1m'
116 man5_dir = 'usr/share/man/man5'
117 man1_ja_JP_dir = 'usr/share/man/ja_JP.UTF-8/man1'
118 man1m_ja_JP_dir = 'usr/share/man/ja_JP.UTF-8/man1m'
119 man5_ja_JP_dir = 'usr/share/man/ja_JP.UTF-8/man5'
120 man1_zh_CN_dir = 'usr/share/man/zh_CN.UTF-8/man1'
121 man1m_zh_CN_dir = 'usr/share/man/zh_CN.UTF-8/man1m'
122 man5_zh_CN_dir = 'usr/share/man/zh_CN.UTF-8/man5'
124 ignored_deps_dir = 'usr/share/pkg/ignored_deps'
125 rad_dir = 'usr/share/lib/pkg'
126 resource_dir = 'usr/share/lib/pkg'
127 transform_dir = 'usr/share/pkg/transforms'
128 smf_app_dir = 'lib/svc/manifest/application/pkg'
129 execattrd_dir = 'etc/security/exec_attr.d'
130 authattrd_dir = 'etc/security/auth_attr.d'
131 userattrd_dir = 'etc/user_attr.d'
132 sysrepo_dir = 'etc/pkg/sysrepo'
133 sysrepo_logs_dir = 'var/log/pkg/sysrepo'
134 sysrepo_cache_dir = 'var/cache/pkg/sysrepo'
135 depot_dir = 'etc/pkg/depot'
136 depot_conf_dir = 'etc/pkg/depot/conf.d'
137 depot_logs_dir = 'var/log/pkg/depot'
138 depot_cache_dir = 'var/cache/pkg/depot'
139 locale_dir = 'usr/share/locale'
140 mirror_logs_dir = 'var/log/pkg/mirror'
141 mirror_cache_dir = 'var/cache/pkg/mirror'
144 # A list of source, destination tuples of modules which should be hardlinked
145 # together if the os supports it and otherwise copied.
146 hardlink_modules = []
148 scripts_sunos = {
149 scripts_dir: [
150 ['client.py', 'pkg'],
151 ['pkgdep.py', 'pkgdepend'],
152 ['pkgrepo.py', 'pkgrepo'],
153 ['util/publish/pkgdiff.py', 'pkgdiff'],
154 ['util/publish/pkgfmt.py', 'pkgfmt'],
155 ['util/publish/pkglint.py', 'pkglint'],
156 ['util/publish/pkgmerge.py', 'pkgmerge'],
157 ['util/publish/pkgmogrify.py', 'pkgmogrify'],
158 ['util/publish/pkgsurf.py', 'pkgsurf'],
159 ['publish.py', 'pkgsend'],
160 ['pull.py', 'pkgrecv'],
161 ['sign.py', 'pkgsign'],
163 lib_dir: [
164 ['depot.py', 'pkg.depotd'],
165 ['sysrepo.py', 'pkg.sysrepo'],
166 ['depot-config.py', "pkg.depot-config"]
168 svc_method_dir: [
169 ['svc/svc-pkg-depot', 'svc-pkg-depot'],
170 ['svc/svc-pkg-mirror', 'svc-pkg-mirror'],
171 ['svc/svc-pkg-repositories-setup',
172 'svc-pkg-repositories-setup'],
173 ['svc/svc-pkg-server', 'svc-pkg-server'],
174 ['svc/svc-pkg-sysrepo', 'svc-pkg-sysrepo'],
176 svc_share_dir: [
177 ['svc/pkg5_include.sh', 'pkg5_include.sh'],
179 rad_dir: [
180 ["rad-invoke.py", "rad-invoke"],
184 scripts_windows = {
185 scripts_dir: [
186 ['client.py', 'client.py'],
187 ['pkgrepo.py', 'pkgrepo.py'],
188 ['publish.py', 'publish.py'],
189 ['pull.py', 'pull.py'],
190 ['scripts/pkg.bat', 'pkg.bat'],
191 ['scripts/pkgsend.bat', 'pkgsend.bat'],
192 ['scripts/pkgrecv.bat', 'pkgrecv.bat'],
194 lib_dir: [
195 ['depot.py', 'depot.py'],
196 ['scripts/pkg.depotd.bat', 'pkg.depotd.bat'],
200 scripts_other_unix = {
201 scripts_dir: [
202 ['client.py', 'client.py'],
203 ['pkgdep.py', 'pkgdep'],
204 ['util/publish/pkgdiff.py', 'pkgdiff'],
205 ['util/publish/pkgfmt.py', 'pkgfmt'],
206 ['util/publish/pkgmogrify.py', 'pkgmogrify'],
207 ['pull.py', 'pull.py'],
208 ['publish.py', 'publish.py'],
209 ['scripts/pkg.sh', 'pkg'],
210 ['scripts/pkgsend.sh', 'pkgsend'],
211 ['scripts/pkgrecv.sh', 'pkgrecv'],
213 lib_dir: [
214 ['depot.py', 'depot.py'],
215 ['scripts/pkg.depotd.sh', 'pkg.depotd'],
217 rad_dir: [
218 ["rad-invoke.py", "rad-invoke"],
222 # indexed by 'osname'
223 scripts = {
224 "sunos": scripts_sunos,
225 "unleashed": scripts_sunos,
226 "linux": scripts_other_unix,
227 "windows": scripts_windows,
228 "darwin": scripts_other_unix,
229 "aix" : scripts_other_unix,
230 "unknown": scripts_sunos,
233 man1_files = [
234 'man/pkg.1',
235 'man/pkgdepend.1',
236 'man/pkgdiff.1',
237 'man/pkgfmt.1',
238 'man/pkglint.1',
239 'man/pkgmerge.1',
240 'man/pkgmogrify.1',
241 'man/pkgsend.1',
242 'man/pkgsign.1',
243 'man/pkgsurf.1',
244 'man/pkgrecv.1',
245 'man/pkgrepo.1',
247 man1m_files = [
248 'man/pkg.depotd.1m',
249 'man/pkg.depot-config.1m',
250 'man/pkg.sysrepo.1m'
252 man5_files = [
253 'man/pkg.5'
256 man1_ja_files = [
257 'man/ja_JP/pkg.1',
258 'man/ja_JP/pkgdepend.1',
259 'man/ja_JP/pkgdiff.1',
260 'man/ja_JP/pkgfmt.1',
261 'man/ja_JP/pkglint.1',
262 'man/ja_JP/pkgmerge.1',
263 'man/ja_JP/pkgmogrify.1',
264 'man/ja_JP/pkgsend.1',
265 'man/ja_JP/pkgsign.1',
266 'man/ja_JP/pkgrecv.1',
267 'man/ja_JP/pkgrepo.1',
269 man1m_ja_files = [
270 'man/ja_JP/pkg.depotd.1m',
271 'man/ja_JP/pkg.sysrepo.1m'
273 man5_ja_files = [
274 'man/ja_JP/pkg.5'
277 man1_zh_CN_files = [
278 'man/zh_CN/pkg.1',
279 'man/zh_CN/pkgdepend.1',
280 'man/zh_CN/pkgdiff.1',
281 'man/zh_CN/pkgfmt.1',
282 'man/zh_CN/pkglint.1',
283 'man/zh_CN/pkgmerge.1',
284 'man/zh_CN/pkgmogrify.1',
285 'man/zh_CN/pkgsend.1',
286 'man/zh_CN/pkgsign.1',
287 'man/zh_CN/pkgrecv.1',
288 'man/zh_CN/pkgrepo.1',
290 man1m_zh_CN_files = [
291 'man/zh_CN/pkg.depotd.1m',
292 'man/zh_CN/pkg.sysrepo.1m'
294 man5_zh_CN_files = [
295 'man/zh_CN/pkg.5'
298 packages = [
299 'pkg',
300 'pkg.actions',
301 'pkg.bundle',
302 'pkg.client',
303 'pkg.client.linkedimage',
304 'pkg.client.transport',
305 'pkg.file_layout',
306 'pkg.flavor',
307 'pkg.lint',
308 'pkg.portable',
309 'pkg.publish',
310 'pkg.server'
313 pylint_targets = [
314 'pkg.altroot',
315 'pkg.client.__init__',
316 'pkg.client.api',
317 'pkg.client.linkedimage',
318 'pkg.client.pkg_solver',
319 'pkg.client.pkgdefs',
320 'pkg.client.pkgremote',
321 'pkg.client.plandesc',
322 'pkg.client.printengine',
323 'pkg.client.progress',
324 'pkg.misc',
325 'pkg.pipeutils',
328 web_files = []
329 for entry in os.walk("web"):
330 web_dir, dirs, files = entry
331 if not files:
332 continue
333 web_files.append((os.path.join(resource_dir, web_dir), [
334 os.path.join(web_dir, f) for f in files
335 if f != "Makefile"
337 # install same set of files in "en/" in "__LOCALE__/ as well"
338 # for localizable file package (regarding themes, install
339 # theme "oracle.com" only)
340 if os.path.basename(web_dir) == "en" and \
341 os.path.dirname(web_dir) in ("web", "web/_themes/oracle.com"):
342 web_files.append((os.path.join(resource_dir,
343 os.path.dirname(web_dir), "__LOCALE__"), [
344 os.path.join(web_dir, f) for f in files
345 if f != "Makefile"
348 smf_app_files = [
349 'svc/pkg-depot.xml',
350 'svc/pkg-mirror.xml',
351 'svc/pkg-repositories-setup.xml',
352 'svc/pkg-server.xml',
353 'svc/pkg-system-repository.xml',
354 'svc/zoneproxy-client.xml',
355 'svc/zoneproxyd.xml'
357 resource_files = [
358 'util/opensolaris.org.sections',
359 'util/pkglintrc',
361 transform_files = [
362 'util/publish/transforms/developer',
363 'util/publish/transforms/documentation',
364 'util/publish/transforms/locale',
365 'util/publish/transforms/smf-manifests'
367 sysrepo_files = [
368 'util/apache2/sysrepo/sysrepo_p5p.py',
369 'util/apache2/sysrepo/sysrepo_httpd.conf.mako',
370 'util/apache2/sysrepo/sysrepo_publisher_response.mako',
372 sysrepo_log_stubs = [
373 'util/apache2/sysrepo/logs/access_log',
374 'util/apache2/sysrepo/logs/error_log',
375 'util/apache2/sysrepo/logs/rewrite.log',
377 depot_files = [
378 'util/apache2/depot/depot.conf.mako',
379 'util/apache2/depot/depot_httpd.conf.mako',
380 'util/apache2/depot/depot_index.py',
381 'util/apache2/depot/depot_httpd_ssl_protocol.conf',
383 depot_log_stubs = [
384 'util/apache2/depot/logs/access_log',
385 'util/apache2/depot/logs/error_log',
386 'util/apache2/depot/logs/rewrite.log',
388 ignored_deps_files = []
390 # The apache-based depot includes an shtml file we add to the resource dir
391 web_files.append((os.path.join(resource_dir, "web"),
392 ["util/apache2/depot/repos.shtml"]))
393 execattrd_files = [
394 'util/misc/exec_attr.d/package:pkg',
396 authattrd_files = ['util/misc/auth_attr.d/package:pkg']
397 userattrd_files = ['util/misc/user_attr.d/package:pkg']
398 pkg_locales = \
399 '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()
401 sysattr_srcs = [
402 'modules/sysattr.c'
404 syscallat_srcs = [
405 'modules/syscallat.c'
407 pspawn_srcs = [
408 'modules/pspawn.c'
410 elf_srcs = [
411 'modules/elf.c',
412 'modules/elfextract.c',
413 'modules/liblist.c',
415 arch_srcs = [
416 'modules/arch.c'
418 _actions_srcs = [
419 'modules/actions/_actions.c'
421 _actcomm_srcs = [
422 'modules/actions/_common.c'
424 _varcet_srcs = [
425 'modules/_varcet.c'
427 solver_srcs = [
428 'modules/solver/solver.c',
429 'modules/solver/py_solver.c'
431 solver_link_args = ["-lm", "-lc"]
432 if osname == 'sunos' or osname == 'unleashed':
433 solver_link_args = ["-ztext"] + solver_link_args
435 # Runs lint on the extension module source code
436 class pylint_func(Command):
437 description = "Runs pylint tools over IPS python source code"
438 user_options = []
440 def initialize_options(self):
441 pass
443 def finalize_options(self):
444 pass
446 # Make string shell-friendly
447 @staticmethod
448 def escape(astring):
449 return astring.replace(' ', '\\ ')
451 def run(self, quiet=False):
453 def supported_pylint_ver(version):
454 """Compare the installed version against the version
455 we require to build with, returning False if the version
456 is too old. It's tempting to use pkg.version.Version
457 here, but since that's a build artifact, we'll do it
458 the long way."""
459 inst_pylint_ver = version.split(".")
460 req_pylint_ver = req_pylint_version.split(".")
462 # if the lists are of different lengths, we just
463 # compare with the precision we have.
464 vers_comp = zip(inst_pylint_ver, req_pylint_ver)
465 for inst, req in vers_comp:
466 try:
467 if int(inst) < int(req):
468 return False
469 except ValueError:
470 # if we somehow get non-numeric version
471 # components, we ignore them.
472 continue
473 return True
475 # it's fine to default to the required version - the build will
476 # break if the installed version is incompatible and $PYLINT_VER
477 # didn't get set, somehow.
478 pylint_ver_str = os.environ.get("PYLINT_VER",
479 req_pylint_version)
480 if pylint_ver_str == "":
481 pylint_ver_str = req_pylint_version
483 if os.environ.get("PKG_SKIP_PYLINT"):
484 log.warn("WARNING: skipping pylint checks: "
485 "$PKG_SKIP_PYLINT was set")
486 return
487 elif not pylint_ver_str or \
488 not supported_pylint_ver(pylint_ver_str):
489 log.warn("WARNING: skipping pylint checks: the "
490 "installed version {0} is older than version {1}".format(
491 pylint_ver_str, req_pylint_version))
492 return
494 proto = os.path.join(root_dir, py_install_dir)
495 sys.path.insert(0, proto)
497 # Insert tests directory onto sys.path so any custom checkers
498 # can be found.
499 sys.path.insert(0, os.path.join(pwd, 'tests'))
500 # assumes pylint is accessible on the sys.path
501 from pylint import lint
504 # For some reason, the load-plugins option, when used in the
505 # rcfile, does not work, so we put it here instead, to load
506 # our custom checkers.
508 # Unfortunately, pylint seems pretty fragile and will crash if
509 # we try to run it over all the current pkg source. Hence for
510 # now we only run it over a subset of the source. As source
511 # files are made pylint clean they should be added to the
512 # pylint_targets list.
514 args = ['--load-plugins=multiplatform']
515 if quiet:
516 args += ['--reports=no']
517 args += ['--rcfile', os.path.join(pwd, 'tests', 'pylintrc')]
518 args += pylint_targets
519 lint.Run(args)
522 class pylint_func_quiet(pylint_func):
524 def run(self, quiet=False):
525 pylint_func.run(self, quiet=True)
528 include_dirs = [ 'modules' ]
529 lint_flags = [ '-u', '-axms', '-erroff=E_NAME_DEF_NOT_USED2' ]
531 # Runs lint on the extension module source code
532 class clint_func(Command):
533 description = "Runs lint tools over IPS C extension source code"
534 user_options = []
536 def initialize_options(self):
537 pass
539 def finalize_options(self):
540 pass
542 # Make string shell-friendly
543 @staticmethod
544 def escape(astring):
545 return astring.replace(' ', '\\ ')
547 def run(self):
548 if "LINT" in os.environ and os.environ["LINT"] != "":
549 lint = [os.environ["LINT"]]
550 else:
551 lint = ['lint']
552 if osname in ['sunos', 'unleashed', 'linux']:
553 archcmd = lint + lint_flags + \
554 ["{0}{1}".format("-I", k) for k in include_dirs] + \
555 ['-I' + self.escape(get_python_inc())] + \
556 arch_srcs
557 elfcmd = lint + lint_flags + \
558 ["{0}{1}".format("-I", k) for k in include_dirs] + \
559 ['-I' + self.escape(get_python_inc())] + \
560 ["{0}{1}".format("-l", k) for k in elf_libraries] + \
561 elf_srcs
562 _actionscmd = lint + lint_flags + \
563 ["{0}{1}".format("-I", k) for k in include_dirs] + \
564 ['-I' + self.escape(get_python_inc())] + \
565 _actions_srcs
566 _actcommcmd = lint + lint_flags + \
567 ["{0}{1}".format("-I", k) for k in include_dirs] + \
568 ['-I' + self.escape(get_python_inc())] + \
569 _actcomm_srcs
570 _varcetcmd = lint + lint_flags + \
571 ["{0}{1}".format("-I", k) for k in include_dirs] + \
572 ['-I' + self.escape(get_python_inc())] + \
573 _varcet_srcs
574 pspawncmd = lint + lint_flags + \
575 ["{0}{1}".format("-I", k) for k in include_dirs] + \
576 ['-I' + self.escape(get_python_inc())] + \
577 pspawn_srcs
578 syscallatcmd = lint + lint_flags + \
579 ["{0}{1}".format("-I", k) for k in include_dirs] + \
580 ['-I' + self.escape(get_python_inc())] + \
581 syscallat_srcs
582 sysattrcmd = lint + lint_flags + \
583 ["{0}{1}".format("-I", k) for k in include_dirs] + \
584 ['-I' + self.escape(get_python_inc())] + \
585 ["{0}{1}".format("-l", k) for k in sysattr_libraries] + \
586 sysattr_srcs
588 print(" ".join(archcmd))
589 os.system(" ".join(archcmd))
590 print(" ".join(elfcmd))
591 os.system(" ".join(elfcmd))
592 print(" ".join(_actionscmd))
593 os.system(" ".join(_actionscmd))
594 print(" ".join(_actcommcmd))
595 os.system(" ".join(_actcommcmd))
596 print(" ".join(_varcetcmd))
597 os.system(" ".join(_varcetcmd))
598 print(" ".join(pspawncmd))
599 os.system(" ".join(pspawncmd))
600 print(" ".join(syscallatcmd))
601 os.system(" ".join(syscallatcmd))
602 print(" ".join(sysattrcmd))
603 os.system(" ".join(sysattrcmd))
606 # Runs both C and Python lint
607 class lint_func(Command):
608 description = "Runs C and Python lint checkers"
609 user_options = []
611 def initialize_options(self):
612 pass
614 def finalize_options(self):
615 pass
617 # Make string shell-friendly
618 @staticmethod
619 def escape(astring):
620 return astring.replace(' ', '\\ ')
622 def run(self):
623 clint_func(Distribution()).run()
624 pylint_func(Distribution()).run()
626 class install_func(_install):
627 def initialize_options(self):
628 _install.initialize_options(self)
630 # PRIVATE_BUILD set in the environment tells us to put the build
631 # directory into the .pyc files, rather than the final
632 # installation directory.
633 private_build = os.getenv("PRIVATE_BUILD", None)
635 if private_build is None:
636 self.install_lib = py_install_dir
637 self.install_data = os.path.sep
638 self.root = root_dir
639 else:
640 self.install_lib = os.path.join(root_dir, py_install_dir)
641 self.install_data = root_dir
643 # This is used when installing scripts, below, but it isn't a
644 # standard distutils variable.
645 self.root_dir = root_dir
647 def run(self):
648 """At the end of the install function, we need to rename some
649 files because distutils provides no way to rename files as they
650 are placed in their install locations.
653 _install.run(self)
655 for o_src, o_dest in hardlink_modules:
656 for e in [".py", ".pyc"]:
657 src = util.change_root(self.root_dir, o_src + e)
658 dest = util.change_root(
659 self.root_dir, o_dest + e)
660 if ostype == "posix":
661 if os.path.exists(dest) and \
662 os.stat(src)[stat.ST_INO] != \
663 os.stat(dest)[stat.ST_INO]:
664 os.remove(dest)
665 file_util.copy_file(src, dest,
666 link="hard", update=1)
667 else:
668 file_util.copy_file(src, dest, update=1)
670 # Don't install the scripts for python 2.6.
671 if py_version == '2.6':
672 return
673 for d, files in scripts[osname].iteritems():
674 for (srcname, dstname) in files:
675 dst_dir = util.change_root(self.root_dir, d)
676 dst_path = util.change_root(self.root_dir,
677 os.path.join(d, dstname))
678 dir_util.mkpath(dst_dir, verbose=True)
679 file_util.copy_file(srcname, dst_path, update=True)
680 # make scripts executable
681 os.chmod(dst_path,
682 os.stat(dst_path).st_mode
683 | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
685 class install_lib_func(_install_lib):
686 """Remove the target files prior to the standard install_lib procedure
687 if the build_py module has determined that they've actually changed.
688 This may be needed when a module's timestamp goes backwards in time, if
689 a working-directory change is reverted, or an older changeset is checked
690 out.
693 def install(self):
694 build_py = self.get_finalized_command("build_py")
695 prefix_len = len(self.build_dir) + 1
696 for p in build_py.copied:
697 id_p = os.path.join(self.install_dir, p[prefix_len:])
698 rm_f(id_p)
699 if self.compile:
700 rm_f(id_p + "c")
701 if self.optimize > 0:
702 rm_f(id_p + "o")
703 return _install_lib.install(self)
705 class install_data_func(_install_data):
706 """Enhance the standard install_data subcommand to take not only a list
707 of filenames, but a list of source and destination filename tuples, for
708 the cases where a filename needs to be renamed between the two
709 locations."""
711 def run(self):
712 self.mkpath(self.install_dir)
713 for f in self.data_files:
714 dir, files = f
715 dir = util.convert_path(dir)
716 if not os.path.isabs(dir):
717 dir = os.path.join(self.install_dir, dir)
718 elif self.root:
719 dir = change_root(self.root, dir)
720 self.mkpath(dir)
722 if not files:
723 self.outfiles.append(dir)
724 else:
725 for file in files:
726 if isinstance(file, basestring):
727 infile = file
728 outfile = os.path.join(dir,
729 os.path.basename(file))
730 else:
731 infile, outfile = file
732 infile = util.convert_path(infile)
733 outfile = util.convert_path(outfile)
734 if os.path.sep not in outfile:
735 outfile = os.path.join(dir,
736 outfile)
737 self.copy_file(infile, outfile)
738 self.outfiles.append(outfile)
740 def run_cmd(args, swdir, updenv=None, ignerr=False, savestderr=None):
741 if updenv:
742 # use temp environment modified with the given dict
743 env = os.environ.copy()
744 env.update(updenv)
745 else:
746 # just use environment of this (parent) process as is
747 env = os.environ
748 if ignerr:
749 # send stderr to devnull
750 stderr = open(os.devnull)
751 elif savestderr:
752 stderr = savestderr
753 else:
754 # just use stderr of this (parent) process
755 stderr = None
756 ret = subprocess.Popen(args, cwd=swdir, env=env,
757 stderr=stderr).wait()
758 if ret != 0:
759 if stderr:
760 stderr.close()
761 print("install failed and returned {0:d}.".format(ret),
762 file=sys.stderr)
763 print("Command was: {0}".format(" ".join(args)),
764 file=sys.stderr)
766 sys.exit(1)
767 if stderr:
768 stderr.close()
770 def _copy_file_contents(src, dst, buffer_size=16*1024):
771 """A clone of distutils.file_util._copy_file_contents() that strips the
772 CDDL text. For Python files, we replace the CDDL text with an equal
773 number of empty comment lines so that line numbers match between the
774 source and destination files."""
776 # Match the lines between and including the CDDL header signposts, as
777 # well as empty comment lines before and after, if they exist.
778 cddl_re = re.compile("\n(#\s*\n)?^[^\n]*CDDL HEADER START.+"
779 "CDDL HEADER END[^\n]*$(\n#\s*$)?", re.MULTILINE|re.DOTALL)
781 with file(src, "r") as sfp:
782 try:
783 os.unlink(dst)
784 except EnvironmentError as e:
785 if e.errno != errno.ENOENT:
786 raise DistutilsFileError("could not delete "
787 "'{0}': {1}".format(dst, e))
789 with file(dst, "w") as dfp:
790 while True:
791 buf = sfp.read(buffer_size)
792 if not buf:
793 break
794 if src.endswith(".py"):
795 match = cddl_re.search(buf)
796 if match:
797 # replace the CDDL expression
798 # with the same number of empty
799 # comment lines as the cddl_re
800 # matched.
801 substr = buf[
802 match.start():match.end()]
803 count = len(
804 substr.split("\n")) - 2
805 blanks = "#\n" * count
806 buf = cddl_re.sub("\n" + blanks,
807 buf)
808 else:
809 buf = cddl_re.sub("", buf)
810 dfp.write(buf)
812 # Make file_util use our version of _copy_file_contents
813 file_util._copy_file_contents = _copy_file_contents
815 def intltool_update_maintain():
816 """Check if scope of localization looks up-to-date or possibly not,
817 by comparing file set described in po/POTFILES.{in,skip} and
818 actual source files (e.g. .py) detected.
820 rm_f("po/missing")
821 rm_f("po/notexist")
823 args = [
824 "/usr/bin/intltool-update", "--maintain"
826 print(" ".join(args))
827 podir = os.path.join(os.getcwd(), "po")
828 run_cmd(args, podir, updenv={"LC_ALL": "C"}, ignerr=True)
830 if os.path.exists("po/missing"):
831 print("New file(s) with translatable strings detected:",
832 file=sys.stderr)
833 missing = open("po/missing", "r")
834 print("--------", file=sys.stderr)
835 for fn in missing:
836 print("{0}".format(fn.strip()), file=sys.stderr)
837 print("--------", file=sys.stderr)
838 missing.close()
839 print("""\
840 Please evaluate whether any of the above file(s) needs localization.
841 If so, please add its name to po/POTFILES.in. If not (e.g., it's not
842 delivered), please add its name to po/POTFILES.skip.
843 Please be sure to maintain alphabetical ordering in both files.""", file=sys.stderr)
844 sys.exit(1)
846 if os.path.exists("po/notexist"):
847 print("""\
848 The following files are listed in po/POTFILES.in, but no longer exist
849 in the workspace:""", file=sys.stderr)
850 notexist = open("po/notexist", "r")
851 print("--------", file=sys.stderr)
852 for fn in notexist:
853 print("{0}".format(fn.strip()), file=sys.stderr)
854 print("--------", file=sys.stderr)
856 notexist.close()
857 print("Please remove the file names from po/POTFILES.in",
858 file=sys.stderr)
859 sys.exit(1)
861 def intltool_update_pot():
862 """Generate pkg.pot by extracting localizable strings from source
863 files (e.g. .py)
865 rm_f("po/pkg.pot")
867 args = [
868 "/usr/bin/intltool-update", "--pot"
870 print(" ".join(args))
871 podir = os.path.join(os.getcwd(), "po")
872 run_cmd(args, podir,
873 updenv={"LC_ALL": "C", "XGETTEXT": "/usr/gnu/bin/xgettext"})
875 if not os.path.exists("po/pkg.pot"):
876 print("Failed in generating pkg.pot.", file=sys.stderr)
877 sys.exit(1)
879 def intltool_merge(src, dst):
880 if not dep_util.newer(src, dst):
881 return
883 args = [
884 "/usr/bin/intltool-merge", "-d", "-u",
885 "-c", "po/.intltool-merge-cache", "po", src, dst
887 print(" ".join(args))
888 run_cmd(args, os.getcwd(), updenv={"LC_ALL": "C"})
890 def i18n_check():
891 """Checks for common i18n messaging bugs in the source."""
893 src_files = []
894 # A list of the i18n errors we check for in the code
895 common_i18n_errors = [
896 # This checks that messages with multiple parameters are always
897 # written using "{name}" format, rather than just "{0}"
898 "format string with unnamed arguments cannot be properly localized"
901 for line in open("po/POTFILES.in", "r").readlines():
902 if line.startswith("["):
903 continue
904 if line.startswith("#"):
905 continue
906 src_files.append(line.rstrip())
908 args = [
909 "/usr/gnu/bin/xgettext", "--from-code=UTF-8", "-o", "/dev/null"]
910 args += src_files
912 xgettext_output_path = tempfile.mkstemp()[1]
913 xgettext_output = open(xgettext_output_path, "w")
914 run_cmd(args, os.getcwd(), updenv={"LC_ALL": "C"},
915 savestderr=xgettext_output)
917 found_errs = False
918 i18n_errs = open("po/i18n_errs.txt", "w")
919 for line in open(xgettext_output_path, "r").readlines():
920 for err in common_i18n_errors:
921 if err in line:
922 i18n_errs.write(line)
923 found_errs = True
924 i18n_errs.close()
925 if found_errs:
926 print("""\
927 The following i18n errors were detected and should be corrected:
928 (this list is saved in po/i18n_errs.txt)
929 """, file=sys.stderr)
930 for line in open("po/i18n_errs.txt", "r"):
931 print(line.rstrip(), file=sys.stderr)
932 sys.exit(1)
933 os.remove(xgettext_output_path)
935 def msgfmt(src, dst):
936 if not dep_util.newer(src, dst):
937 return
939 args = ["/usr/bin/msgfmt", "-o", dst, src]
940 print(" ".join(args))
941 run_cmd(args, os.getcwd())
943 def localizablexml(src, dst):
944 """create XML help for localization, where French part of legalnotice
945 is stripped off
947 if not dep_util.newer(src, dst):
948 return
950 fsrc = open(src, "r")
951 fdst = open(dst, "w")
953 # indicates currently in French part of legalnotice
954 in_fr = False
956 for l in fsrc:
957 if in_fr: # in French part
958 if l.startswith('</legalnotice>'):
959 # reached end of legalnotice
960 print(l, file=fdst)
961 in_fr = False
962 elif l.startswith('<para lang="fr"/>') or \
963 l.startswith('<para lang="fr"></para>'):
964 in_fr = True
965 else:
966 # not in French part
967 print(l, file=fdst)
969 fsrc.close()
970 fdst.close()
972 def xml2po_gen(src, dst):
973 """Input is English XML file. Output is pkg_help.pot, message
974 source for next translation update.
976 if not dep_util.newer(src, dst):
977 return
979 args = ["/usr/bin/xml2po", "-o", dst, src]
980 print(" ".join(args))
981 run_cmd(args, os.getcwd())
983 def xml2po_merge(src, dst, mofile):
984 """Input is English XML file and <lang>.po file (which contains
985 translations). Output is translated XML file.
987 msgfmt(mofile[:-3] + ".po", mofile)
989 monewer = dep_util.newer(mofile, dst)
990 srcnewer = dep_util.newer(src, dst)
992 if not srcnewer and not monewer:
993 return
995 args = ["/usr/bin/xml2po", "-t", mofile, "-o", dst, src]
996 print(" ".join(args))
997 run_cmd(args, os.getcwd())
999 class installfile(Command):
1000 user_options = [
1001 ("file=", "f", "source file to copy"),
1002 ("dest=", "d", "destination directory"),
1003 ("mode=", "m", "file mode"),
1006 description = "De-CDDLing file copy"
1008 def initialize_options(self):
1009 self.file = None
1010 self.dest = None
1011 self.mode = None
1013 def finalize_options(self):
1014 if self.mode is None:
1015 self.mode = 0o644
1016 elif isinstance(self.mode, basestring):
1017 try:
1018 self.mode = int(self.mode, 8)
1019 except ValueError:
1020 self.mode = 0o644
1022 def run(self):
1023 dest_file = os.path.join(self.dest, os.path.basename(self.file))
1024 ret = self.copy_file(self.file, dest_file)
1026 os.chmod(dest_file, self.mode)
1027 os.utime(dest_file, None)
1029 return ret
1031 class build_func(_build):
1032 sub_commands = _build.sub_commands + [('build_data', None)]
1034 def initialize_options(self):
1035 _build.initialize_options(self)
1036 self.build_base = build_dir
1038 def get_hg_version():
1039 try:
1040 cmd = 'hg id -i 2>/dev/null || git log --pretty=format:\'%h\' -1'
1041 p = subprocess.Popen(cmd, shell=True, stdout = subprocess.PIPE)
1042 return p.communicate()[0].strip()
1043 except OSError:
1044 print("ERROR: unable to obtain mercurial/git version",
1045 file=sys.stderr)
1046 return "unknown"
1048 def syntax_check(filename):
1049 """ Run python's compiler over the file, and discard the results.
1050 Arrange to generate an exception if the file does not compile.
1051 This is needed because distutil's own use of pycompile (in the
1052 distutils.utils module) is broken, and doesn't stop on error. """
1053 try:
1054 py_compile.compile(filename, os.devnull, doraise=True)
1055 except py_compile.PyCompileError as e:
1056 res = ""
1057 for err in e.exc_value:
1058 if isinstance(err, basestring):
1059 res += err + "\n"
1060 continue
1062 # Assume it's a tuple of (filename, lineno, col, code)
1063 fname, line, col, code = err
1064 res += "line {0:d}, column {1}, in {2}:\n{3}".format(
1065 line, col or "unknown", fname, code)
1067 raise DistutilsError(res)
1069 # On Solaris, ld inserts the full argument to the -o option into the symbol
1070 # table. This means that the resulting object will be different depending on
1071 # the path at which the workspace lives, and not just on the interesting content
1072 # of the object.
1074 # In order to work around that bug (7076871), we create a new compiler class
1075 # that looks at the argument indicating the output file, chdirs to its
1076 # directory, and runs the real link with the output file set to just the base
1077 # name of the file.
1079 # Unfortunately, distutils isn't too customizable in this regard, so we have to
1080 # twiddle with a couple of the names in the distutils.ccompiler namespace: we
1081 # have to add a new entry to the compiler_class dict, and we have to override
1082 # the new_compiler() function to point to our own. Luckily, our copy of
1083 # new_compiler() gets to be very simple, since we always know what we want to
1084 # return.
1085 class MyUnixCCompiler(UnixCCompiler):
1087 def link(self, *args, **kwargs):
1089 output_filename = args[2]
1090 output_dir = kwargs.get('output_dir')
1091 cwd = os.getcwd()
1093 assert(not output_dir)
1094 output_dir = os.path.join(cwd, os.path.dirname(output_filename))
1095 output_filename = os.path.basename(output_filename)
1096 nargs = args[:2] + (output_filename,) + args[3:]
1097 if not os.path.exists(output_dir):
1098 os.mkdir(output_dir, 0o755)
1099 os.chdir(output_dir)
1101 UnixCCompiler.link(self, *nargs, **kwargs)
1103 os.chdir(cwd)
1105 distutils.ccompiler.compiler_class['myunix'] = (
1106 'unixccompiler', 'MyUnixCCompiler',
1107 'standard Unix-style compiler with a link stage modified for Solaris'
1110 def my_new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
1111 return MyUnixCCompiler(None, dry_run, force)
1113 if osname == 'sunos' or osname == 'unleashed':
1114 distutils.ccompiler.new_compiler = my_new_compiler
1116 class build_ext_func(_build_ext):
1118 def initialize_options(self):
1119 _build_ext.initialize_options(self)
1121 if osname == 'sunos' or osname == 'unleashed':
1122 self.compiler = 'myunix'
1124 def build_extension(self, ext):
1125 _build_ext.build_extension(self, ext)
1127 def get_ext_fullpath(self, ext_name):
1128 return _build_ext.get_ext_fullpath(self, ext_name)
1130 class build_py_func(_build_py):
1132 def __init__(self, dist):
1133 ret = _build_py.__init__(self, dist)
1135 self.copied = []
1137 # Gather the timestamps of the .py files in the gate, so we can
1138 # force the mtimes of the built and delivered copies to be
1139 # consistent across builds, causing their corresponding .pyc
1140 # files to be unchanged unless the .py file content changed.
1142 self.timestamps = {}
1144 pydates = "pydates"
1146 if os.path.isdir(os.path.join(pwd, "../.git")):
1147 pydates = "pydates.git"
1149 p = subprocess.Popen(
1150 os.path.join(pwd, pydates),
1151 stdout=subprocess.PIPE)
1153 for line in p.stdout:
1154 stamp, path = line.split()
1155 stamp = float(stamp)
1156 self.timestamps[path] = stamp
1158 if p.wait() != 0:
1159 print("ERROR: unable to gather .py timestamps",
1160 file=sys.stderr)
1161 sys.exit(1)
1163 return ret
1165 # override the build_module method to do VERSION substitution on
1166 # pkg/__init__.py
1167 def build_module (self, module, module_file, package):
1169 if module == "__init__" and package == "pkg":
1170 versionre = '(?m)^VERSION[^"]*"([^"]*)"'
1171 # Grab the previously-built version out of the build
1172 # tree.
1173 try:
1174 ocontent = \
1175 file(self.get_module_outfile(self.build_lib,
1176 [package], module)).read()
1177 ov = re.search(versionre, ocontent).group(1)
1178 except IOError:
1179 ov = None
1180 v = get_hg_version()
1181 vstr = 'VERSION = "{0}"'.format(v)
1182 # If the versions haven't changed, there's no need to
1183 # recompile.
1184 if v == ov:
1185 return
1187 mcontent = file(module_file).read()
1188 mcontent = re.sub(versionre, vstr, mcontent)
1189 tmpfd, tmp_file = tempfile.mkstemp()
1190 os.write(tmpfd, mcontent)
1191 os.close(tmpfd)
1192 print("doing version substitution: ", v)
1193 rv = _build_py.build_module(self, module, tmp_file, package)
1194 os.unlink(tmp_file)
1195 return rv
1197 # Will raise a DistutilsError on failure.
1198 syntax_check(module_file)
1200 return _build_py.build_module(self, module, module_file, package)
1202 def copy_file(self, infile, outfile, preserve_mode=1, preserve_times=1,
1203 link=None, level=1):
1205 # If the timestamp on the source file (coming from mercurial if
1206 # unchanged, or from the filesystem if changed) doesn't match
1207 # the filesystem timestamp on the destination, then force the
1208 # copy to make sure the right data is in place.
1210 try:
1211 dst_mtime = os.stat(outfile).st_mtime
1212 except OSError as e:
1213 if e.errno != errno.ENOENT:
1214 raise
1215 dst_mtime = time.time()
1217 # The timestamp for __init__.py is the timestamp for the
1218 # workspace itself.
1219 if outfile.endswith("/pkg/__init__.py"):
1220 src_mtime = self.timestamps["."]
1221 else:
1222 src_mtime = self.timestamps.get(
1223 os.path.join("src", infile), self.timestamps["."])
1225 # Force a copy of the file if the source timestamp is different
1226 # from that of the destination, not just if it's newer. This
1227 # allows timestamps in the working directory to regress (for
1228 # instance, following the reversion of a change).
1229 if dst_mtime != src_mtime:
1230 f = self.force
1231 self.force = True
1232 dst, copied = _build_py.copy_file(self, infile, outfile,
1233 preserve_mode, preserve_times, link, level)
1234 self.force = f
1235 else:
1236 dst, copied = outfile, 0
1238 # If we copied the file, then we need to go and readjust the
1239 # timestamp on the file to match what we have in our database.
1240 # Save the filename aside for our version of install_lib.
1241 if copied and dst.endswith(".py"):
1242 os.utime(dst, (src_mtime, src_mtime))
1243 self.copied.append(dst)
1245 return dst, copied
1247 def manpage_input_dir(path):
1248 """Convert a manpage output path to the directory where its source lives."""
1250 patharr = path.split("/")
1251 if len(patharr) == 4:
1252 loc = ""
1253 elif len(patharr) == 5:
1254 loc = patharr[-3].split(".")[0]
1255 else:
1256 raise RuntimeError("bad manpage path")
1257 return os.path.join(patharr[0], loc).rstrip("/")
1259 def xml2roff(files):
1260 """Convert XML manpages to ROFF for delivery.
1262 The input should be a list of the output file paths. The corresponding
1263 inputs will be generated from this. We do it in this way so that we can
1264 share the paths with the install code.
1266 All paths should have a common manpath root. In particular, pages
1267 belonging to different localizations should be run through this function
1268 separately.
1271 input_dir = manpage_input_dir(files[0])
1272 do_files = [
1273 os.path.join(input_dir, os.path.basename(f))
1274 for f in files
1275 if dep_util.newer(os.path.join(input_dir, os.path.basename(f)), f)
1277 if do_files:
1278 # Get the output dir by removing the filename and the manX
1279 # directory
1280 output_dir = os.path.join(*files[0].split("/")[:-2])
1281 args = ["/usr/share/xml/xsolbook/python/xml2roff.py", "-o", output_dir]
1282 args += do_files
1283 print(" ".join(args))
1284 run_cmd(args, os.getcwd())
1286 class build_data_func(Command):
1287 description = "build data files whose source isn't in deliverable form"
1288 user_options = []
1290 # As a subclass of distutils.cmd.Command, these methods are required to
1291 # be implemented.
1292 def initialize_options(self):
1293 pass
1295 def finalize_options(self):
1296 pass
1298 def run(self):
1299 pass
1301 def rm_f(filepath):
1302 """Remove a file without caring whether it exists."""
1304 try:
1305 os.unlink(filepath)
1306 except OSError as e:
1307 if e.errno != errno.ENOENT:
1308 raise
1310 class clean_func(_clean):
1311 def initialize_options(self):
1312 _clean.initialize_options(self)
1313 self.build_base = build_dir
1315 def run(self):
1316 _clean.run(self)
1318 rm_f("po/.intltool-merge-cache")
1320 for l in pkg_locales:
1321 rm_f("po/{0}.mo".format(l))
1323 rm_f("po/pkg.pot")
1325 rm_f("po/i18n_errs.txt")
1327 #shutil.rmtree(MANPAGE_OUTPUT_ROOT, True)
1329 class clobber_func(Command):
1330 user_options = []
1331 description = "Deletes any and all files created by setup"
1333 def initialize_options(self):
1334 pass
1335 def finalize_options(self):
1336 pass
1337 def run(self):
1338 # nuke everything
1339 print("deleting " + dist_dir)
1340 shutil.rmtree(dist_dir, True)
1341 print("deleting " + build_dir)
1342 shutil.rmtree(build_dir, True)
1343 print("deleting " + root_dir)
1344 shutil.rmtree(root_dir, True)
1345 print("deleting " + pkgs_dir)
1346 shutil.rmtree(pkgs_dir, True)
1347 print("deleting " + extern_dir)
1348 shutil.rmtree(extern_dir, True)
1350 class test_func(Command):
1351 # NOTE: these options need to be in sync with tests/run.py and the
1352 # list of options stored in initialize_options below. The first entry
1353 # in each tuple must be the exact name of a member variable.
1354 user_options = [
1355 ("archivedir=", 'a', "archive failed tests <dir>"),
1356 ("baselinefile=", 'b', "baseline file <file>"),
1357 ("coverage", "c", "collect code coverage data"),
1358 ("genbaseline", 'g', "generate test baseline"),
1359 ("only=", "o", "only <regex>"),
1360 ("parseable", 'p', "parseable output"),
1361 ("port=", "z", "lowest port to start a depot on"),
1362 ("timing", "t", "timing file <file>"),
1363 ("verbosemode", 'v', "run tests in verbose mode"),
1364 ("stoponerr", 'x', "stop when a baseline mismatch occurs"),
1365 ("debugoutput", 'd', "emit debugging output"),
1366 ("showonexpectedfail", 'f',
1367 "show all failure info, even for expected fails"),
1368 ("startattest=", 's', "start at indicated test"),
1369 ("jobs=", 'j', "number of parallel processes to use"),
1370 ("quiet", "q", "use the dots as the output format"),
1371 ("livesystem", 'l', "run tests on live system"),
1373 description = "Runs unit and functional tests"
1375 def initialize_options(self):
1376 self.only = ""
1377 self.baselinefile = ""
1378 self.verbosemode = 0
1379 self.parseable = 0
1380 self.genbaseline = 0
1381 self.timing = 0
1382 self.coverage = 0
1383 self.stoponerr = 0
1384 self.debugoutput = 0
1385 self.showonexpectedfail = 0
1386 self.startattest = ""
1387 self.archivedir = ""
1388 self.port = 12001
1389 self.jobs = 1
1390 self.quiet = False
1391 self.livesystem = False
1393 def finalize_options(self):
1394 pass
1396 def run(self):
1398 os.putenv('PYEXE', sys.executable)
1399 os.chdir(os.path.join(pwd, "tests"))
1401 # Reconstruct the cmdline and send that to run.py
1402 cmd = [sys.executable, "run.py"]
1403 args = ""
1404 if "test" in sys.argv:
1405 args = sys.argv[sys.argv.index("test")+1:]
1406 cmd.extend(args)
1407 subprocess.call(cmd)
1409 class dist_func(_bdist):
1410 def initialize_options(self):
1411 _bdist.initialize_options(self)
1412 self.dist_dir = dist_dir
1414 # These are set to real values based on the platform, down below
1415 compile_args = None
1416 if osname in ("sunos", "unleashed", "linux", "darwin"):
1417 compile_args = [ "-O3" ]
1418 if osname == "sunos" or osname == "unleashed":
1419 link_args = []
1420 else:
1421 link_args = []
1423 ext_modules = [
1424 Extension(
1425 'actions._actions',
1426 _actions_srcs,
1427 include_dirs = include_dirs,
1428 extra_compile_args = compile_args,
1429 extra_link_args = link_args,
1431 Extension(
1432 'actions._common',
1433 _actcomm_srcs,
1434 include_dirs = include_dirs,
1435 extra_compile_args = compile_args,
1436 extra_link_args = link_args,
1438 Extension(
1439 '_varcet',
1440 _varcet_srcs,
1441 include_dirs = include_dirs,
1442 extra_compile_args = compile_args,
1443 extra_link_args = link_args,
1445 Extension(
1446 'solver',
1447 solver_srcs,
1448 include_dirs = include_dirs + ["."],
1449 extra_compile_args = compile_args,
1450 extra_link_args = link_args + solver_link_args,
1453 elf_libraries = None
1454 sysattr_libraries = None
1455 data_files = web_files
1456 cmdclasses = {
1457 'install': install_func,
1458 'install_data': install_data_func,
1459 'install_lib': install_lib_func,
1460 'build': build_func,
1461 'build_data': build_data_func,
1462 'build_ext': build_ext_func,
1463 'build_py': build_py_func,
1464 'bdist': dist_func,
1465 'lint': lint_func,
1466 'clint': clint_func,
1467 'pylint': pylint_func,
1468 'pylint_quiet': pylint_func_quiet,
1469 'clean': clean_func,
1470 'clobber': clobber_func,
1471 'test': test_func,
1472 'installfile': installfile,
1475 # all builds of IPS should have manpages
1476 data_files += [
1477 (man1_dir, man1_files),
1478 (man1m_dir, man1m_files),
1479 (man5_dir, man5_files),
1480 (man1_ja_JP_dir, man1_ja_files),
1481 (man1m_ja_JP_dir, man1m_ja_files),
1482 (man5_ja_JP_dir, man5_ja_files),
1483 (man1_zh_CN_dir, man1_zh_CN_files),
1484 (man1m_zh_CN_dir, man1m_zh_CN_files),
1485 (man5_zh_CN_dir, man5_zh_CN_files),
1486 (resource_dir, resource_files),
1488 # add transforms
1489 data_files += [
1490 (transform_dir, transform_files)
1492 # add ignored deps
1493 data_files += [
1494 (ignored_deps_dir, ignored_deps_files)
1496 if osname == 'sunos' or osname == 'unleashed':
1497 # Solaris-specific extensions are added here
1498 data_files += [
1499 (smf_app_dir, smf_app_files),
1500 (execattrd_dir, execattrd_files),
1501 (authattrd_dir, authattrd_files),
1502 (userattrd_dir, userattrd_files),
1503 (sysrepo_dir, sysrepo_files),
1504 (sysrepo_logs_dir, sysrepo_log_stubs),
1505 (sysrepo_cache_dir, {}),
1506 (depot_dir, depot_files),
1507 (depot_conf_dir, {}),
1508 (depot_logs_dir, depot_log_stubs),
1509 (depot_cache_dir, {}),
1510 (mirror_cache_dir, {}),
1511 (mirror_logs_dir, {}),
1514 if osname in ['sunos', 'unleashed', 'linux']:
1515 # Unix platforms which the elf extension has been ported to
1516 # are specified here, so they are built automatically
1517 elf_libraries = ['elf']
1518 ext_modules += [
1519 Extension(
1520 'elf',
1521 elf_srcs,
1522 include_dirs = include_dirs,
1523 libraries = elf_libraries,
1524 extra_compile_args = compile_args,
1525 extra_link_args = link_args,
1529 # Solaris has built-in md library and Solaris-specific arch extension
1530 # All others use OpenSSL and cross-platform arch module
1531 if osname == 'sunos' or osname == 'unleashed':
1532 elf_libraries += [ 'md' ]
1533 sysattr_libraries = [ 'nvpair' ]
1534 ext_modules += [
1535 Extension(
1536 'arch',
1537 arch_srcs,
1538 include_dirs = include_dirs,
1539 extra_compile_args = compile_args,
1540 extra_link_args = link_args,
1542 Extension(
1543 'pspawn',
1544 pspawn_srcs,
1545 include_dirs = include_dirs,
1546 extra_compile_args = compile_args,
1547 extra_link_args = link_args,
1549 Extension(
1550 'syscallat',
1551 syscallat_srcs,
1552 include_dirs = include_dirs,
1553 extra_compile_args = compile_args,
1554 extra_link_args = link_args,
1556 Extension(
1557 'sysattr',
1558 sysattr_srcs,
1559 include_dirs = include_dirs,
1560 libraries = sysattr_libraries,
1561 extra_compile_args = compile_args,
1562 extra_link_args = link_args,
1565 else:
1566 elf_libraries += [ 'ssl' ]
1568 setup(cmdclass = cmdclasses,
1569 name = 'pkg',
1570 version = '0.1',
1571 package_dir = {'pkg':'modules'},
1572 packages = packages,
1573 data_files = data_files,
1574 ext_package = 'pkg',
1575 ext_modules = ext_modules,