]>
Commit | Line | Data |
---|---|---|
53e6db90 DC |
1 | import os |
2 | import sys | |
3 | from itertools import product, starmap | |
4 | import distutils.command.install_lib as orig | |
5 | ||
6 | ||
7 | class install_lib(orig.install_lib): | |
8 | """Don't add compiled flags to filenames of non-Python files""" | |
9 | ||
10 | def initialize_options(self): | |
11 | orig.install_lib.initialize_options(self) | |
12 | self.multiarch = None | |
13 | self.install_layout = None | |
14 | ||
15 | def finalize_options(self): | |
16 | orig.install_lib.finalize_options(self) | |
17 | self.set_undefined_options('install',('install_layout','install_layout')) | |
18 | if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3): | |
19 | import sysconfig | |
20 | self.multiarch = sysconfig.get_config_var('MULTIARCH') | |
21 | ||
22 | def run(self): | |
23 | self.build() | |
24 | outfiles = self.install() | |
25 | if outfiles is not None: | |
26 | # always compile, in case we have any extension stubs to deal with | |
27 | self.byte_compile(outfiles) | |
28 | ||
29 | def get_exclusions(self): | |
30 | """ | |
31 | Return a collections.Sized collections.Container of paths to be | |
32 | excluded for single_version_externally_managed installations. | |
33 | """ | |
34 | all_packages = ( | |
35 | pkg | |
36 | for ns_pkg in self._get_SVEM_NSPs() | |
37 | for pkg in self._all_packages(ns_pkg) | |
38 | ) | |
39 | ||
40 | excl_specs = product(all_packages, self._gen_exclusion_paths()) | |
41 | return set(starmap(self._exclude_pkg_path, excl_specs)) | |
42 | ||
43 | def _exclude_pkg_path(self, pkg, exclusion_path): | |
44 | """ | |
45 | Given a package name and exclusion path within that package, | |
46 | compute the full exclusion path. | |
47 | """ | |
48 | parts = pkg.split('.') + [exclusion_path] | |
49 | return os.path.join(self.install_dir, *parts) | |
50 | ||
51 | @staticmethod | |
52 | def _all_packages(pkg_name): | |
53 | """ | |
54 | >>> list(install_lib._all_packages('foo.bar.baz')) | |
55 | ['foo.bar.baz', 'foo.bar', 'foo'] | |
56 | """ | |
57 | while pkg_name: | |
58 | yield pkg_name | |
59 | pkg_name, sep, child = pkg_name.rpartition('.') | |
60 | ||
61 | def _get_SVEM_NSPs(self): | |
62 | """ | |
63 | Get namespace packages (list) but only for | |
64 | single_version_externally_managed installations and empty otherwise. | |
65 | """ | |
66 | # TODO: is it necessary to short-circuit here? i.e. what's the cost | |
67 | # if get_finalized_command is called even when namespace_packages is | |
68 | # False? | |
69 | if not self.distribution.namespace_packages: | |
70 | return [] | |
71 | ||
72 | install_cmd = self.get_finalized_command('install') | |
73 | svem = install_cmd.single_version_externally_managed | |
74 | ||
75 | return self.distribution.namespace_packages if svem else [] | |
76 | ||
77 | @staticmethod | |
78 | def _gen_exclusion_paths(): | |
79 | """ | |
80 | Generate file paths to be excluded for namespace packages (bytecode | |
81 | cache files). | |
82 | """ | |
83 | # always exclude the package module itself | |
84 | yield '__init__.py' | |
85 | ||
86 | yield '__init__.pyc' | |
87 | yield '__init__.pyo' | |
88 | ||
89 | if not hasattr(sys, 'implementation'): | |
90 | return | |
91 | ||
92 | base = os.path.join( | |
93 | '__pycache__', '__init__.' + sys.implementation.cache_tag) | |
94 | yield base + '.pyc' | |
95 | yield base + '.pyo' | |
96 | yield base + '.opt-1.pyc' | |
97 | yield base + '.opt-2.pyc' | |
98 | ||
99 | def copy_tree( | |
100 | self, infile, outfile, | |
101 | preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 | |
102 | ): | |
103 | assert preserve_mode and preserve_times and not preserve_symlinks | |
104 | exclude = self.get_exclusions() | |
105 | ||
106 | if not exclude: | |
107 | import distutils.dir_util | |
108 | distutils.dir_util._multiarch = self.multiarch | |
109 | return orig.install_lib.copy_tree(self, infile, outfile) | |
110 | ||
111 | # Exclude namespace package __init__.py* files from the output | |
112 | ||
113 | from setuptools.archive_util import unpack_directory | |
114 | from distutils import log | |
115 | ||
116 | outfiles = [] | |
117 | ||
118 | if self.multiarch: | |
119 | import sysconfig | |
120 | ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') | |
121 | if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]): | |
122 | new_suffix = None | |
123 | else: | |
124 | new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) | |
125 | ||
126 | def pf(src, dst): | |
127 | if dst in exclude: | |
128 | log.warn("Skipping installation of %s (namespace package)", | |
129 | dst) | |
130 | return False | |
131 | ||
132 | if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): | |
133 | dst = dst.replace(ext_suffix, new_suffix) | |
134 | log.info("renaming extension to %s", os.path.basename(dst)) | |
135 | ||
136 | log.info("copying %s -> %s", src, os.path.dirname(dst)) | |
137 | outfiles.append(dst) | |
138 | return dst | |
139 | ||
140 | unpack_directory(infile, outfile, pf) | |
141 | return outfiles | |
142 | ||
143 | def get_outputs(self): | |
144 | outputs = orig.install_lib.get_outputs(self) | |
145 | exclude = self.get_exclusions() | |
146 | if exclude: | |
147 | return [f for f in outputs if f not in exclude] | |
148 | return outputs |