1 |
commit: 44f2b8f9603964abe230cfe8ef75831a82855da5 |
2 |
Author: Arfrever Frehtes Taifersar Arahesis <Arfrever <AT> Apache <DOT> Org> |
3 |
AuthorDate: Sat Nov 24 12:28:44 2012 +0000 |
4 |
Commit: Arfrever Frehtes Taifersar Arahesis <arfrever.fta <AT> gmail <DOT> com> |
5 |
CommitDate: Sat Nov 24 12:28:44 2012 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=44f2b8f9 |
7 |
|
8 |
EAPI="5-progress": Add automatic unpack dependencies. |
9 |
|
10 |
--- |
11 |
doc/package/ebuild/eapi/5-progress.docbook | 30 +++++++++ |
12 |
pym/_emerge/EbuildMetadataPhase.py | 9 +++ |
13 |
pym/portage/__init__.py | 1 + |
14 |
pym/portage/dep/__init__.py | 45 ++++++++++++++ |
15 |
pym/portage/eapi.py | 3 + |
16 |
.../package/ebuild/_config/unpack_dependencies.py | 38 +++++++++++ |
17 |
pym/portage/package/ebuild/config.py | 3 + |
18 |
pym/portage/tests/resolver/ResolverPlayground.py | 7 ++- |
19 |
.../tests/resolver/test_unpack_dependencies.py | 65 ++++++++++++++++++++ |
20 |
9 files changed, 199 insertions(+), 2 deletions(-) |
21 |
|
22 |
diff --git a/doc/package/ebuild/eapi/5-progress.docbook b/doc/package/ebuild/eapi/5-progress.docbook |
23 |
index 3346464..93ce6dc 100644 |
24 |
--- a/doc/package/ebuild/eapi/5-progress.docbook |
25 |
+++ b/doc/package/ebuild/eapi/5-progress.docbook |
26 |
@@ -121,6 +121,36 @@ |
27 |
</tgroup> |
28 |
</table> |
29 |
</section> |
30 |
+ <section id='package-ebuild-eapi-5-progress-metadata-automatic-unpack-dependencies'> |
31 |
+ <title>Automatic Unpack Dependencies</title> |
32 |
+ <para> |
33 |
+ Dependencies on packages required to unpack archives specified in SRC_URI are automatically appended to DEPEND. These dependencies are calculated from filename extensions of archives specified in SRC_URI. Dependencies (for ebuilds using given EAPI) corresponding to given filename extensions are configured in ${repository_path}/profiles/unpack_dependencies/${EAPI} files. |
34 |
+ </para> |
35 |
+ <table><title>Unpack Dependencies Configuration Examples</title> |
36 |
+ <tgroup cols='1' align='left'> |
37 |
+ <tbody> |
38 |
+ <row> |
39 |
+ <entry>bz2 app-arch/bzip2</entry> |
40 |
+ </row> |
41 |
+ <row> |
42 |
+ <entry>gz app-arch/gzip</entry> |
43 |
+ </row> |
44 |
+ <row> |
45 |
+ <entry>tar app-arch/tar</entry> |
46 |
+ </row> |
47 |
+ <row> |
48 |
+ <entry>tar.bz2 app-arch/tar app-arch/bzip2</entry> |
49 |
+ </row> |
50 |
+ <row> |
51 |
+ <entry>tar.gz app-arch/tar app-arch/gzip</entry> |
52 |
+ </row> |
53 |
+ <row> |
54 |
+ <entry>zip app-arch/unzip</entry> |
55 |
+ </row> |
56 |
+ </tbody> |
57 |
+ </tgroup> |
58 |
+ </table> |
59 |
+ </section> |
60 |
</section> |
61 |
<section id='package-ebuild-eapi-5-progress-globstar'> |
62 |
<title>globstar shell option enabled by default</title> |
63 |
|
64 |
diff --git a/pym/_emerge/EbuildMetadataPhase.py b/pym/_emerge/EbuildMetadataPhase.py |
65 |
index a6c515a..f351b16 100644 |
66 |
--- a/pym/_emerge/EbuildMetadataPhase.py |
67 |
+++ b/pym/_emerge/EbuildMetadataPhase.py |
68 |
@@ -12,6 +12,8 @@ from portage import os |
69 |
from portage import _encodings |
70 |
from portage import _unicode_decode |
71 |
from portage import _unicode_encode |
72 |
+from portage.dep import extract_unpack_dependencies |
73 |
+from portage.eapi import eapi_has_automatic_unpack_dependencies |
74 |
|
75 |
import errno |
76 |
import fcntl |
77 |
@@ -180,6 +182,13 @@ class EbuildMetadataPhase(SubProcess): |
78 |
metadata["_eclasses_"] = {} |
79 |
metadata.pop("INHERITED", None) |
80 |
|
81 |
+ if eapi_has_automatic_unpack_dependencies(metadata["EAPI"]): |
82 |
+ repo = self.portdb.repositories.get_name_for_location(self.repo_path) |
83 |
+ unpackers = self.settings.unpack_dependencies.get(repo, {}).get(metadata["EAPI"], {}) |
84 |
+ unpack_dependencies = extract_unpack_dependencies(metadata["SRC_URI"], unpackers) |
85 |
+ if unpack_dependencies: |
86 |
+ metadata["DEPEND"] += (" " if metadata["DEPEND"] else "") + unpack_dependencies |
87 |
+ |
88 |
# If called by egencache, this cache write is |
89 |
# undesirable when metadata-transfer is disabled. |
90 |
if self.write_auxdb is not False: |
91 |
|
92 |
diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py |
93 |
index 08d9e5d..3e634b5 100644 |
94 |
--- a/pym/portage/__init__.py |
95 |
+++ b/pym/portage/__init__.py |
96 |
@@ -427,6 +427,7 @@ _doebuild_manifest_exempt_depend = 0 |
97 |
|
98 |
_testing_eapis = frozenset(["4-python", "4-slot-abi", "5-progress", "5-hdepend"]) |
99 |
_deprecated_eapis = frozenset(["4_pre1", "3_pre2", "3_pre1", "5_pre1", "5_pre2"]) |
100 |
+_supported_eapis = frozenset([str(x) for x in range(portage.const.EAPI)] + list(_testing_eapis) + list(_deprecated_eapis)) |
101 |
|
102 |
def _eapi_is_deprecated(eapi): |
103 |
return eapi in _deprecated_eapis |
104 |
|
105 |
diff --git a/pym/portage/dep/__init__.py b/pym/portage/dep/__init__.py |
106 |
index 60d1cc9..e2aa00d 100644 |
107 |
--- a/pym/portage/dep/__init__.py |
108 |
+++ b/pym/portage/dep/__init__.py |
109 |
@@ -2764,3 +2764,48 @@ def extract_affecting_use(mystr, atom, eapi=None): |
110 |
_("malformed syntax: '%s'") % mystr) |
111 |
|
112 |
return affecting_use |
113 |
+ |
114 |
+def extract_unpack_dependencies(src_uri, unpackers): |
115 |
+ """ |
116 |
+ Return unpack dependencies string for given SRC_URI string. |
117 |
+ |
118 |
+ @param src_uri: SRC_URI string |
119 |
+ @type src_uri: String |
120 |
+ @param unpackers: Dictionary mapping archive suffixes to dependency strings |
121 |
+ @type unpackers: Dictionary |
122 |
+ @rtype: String |
123 |
+ @return: Dependency string specifying packages required to unpack archives. |
124 |
+ """ |
125 |
+ src_uri = src_uri.split() |
126 |
+ |
127 |
+ depend = [] |
128 |
+ for i in range(len(src_uri)): |
129 |
+ if src_uri[i][-1] == "?" or src_uri[i] in ("(", ")"): |
130 |
+ depend.append(src_uri[i]) |
131 |
+ elif (i+1 < len(src_uri) and src_uri[i+1] == "->") or src_uri[i] == "->": |
132 |
+ continue |
133 |
+ else: |
134 |
+ for suffix in sorted(unpackers, key=lambda x: len(x), reverse=True): |
135 |
+ suffix = suffix.lower() |
136 |
+ if src_uri[i].lower().endswith(suffix): |
137 |
+ depend.append(unpackers[suffix]) |
138 |
+ break |
139 |
+ |
140 |
+ while True: |
141 |
+ cleaned_depend = depend[:] |
142 |
+ for i in range(len(cleaned_depend)): |
143 |
+ if cleaned_depend[i] is None: |
144 |
+ continue |
145 |
+ elif cleaned_depend[i] == "(" and cleaned_depend[i+1] == ")": |
146 |
+ cleaned_depend[i] = None |
147 |
+ cleaned_depend[i+1] = None |
148 |
+ elif cleaned_depend[i][-1] == "?" and cleaned_depend[i+1] == "(" and cleaned_depend[i+2] == ")": |
149 |
+ cleaned_depend[i] = None |
150 |
+ cleaned_depend[i+1] = None |
151 |
+ cleaned_depend[i+2] = None |
152 |
+ if depend == cleaned_depend: |
153 |
+ break |
154 |
+ else: |
155 |
+ depend = [x for x in cleaned_depend if x is not None] |
156 |
+ |
157 |
+ return " ".join(depend) |
158 |
|
159 |
diff --git a/pym/portage/eapi.py b/pym/portage/eapi.py |
160 |
index bc1240c..4f77910 100644 |
161 |
--- a/pym/portage/eapi.py |
162 |
+++ b/pym/portage/eapi.py |
163 |
@@ -86,6 +86,9 @@ def eapi_allows_directories_on_profile_level_and_repository_level(eapi): |
164 |
def eapi_has_use_aliases(eapi): |
165 |
return eapi in ("4-python", "5-progress") |
166 |
|
167 |
+def eapi_has_automatic_unpack_dependencies(eapi): |
168 |
+ return eapi in ("5-progress",) |
169 |
+ |
170 |
def eapi_has_hdepend(eapi): |
171 |
return eapi in ("5-hdepend",) |
172 |
|
173 |
|
174 |
diff --git a/pym/portage/package/ebuild/_config/unpack_dependencies.py b/pym/portage/package/ebuild/_config/unpack_dependencies.py |
175 |
new file mode 100644 |
176 |
index 0000000..1375189 |
177 |
--- /dev/null |
178 |
+++ b/pym/portage/package/ebuild/_config/unpack_dependencies.py |
179 |
@@ -0,0 +1,38 @@ |
180 |
+# Copyright 2012 Gentoo Foundation |
181 |
+# Distributed under the terms of the GNU General Public License v2 |
182 |
+ |
183 |
+from portage import os, _supported_eapis |
184 |
+from portage.dep import use_reduce |
185 |
+from portage.eapi import eapi_has_automatic_unpack_dependencies |
186 |
+from portage.exception import InvalidDependString |
187 |
+from portage.localization import _ |
188 |
+from portage.util import grabfile, writemsg |
189 |
+ |
190 |
+def load_unpack_dependencies_configuration(repositories): |
191 |
+ repo_dict = {} |
192 |
+ for repo in repositories.repos_with_profiles(): |
193 |
+ for eapi in _supported_eapis: |
194 |
+ if eapi_has_automatic_unpack_dependencies(eapi): |
195 |
+ file_name = os.path.join(repo.location, "profiles", "unpack_dependencies", eapi) |
196 |
+ lines = grabfile(file_name, recursive=True) |
197 |
+ for line in lines: |
198 |
+ elements = line.split() |
199 |
+ suffix = elements[0].lower() |
200 |
+ if len(elements) == 1: |
201 |
+ writemsg(_("--- Missing unpack dependencies for '%s' suffix in '%s'\n") % (suffix, file_name)) |
202 |
+ depend = " ".join(elements[1:]) |
203 |
+ try: |
204 |
+ use_reduce(depend, eapi=eapi) |
205 |
+ except InvalidDependString as e: |
206 |
+ writemsg(_("--- Invalid unpack dependencies for '%s' suffix in '%s': '%s'\n" % (suffix, file_name, e))) |
207 |
+ else: |
208 |
+ repo_dict.setdefault(repo.name, {}).setdefault(eapi, {})[suffix] = depend |
209 |
+ |
210 |
+ ret = {} |
211 |
+ for repo in repositories.repos_with_profiles(): |
212 |
+ for repo_name in [x.name for x in repo.masters] + [repo.name]: |
213 |
+ for eapi in repo_dict.get(repo_name, {}): |
214 |
+ for suffix, depend in repo_dict.get(repo_name, {}).get(eapi, {}).items(): |
215 |
+ ret.setdefault(repo.name, {}).setdefault(eapi, {})[suffix] = depend |
216 |
+ |
217 |
+ return ret |
218 |
|
219 |
diff --git a/pym/portage/package/ebuild/config.py b/pym/portage/package/ebuild/config.py |
220 |
index 45a3351..86eac8a 100644 |
221 |
--- a/pym/portage/package/ebuild/config.py |
222 |
+++ b/pym/portage/package/ebuild/config.py |
223 |
@@ -56,6 +56,7 @@ from portage.package.ebuild._config.LocationsManager import LocationsManager |
224 |
from portage.package.ebuild._config.MaskManager import MaskManager |
225 |
from portage.package.ebuild._config.VirtualsManager import VirtualsManager |
226 |
from portage.package.ebuild._config.helper import ordered_by_atom_specificity, prune_incremental |
227 |
+from portage.package.ebuild._config.unpack_dependencies import load_unpack_dependencies_configuration |
228 |
|
229 |
if sys.hexversion >= 0x3000000: |
230 |
basestring = str |
231 |
@@ -237,6 +238,7 @@ class config(object): |
232 |
self.profiles = clone.profiles |
233 |
self.packages = clone.packages |
234 |
self.repositories = clone.repositories |
235 |
+ self.unpack_dependencies = clone.unpack_dependencies |
236 |
self._iuse_effective = clone._iuse_effective |
237 |
self._iuse_implicit_match = clone._iuse_implicit_match |
238 |
self._non_user_variables = clone._non_user_variables |
239 |
@@ -489,6 +491,7 @@ class config(object): |
240 |
x = Atom(x.lstrip('*')) |
241 |
self.prevmaskdict.setdefault(x.cp, []).append(x) |
242 |
|
243 |
+ self.unpack_dependencies = load_unpack_dependencies_configuration(self.repositories) |
244 |
|
245 |
mygcfg = {} |
246 |
if self.profiles: |
247 |
|
248 |
diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py |
249 |
index 9b30edb..f81e046 100644 |
250 |
--- a/pym/portage/tests/resolver/ResolverPlayground.py |
251 |
+++ b/pym/portage/tests/resolver/ResolverPlayground.py |
252 |
@@ -2,6 +2,7 @@ |
253 |
# Distributed under the terms of the GNU General Public License v2 |
254 |
|
255 |
from itertools import permutations |
256 |
+import fnmatch |
257 |
import sys |
258 |
import tempfile |
259 |
import portage |
260 |
@@ -37,7 +38,7 @@ class ResolverPlayground(object): |
261 |
config_files = frozenset(("eapi", "layout.conf", "make.conf", "package.accept_keywords", |
262 |
"package.keywords", "package.license", "package.mask", "package.properties", |
263 |
"package.unmask", "package.use", "package.use.aliases", "package.use.stable.mask", |
264 |
- "use.aliases", "use.force", "use.mask", "layout.conf")) |
265 |
+ "unpack_dependencies", "use.aliases", "use.force", "use.mask", "layout.conf")) |
266 |
|
267 |
metadata_xml_template = """<?xml version="1.0" encoding="UTF-8"?> |
268 |
<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> |
269 |
@@ -282,13 +283,15 @@ class ResolverPlayground(object): |
270 |
repo_config = repo_configs.get(repo) |
271 |
if repo_config: |
272 |
for config_file, lines in repo_config.items(): |
273 |
- if config_file not in self.config_files: |
274 |
+ if config_file not in self.config_files and not any(fnmatch.fnmatch(config_file, os.path.join(x, "*")) for x in self.config_files): |
275 |
raise ValueError("Unknown config file: '%s'" % config_file) |
276 |
|
277 |
if config_file in ("layout.conf",): |
278 |
file_name = os.path.join(repo_dir, "metadata", config_file) |
279 |
else: |
280 |
file_name = os.path.join(profile_dir, config_file) |
281 |
+ if "/" in config_file and not os.path.isdir(os.path.dirname(file_name)): |
282 |
+ os.makedirs(os.path.dirname(file_name)) |
283 |
f = open(file_name, "w") |
284 |
for line in lines: |
285 |
f.write("%s\n" % line) |
286 |
|
287 |
diff --git a/pym/portage/tests/resolver/test_unpack_dependencies.py b/pym/portage/tests/resolver/test_unpack_dependencies.py |
288 |
new file mode 100644 |
289 |
index 0000000..cfceff4 |
290 |
--- /dev/null |
291 |
+++ b/pym/portage/tests/resolver/test_unpack_dependencies.py |
292 |
@@ -0,0 +1,65 @@ |
293 |
+# Copyright 2012 Gentoo Foundation |
294 |
+# Distributed under the terms of the GNU General Public License v2 |
295 |
+ |
296 |
+from portage.tests import TestCase |
297 |
+from portage.tests.resolver.ResolverPlayground import ResolverPlayground, ResolverPlaygroundTestCase |
298 |
+ |
299 |
+class UnpackDependenciesTestCase(TestCase): |
300 |
+ def testUnpackDependencies(self): |
301 |
+ distfiles = { |
302 |
+ "A-1.tar.gz": b"binary\0content", |
303 |
+ "B-1.TAR.XZ": b"binary\0content", |
304 |
+ "B-docs-1.tar.bz2": b"binary\0content", |
305 |
+ "C-1.TAR.XZ": b"binary\0content", |
306 |
+ "C-docs-1.tar.bz2": b"binary\0content", |
307 |
+ } |
308 |
+ |
309 |
+ ebuilds = { |
310 |
+ "dev-libs/A-1": {"SRC_URI": "A-1.tar.gz", "EAPI": "5-progress"}, |
311 |
+ "dev-libs/B-1": {"IUSE": "doc", "SRC_URI": "B-1.TAR.XZ doc? ( B-docs-1.tar.bz2 )", "EAPI": "5-progress"}, |
312 |
+ "dev-libs/C-1": {"IUSE": "doc", "SRC_URI": "C-1.TAR.XZ doc? ( C-docs-1.tar.bz2 )", "EAPI": "5-progress"}, |
313 |
+ "app-arch/bzip2-1": {}, |
314 |
+ "app-arch/gzip-1": {}, |
315 |
+ "app-arch/tar-1": {}, |
316 |
+ "app-arch/xz-utils-1": {}, |
317 |
+ } |
318 |
+ |
319 |
+ repo_configs = { |
320 |
+ "test_repo": { |
321 |
+ "unpack_dependencies/5-progress": ( |
322 |
+ "tar.bz2 app-arch/tar app-arch/bzip2", |
323 |
+ "tar.gz app-arch/tar app-arch/gzip", |
324 |
+ "tar.xz app-arch/tar app-arch/xz-utils", |
325 |
+ ), |
326 |
+ }, |
327 |
+ } |
328 |
+ |
329 |
+ test_cases = ( |
330 |
+ ResolverPlaygroundTestCase( |
331 |
+ ["dev-libs/A"], |
332 |
+ success = True, |
333 |
+ ignore_mergelist_order = True, |
334 |
+ mergelist = ["app-arch/tar-1", "app-arch/gzip-1", "dev-libs/A-1"]), |
335 |
+ ResolverPlaygroundTestCase( |
336 |
+ ["dev-libs/B"], |
337 |
+ success = True, |
338 |
+ ignore_mergelist_order = True, |
339 |
+ mergelist = ["app-arch/tar-1", "app-arch/xz-utils-1", "dev-libs/B-1"]), |
340 |
+ ResolverPlaygroundTestCase( |
341 |
+ ["dev-libs/C"], |
342 |
+ success = True, |
343 |
+ ignore_mergelist_order = True, |
344 |
+ mergelist = ["app-arch/tar-1", "app-arch/xz-utils-1", "app-arch/bzip2-1", "dev-libs/C-1"]), |
345 |
+ ) |
346 |
+ |
347 |
+ user_config = { |
348 |
+ "package.use": ("dev-libs/C doc",) |
349 |
+ } |
350 |
+ |
351 |
+ playground = ResolverPlayground(distfiles=distfiles, ebuilds=ebuilds, repo_configs=repo_configs, user_config=user_config) |
352 |
+ try: |
353 |
+ for test_case in test_cases: |
354 |
+ playground.run_TestCase(test_case) |
355 |
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg) |
356 |
+ finally: |
357 |
+ playground.cleanup() |