Gentoo Archives: gentoo-commits

From: Fabian Groffen <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/portage:prefix commit in: /
Date: Fri, 27 May 2011 17:41:58
Message-Id: abd5adceac4b5f95de66be7516d4f29f24f00d02.grobian@gentoo
1 commit: abd5adceac4b5f95de66be7516d4f29f24f00d02
2 Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
3 AuthorDate: Fri May 27 17:39:37 2011 +0000
4 Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
5 CommitDate: Fri May 27 17:39:37 2011 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=abd5adce
7
8 Merge remote-tracking branch 'overlays-gentoo-org/master' into prefix
9
10 Ported changes to LinkageMapELF to the other LinkageMaps
11
12 Conflicts:
13 bin/etc-update
14 bin/glsa-check
15 bin/regenworld
16 pym/portage/dbapi/vartree.py
17
18
19 bin/ebuild.sh | 7 +
20 bin/etc-update | 8 +-
21 bin/glsa-check | 4 +-
22 bin/regenworld | 6 +-
23 bin/repoman | 2 +-
24 cnf/make.conf.sparc.diff | 2 +-
25 doc/package/ebuild/eapi/4.docbook | 4 +-
26 make.conf.txt | 719 --------------------
27 man/ebuild.5 | 4 +-
28 man/emerge.1 | 15 +-
29 man/make.conf.5 | 5 +-
30 pym/_emerge/AsynchronousLock.py | 49 ++-
31 pym/_emerge/AsynchronousTask.py | 5 +-
32 pym/_emerge/Binpkg.py | 3 +-
33 pym/_emerge/BinpkgFetcher.py | 7 +-
34 pym/_emerge/Blocker.py | 12 +-
35 pym/_emerge/BlockerDB.py | 9 +-
36 pym/_emerge/DepPriority.py | 2 +-
37 pym/_emerge/DepPrioritySatisfiedRange.py | 31 +-
38 pym/_emerge/EbuildBuild.py | 3 +-
39 pym/_emerge/EbuildBuildDir.py | 29 +-
40 pym/_emerge/EbuildMerge.py | 23 +-
41 pym/_emerge/EbuildPhase.py | 34 +-
42 pym/_emerge/FakeVartree.py | 21 +-
43 pym/_emerge/Package.py | 59 ++-
44 pym/_emerge/PackageUninstall.py | 102 +++-
45 pym/_emerge/Scheduler.py | 24 +-
46 pym/_emerge/Task.py | 31 +-
47 pym/_emerge/actions.py | 30 +-
48 pym/_emerge/depgraph.py | 617 ++++++++++++++----
49 pym/_emerge/help.py | 16 +-
50 pym/_emerge/main.py | 17 +-
51 pym/_emerge/resolver/backtracking.py | 7 +-
52 pym/_emerge/resolver/output_helpers.py | 4 +-
53 pym/_emerge/unmerge.py | 74 ++-
54 pym/portage/const.py | 2 +-
55 pym/portage/cvstree.py | 6 +-
56 pym/portage/dbapi/_MergeProcess.py | 43 +-
57 pym/portage/dbapi/vartree.py | 315 ++++++---
58 pym/portage/mail.py | 11 +-
59 pym/portage/output.py | 4 +-
60 pym/portage/package/ebuild/doebuild.py | 121 ++--
61 pym/portage/package/ebuild/getmaskingstatus.py | 7 +-
62 pym/portage/tests/ebuild/test_config.py | 4 +-
63 pym/portage/tests/locks/test_asynchronous_lock.py | 95 +++-
64 pym/portage/tests/resolver/ResolverPlayground.py | 99 +++-
65 pym/portage/tests/resolver/test_autounmask.py | 51 ++-
66 .../tests/resolver/test_circular_dependencies.py | 3 +-
67 pym/portage/tests/resolver/test_depth.py | 8 +-
68 pym/portage/tests/resolver/test_merge_order.py | 386 +++++++++++
69 pym/portage/tests/resolver/test_multirepo.py | 3 +
70 .../tests/resolver/test_old_dep_chain_display.py | 2 +
71 pym/portage/tests/resolver/test_simple.py | 2 +-
72 pym/portage/tests/resolver/test_slot_collisions.py | 3 +-
73 pym/portage/update.py | 4 +-
74 pym/portage/util/__init__.py | 29 +-
75 pym/portage/util/_dyn_libs/LinkageMapELF.py | 13 +-
76 pym/portage/util/_dyn_libs/LinkageMapMachO.py | 13 +-
77 pym/portage/util/_dyn_libs/LinkageMapPeCoff.py | 11 +-
78 pym/portage/util/_dyn_libs/LinkageMapXCoff.py | 11 +-
79 pym/portage/util/digraph.py | 10 +-
80 pym/portage/util/movefile.py | 5 +-
81 pym/portage/xml/metadata.py | 4 +-
82 63 files changed, 1948 insertions(+), 1302 deletions(-)
83
84 diff --cc bin/etc-update
85 index 5fbd345,2369f04..2054389
86 --- a/bin/etc-update
87 +++ b/bin/etc-update
88 @@@ -1,5 -1,5 +1,5 @@@
89 -#!/bin/bash
90 +#!@PORTAGE_BASH@
91 - # Copyright 1999-2007 Gentoo Foundation
92 + # Copyright 1999-2011 Gentoo Foundation
93 # Distributed under the terms of the GNU General Public License v2
94
95 # Author Brandon Low <lostlogic@g.o>
96 diff --cc bin/glsa-check
97 index 64209ab,2f2d555..4f50a1f
98 --- a/bin/glsa-check
99 +++ b/bin/glsa-check
100 @@@ -1,5 -1,5 +1,5 @@@
101 -#!/usr/bin/python
102 +#!@PREFIX_PORTAGE_PYTHON@
103 - # Copyright 2008-2009 Gentoo Foundation
104 + # Copyright 2008-2011 Gentoo Foundation
105 # Distributed under the terms of the GNU General Public License v2
106
107 from __future__ import print_function
108 diff --cc bin/regenworld
109 index e0e9774,6b5af4c..9e0e291
110 --- a/bin/regenworld
111 +++ b/bin/regenworld
112 @@@ -1,5 -1,5 +1,5 @@@
113 -#!/usr/bin/python
114 +#!@PREFIX_PORTAGE_PYTHON@
115 - # Copyright 1999-2010 Gentoo Foundation
116 + # Copyright 1999-2011 Gentoo Foundation
117 # Distributed under the terms of the GNU General Public License v2
118
119 from __future__ import print_function
120 diff --cc pym/portage/const.py
121 index 6057520,e91c009..00a53e4
122 --- a/pym/portage/const.py
123 +++ b/pym/portage/const.py
124 @@@ -132,10 -88,9 +132,10 @@@ EBUILD_PHASES = ("pretend",
125 SUPPORTED_FEATURES = frozenset([
126 "assume-digests", "binpkg-logs", "buildpkg", "buildsyspkg", "candy",
127 "ccache", "chflags", "collision-protect", "compress-build-logs",
128 - "digest", "distcc", "distlocks", "ebuild-locks", "fakeroot",
129 + "digest", "distcc", "distcc-pump", "distlocks", "ebuild-locks", "fakeroot",
130 "fail-clean", "fixpackages", "force-mirror", "getbinpkg",
131 "installsources", "keeptemp", "keepwork", "fixlafiles", "lmirror",
132 + "macossandbox", "macosprefixsandbox", "macosusersandbox",
133 "metadata-transfer", "mirror", "multilib-strict", "news",
134 "noauto", "noclean", "nodoc", "noinfo", "noman",
135 "nostrip", "notitles", "parallel-fetch", "parallel-install",
136 diff --cc pym/portage/dbapi/vartree.py
137 index 581300f,e742358..e0f0856
138 --- a/pym/portage/dbapi/vartree.py
139 +++ b/pym/portage/dbapi/vartree.py
140 @@@ -2347,7 -2386,7 +2407,7 @@@ class dblink(object)
141 def path_to_node(path):
142 node = path_node_map.get(path)
143 if node is None:
144 - node = linkmap._LibGraphNode(path, root)
145 - node = LinkageMap._LibGraphNode(linkmap._obj_key(path))
146 ++ node = linkmap._LibGraphNode(linkmap._obj_key(path))
147 alt_path_node = lib_graph.get(node)
148 if alt_path_node is not None:
149 node = alt_path_node
150 @@@ -2512,15 -2552,7 +2573,15 @@@
151 def path_to_node(path):
152 node = path_node_map.get(path)
153 if node is None:
154 - node = LinkageMap._LibGraphNode(linkmap._obj_key(path))
155 + chost = self.settings.get('CHOST')
156 + if chost.find('darwin') >= 0:
157 - node = LinkageMapMachO._LibGraphNode(path, root)
158 ++ node = LinkageMapMachO._LibGraphNode(linkmap._obj_key(path))
159 + elif chost.find('interix') >= 0 or chost.find('winnt') >= 0:
160 - node = LinkageMapPeCoff._LibGraphNode(path, root)
161 ++ node = LinkageMapPeCoff._LibGraphNode(linkmap._obj_key(path))
162 + elif chost.find('aix') >= 0:
163 - node = LinkageMapXCoff._LibGraphNode(path, root)
164 ++ node = LinkageMapXCoff._LibGraphNode(linkmap._obj_key(path))
165 + else:
166 - node = LinkageMap._LibGraphNode(path, root)
167 ++ node = LinkageMap._LibGraphNode(linkmap._obj_key(path))
168 alt_path_node = lib_graph.get(node)
169 if alt_path_node is not None:
170 node = alt_path_node
171 diff --cc pym/portage/util/_dyn_libs/LinkageMapMachO.py
172 index cbdf6c2,fef75b6..7ed004a
173 --- a/pym/portage/util/_dyn_libs/LinkageMapMachO.py
174 +++ b/pym/portage/util/_dyn_libs/LinkageMapMachO.py
175 @@@ -59,7 -60,7 +59,7 @@@ class LinkageMapMachO(object)
176
177 """Helper class used as _obj_properties keys for objects."""
178
179 - __slots__ = ("__weakref__", "_key")
180 - __slots__ = ("_key",)
181 ++ __slots__ = ("_key")
182
183 def __init__(self, obj, root):
184 """
185 diff --cc pym/portage/util/_dyn_libs/LinkageMapPeCoff.py
186 index c90947e,0000000..25e8a45
187 mode 100644,000000..100644
188 --- a/pym/portage/util/_dyn_libs/LinkageMapPeCoff.py
189 +++ b/pym/portage/util/_dyn_libs/LinkageMapPeCoff.py
190 @@@ -1,267 -1,0 +1,274 @@@
191 +# Copyright 1998-2011 Gentoo Foundation
192 +# Distributed under the terms of the GNU General Public License v2
193 +
194 +import errno
195 +import logging
196 +import subprocess
197 +
198 +import portage
199 +from portage import _encodings
200 +from portage import _os_merge
201 +from portage import _unicode_decode
202 +from portage import _unicode_encode
203 +from portage.cache.mappings import slot_dict_class
204 +from portage.exception import CommandNotFound
205 +from portage.localization import _
206 +from portage.util import getlibpaths
207 +from portage.util import grabfile
208 +from portage.util import normalize_path
209 +from portage.util import writemsg_level
210 +from portage.const import EPREFIX
211 +from portage.util._dyn_libs.LinkageMapELF import LinkageMapELF
212 +
213 +class LinkageMapPeCoff(LinkageMapELF):
214 +
215 + """Models dynamic linker dependencies."""
216 +
217 + # NEEDED.PECOFF.1 has effectively the _same_ format as NEEDED.ELF.2,
218 + # but we keep up the relation "scanelf" -> "NEEDED.ELF", "readpecoff" ->
219 + # "NEEDED.PECOFF", "scanmacho" -> "NEEDED.MACHO", etc. others will follow.
220 + _needed_aux_key = "NEEDED.PECOFF.1"
221 +
222 + class _ObjectKey(LinkageMapELF._ObjectKey):
223 +
224 + """Helper class used as _obj_properties keys for objects."""
225 +
226 + def _generate_object_key(self, obj, root):
227 + """
228 + Generate object key for a given object. This is different from the
229 + Linux implementation, since some systems (e.g. interix) don't have
230 + "inodes", thus the inode field is always zero, or a random value,
231 + making it inappropriate for identifying a file... :)
232 +
233 + @param object: path to a file
234 + @type object: string (example: '/usr/bin/bar')
235 + @rtype: 2-tuple of types (bool, string)
236 + @return:
237 + 2-tuple of boolean indicating existance, and absolut path
238 + """
239 +
240 + os = _os_merge
241 +
242 + try:
243 + _unicode_encode(obj,
244 + encoding=_encodings['merge'], errors='strict')
245 + except UnicodeEncodeError:
246 + # The package appears to have been merged with a
247 + # different value of sys.getfilesystemencoding(),
248 + # so fall back to utf_8 if appropriate.
249 + try:
250 + _unicode_encode(obj,
251 + encoding=_encodings['fs'], errors='strict')
252 + except UnicodeEncodeError:
253 + pass
254 + else:
255 + os = portage.os
256 +
257 + abs_path = os.path.join(root, obj.lstrip(os.sep))
258 + try:
259 + object_stat = os.stat(abs_path)
260 + except OSError:
261 + return (False, os.path.realpath(abs_path))
262 + # On Interix, the inode field may always be zero, since the
263 + # filesystem (NTFS) has no inodes ...
264 + return (True, os.path.realpath(abs_path))
265 +
266 + def file_exists(self):
267 + """
268 + Determine if the file for this key exists on the filesystem.
269 +
270 + @rtype: Boolean
271 + @return:
272 + 1. True if the file exists.
273 + 2. False if the file does not exist or is a broken symlink.
274 +
275 + """
276 + return self._key[0]
277 +
278 + class _LibGraphNode(_ObjectKey):
279 + __slots__ = ("alt_paths",)
280 +
281 - def __init__(self, obj, root):
282 - LinkageMapPeCoff._ObjectKey.__init__(self, obj, root)
283 ++ def __init__(self, key):
284 ++ """
285 ++ Create a _LibGraphNode from an existing _ObjectKey.
286 ++ This re-uses the _key attribute in order to avoid repeating
287 ++ any previous stat calls, which helps to avoid potential race
288 ++ conditions due to inconsistent stat results when the
289 ++ file system is being modified concurrently.
290 ++ """
291 ++ self._key = key._key
292 + self.alt_paths = set()
293 +
294 + def __str__(self):
295 + return str(sorted(self.alt_paths))
296 +
297 + def rebuild(self, exclude_pkgs=None, include_file=None,
298 + preserve_paths=None):
299 + """
300 + Raises CommandNotFound if there are preserved libs
301 + and the readpecoff binary is not available.
302 +
303 + @param exclude_pkgs: A set of packages that should be excluded from
304 + the LinkageMap, since they are being unmerged and their NEEDED
305 + entries are therefore irrelevant and would only serve to corrupt
306 + the LinkageMap.
307 + @type exclude_pkgs: set
308 + @param include_file: The path of a file containing NEEDED entries for
309 + a package which does not exist in the vardbapi yet because it is
310 + currently being merged.
311 + @type include_file: String
312 + @param preserve_paths: Libraries preserved by a package instance that
313 + is currently being merged. They need to be explicitly passed to the
314 + LinkageMap, since they are not registered in the
315 + PreservedLibsRegistry yet.
316 + @type preserve_paths: set
317 + """
318 +
319 + os = _os_merge
320 + root = self._root
321 + root_len = len(root) - 1
322 + self._clear_cache()
323 + self._defpath.update(getlibpaths(self._root))
324 + libs = self._libs
325 + obj_properties = self._obj_properties
326 +
327 + lines = []
328 +
329 + # Data from include_file is processed first so that it
330 + # overrides any data from previously installed files.
331 + if include_file is not None:
332 + for line in grabfile(include_file):
333 + lines.append((include_file, line))
334 +
335 + aux_keys = [self._needed_aux_key]
336 + can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK)
337 + if can_lock:
338 + self._dbapi.lock()
339 + try:
340 + for cpv in self._dbapi.cpv_all():
341 + if exclude_pkgs is not None and cpv in exclude_pkgs:
342 + continue
343 + needed_file = self._dbapi.getpath(cpv,
344 + filename=self._needed_aux_key)
345 + for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines():
346 + lines.append((needed_file, line))
347 + finally:
348 + if can_lock:
349 + self._dbapi.unlock()
350 +
351 + # have to call readpecoff for preserved libs here as they aren't
352 + # registered in NEEDED.PECOFF.1 files
353 + plibs = set()
354 + if preserve_paths is not None:
355 + plibs.update(preserve_paths)
356 + if self._dbapi._plib_registry and \
357 + self._dbapi._plib_registry.hasEntries():
358 + for cpv, items in \
359 + self._dbapi._plib_registry.getPreservedLibs().items():
360 + if exclude_pkgs is not None and cpv in exclude_pkgs:
361 + # These preserved libs will either be unmerged,
362 + # rendering them irrelevant, or they will be
363 + # preserved in the replacement package and are
364 + # already represented via the preserve_paths
365 + # parameter.
366 + continue
367 + plibs.update(items)
368 + if plibs:
369 + args = ["readpecoff", self._dbapi.settings.get('CHOST')]
370 + args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
371 + for x in plibs)
372 + try:
373 + proc = subprocess.Popen(args, stdout=subprocess.PIPE)
374 + except EnvironmentError as e:
375 + if e.errno != errno.ENOENT:
376 + raise
377 + raise CommandNotFound(args[0])
378 + else:
379 + for l in proc.stdout:
380 + try:
381 + l = _unicode_decode(l,
382 + encoding=_encodings['content'], errors='strict')
383 + except UnicodeDecodeError:
384 + l = _unicode_decode(l,
385 + encoding=_encodings['content'], errors='replace')
386 + writemsg_level(_("\nError decoding characters " \
387 + "returned from readpecoff: %s\n\n") % (l,),
388 + level=logging.ERROR, noiselevel=-1)
389 + l = l[3:].rstrip("\n")
390 + if not l:
391 + continue
392 + fields = l.split(";")
393 + if len(fields) < 5:
394 + writemsg_level(_("\nWrong number of fields " \
395 + "returned from readpecoff: %s\n\n") % (l,),
396 + level=logging.ERROR, noiselevel=-1)
397 + continue
398 + fields[1] = fields[1][root_len:]
399 + plibs.discard(fields[1])
400 + lines.append(("readpecoff", ";".join(fields)))
401 + proc.wait()
402 +
403 + if plibs:
404 + # Preserved libraries that did not appear in the scanelf output.
405 + # This is known to happen with statically linked libraries.
406 + # Generate dummy lines for these, so we can assume that every
407 + # preserved library has an entry in self._obj_properties. This
408 + # is important in order to prevent findConsumers from raising
409 + # an unwanted KeyError.
410 + for x in plibs:
411 + lines.append(("plibs", ";".join(['', x, '', '', ''])))
412 +
413 + for location, l in lines:
414 + l = l.rstrip("\n")
415 + if not l:
416 + continue
417 + fields = l.split(";")
418 + if len(fields) < 5:
419 + writemsg_level(_("\nWrong number of fields " \
420 + "in %s: %s\n\n") % (location, l),
421 + level=logging.ERROR, noiselevel=-1)
422 + continue
423 + arch = fields[0]
424 + obj = fields[1]
425 + soname = fields[2]
426 + path = set([normalize_path(x) \
427 + for x in filter(None, fields[3].replace(
428 + "${ORIGIN}", os.path.dirname(obj)).replace(
429 + "$ORIGIN", os.path.dirname(obj)).split(":"))])
430 + needed = [x for x in fields[4].split(",") if x]
431 +
432 + obj_key = self._obj_key(obj)
433 + indexed = True
434 + myprops = obj_properties.get(obj_key)
435 + if myprops is None:
436 + indexed = False
437 + myprops = (arch, needed, path, soname, set())
438 + obj_properties[obj_key] = myprops
439 + # All object paths are added into the obj_properties tuple.
440 + myprops[4].add(obj)
441 +
442 + # Don't index the same file more that once since only one
443 + # set of data can be correct and therefore mixing data
444 + # may corrupt the index (include_file overrides previously
445 + # installed).
446 + if indexed:
447 + continue
448 +
449 + arch_map = libs.get(arch)
450 + if arch_map is None:
451 + arch_map = {}
452 + libs[arch] = arch_map
453 + if soname:
454 + soname_map = arch_map.get(soname)
455 + if soname_map is None:
456 + soname_map = self._soname_map_class(
457 + providers=set(), consumers=set())
458 + arch_map[soname] = soname_map
459 + soname_map.providers.add(obj_key)
460 + for needed_soname in needed:
461 + soname_map = arch_map.get(needed_soname)
462 + if soname_map is None:
463 + soname_map = self._soname_map_class(
464 + providers=set(), consumers=set())
465 + arch_map[needed_soname] = soname_map
466 + soname_map.consumers.add(obj_key)
467 diff --cc pym/portage/util/_dyn_libs/LinkageMapXCoff.py
468 index 0e930fe,0000000..782cc54
469 mode 100644,000000..100644
470 --- a/pym/portage/util/_dyn_libs/LinkageMapXCoff.py
471 +++ b/pym/portage/util/_dyn_libs/LinkageMapXCoff.py
472 @@@ -1,319 -1,0 +1,326 @@@
473 +# Copyright 1998-2011 Gentoo Foundation
474 +# Distributed under the terms of the GNU General Public License v2
475 +
476 +import errno
477 +import logging
478 +import subprocess
479 +
480 +import portage
481 +from portage import _encodings
482 +from portage import _os_merge
483 +from portage import _unicode_decode
484 +from portage import _unicode_encode
485 +from portage.cache.mappings import slot_dict_class
486 +from portage.exception import CommandNotFound
487 +from portage.localization import _
488 +from portage.util import getlibpaths
489 +from portage.util import grabfile
490 +from portage.util import normalize_path
491 +from portage.util import writemsg_level
492 +from portage.const import EPREFIX, BASH_BINARY
493 +from portage.util._dyn_libs.LinkageMapELF import LinkageMapELF
494 +
495 +class LinkageMapXCoff(LinkageMapELF):
496 +
497 + """Models dynamic linker dependencies."""
498 +
499 + _needed_aux_key = "NEEDED.XCOFF.1"
500 +
501 + class _ObjectKey(LinkageMapELF._ObjectKey):
502 +
503 + def __init__(self, obj, root):
504 + LinkageMapELF._ObjectKey.__init__(self, obj, root)
505 +
506 + def _generate_object_key(self, obj, root):
507 + """
508 + Generate object key for a given object.
509 +
510 + @param object: path to a file
511 + @type object: string (example: '/usr/bin/bar')
512 + @rtype: 2-tuple of types (long, int) if object exists. string if
513 + object does not exist.
514 + @return:
515 + 1. 2-tuple of object's inode and device from a stat call, if object
516 + exists.
517 + 2. realpath of object if object does not exist.
518 +
519 + """
520 +
521 + os = _os_merge
522 +
523 + try:
524 + _unicode_encode(obj,
525 + encoding=_encodings['merge'], errors='strict')
526 + except UnicodeEncodeError:
527 + # The package appears to have been merged with a
528 + # different value of sys.getfilesystemencoding(),
529 + # so fall back to utf_8 if appropriate.
530 + try:
531 + _unicode_encode(obj,
532 + encoding=_encodings['fs'], errors='strict')
533 + except UnicodeEncodeError:
534 + pass
535 + else:
536 + os = portage.os
537 +
538 + abs_path = os.path.join(root, obj.lstrip(os.sep))
539 + try:
540 + object_stat = os.stat(abs_path)
541 + except OSError:
542 + # Use the realpath as the key if the file does not exists on the
543 + # filesystem.
544 + return os.path.realpath(abs_path)
545 + # Return a tuple of the device and inode, as well as the basename,
546 + # because of hardlinks the device and inode might be identical.
547 + return (object_stat.st_dev, object_stat.st_ino, os.path.basename(abs_path.rstrip(os.sep)))
548 +
549 + def file_exists(self):
550 + """
551 + Determine if the file for this key exists on the filesystem.
552 +
553 + @rtype: Boolean
554 + @return:
555 + 1. True if the file exists.
556 + 2. False if the file does not exist or is a broken symlink.
557 +
558 + """
559 + return isinstance(self._key, tuple)
560 +
561 + class _LibGraphNode(_ObjectKey):
562 + __slots__ = ("alt_paths",)
563 +
564 - def __init__(self, obj, root):
565 - LinkageMapXCoff._ObjectKey.__init__(self, obj, root)
566 ++ def __init__(self, key):
567 ++ """
568 ++ Create a _LibGraphNode from an existing _ObjectKey.
569 ++ This re-uses the _key attribute in order to avoid repeating
570 ++ any previous stat calls, which helps to avoid potential race
571 ++ conditions due to inconsistent stat results when the
572 ++ file system is being modified concurrently.
573 ++ """
574 ++ self._key = key._key
575 + self.alt_paths = set()
576 +
577 + def __str__(self):
578 + return str(sorted(self.alt_paths))
579 +
580 + def rebuild(self, exclude_pkgs=None, include_file=None,
581 + preserve_paths=None):
582 + """
583 + Raises CommandNotFound if there are preserved libs
584 + and the scanelf binary is not available.
585 +
586 + @param exclude_pkgs: A set of packages that should be excluded from
587 + the LinkageMap, since they are being unmerged and their NEEDED
588 + entries are therefore irrelevant and would only serve to corrupt
589 + the LinkageMap.
590 + @type exclude_pkgs: set
591 + @param include_file: The path of a file containing NEEDED entries for
592 + a package which does not exist in the vardbapi yet because it is
593 + currently being merged.
594 + @type include_file: String
595 + @param preserve_paths: Libraries preserved by a package instance that
596 + is currently being merged. They need to be explicitly passed to the
597 + LinkageMap, since they are not registered in the
598 + PreservedLibsRegistry yet.
599 + @type preserve_paths: set
600 + """
601 +
602 + os = _os_merge
603 + root = self._root
604 + root_len = len(root) - 1
605 + self._clear_cache()
606 + self._defpath.update(getlibpaths(self._root))
607 + libs = self._libs
608 + obj_properties = self._obj_properties
609 +
610 + lines = []
611 +
612 + # Data from include_file is processed first so that it
613 + # overrides any data from previously installed files.
614 + if include_file is not None:
615 + for line in grabfile(include_file):
616 + lines.append((include_file, line))
617 +
618 + aux_keys = [self._needed_aux_key]
619 + can_lock = os.access(os.path.dirname(self._dbapi._dbroot), os.W_OK)
620 + if can_lock:
621 + self._dbapi.lock()
622 + try:
623 + for cpv in self._dbapi.cpv_all():
624 + if exclude_pkgs is not None and cpv in exclude_pkgs:
625 + continue
626 + needed_file = self._dbapi.getpath(cpv,
627 + filename=self._needed_aux_key)
628 + for line in self._dbapi.aux_get(cpv, aux_keys)[0].splitlines():
629 + lines.append((needed_file, line))
630 + finally:
631 + if can_lock:
632 + self._dbapi.unlock()
633 +
634 + # have to call scanelf for preserved libs here as they aren't
635 + # registered in NEEDED.XCOFF.1 files
636 + plibs = set()
637 + if preserve_paths is not None:
638 + plibs.update(preserve_paths)
639 + if self._dbapi._plib_registry and \
640 + self._dbapi._plib_registry.hasEntries():
641 + for cpv, items in \
642 + self._dbapi._plib_registry.getPreservedLibs().items():
643 + if exclude_pkgs is not None and cpv in exclude_pkgs:
644 + # These preserved libs will either be unmerged,
645 + # rendering them irrelevant, or they will be
646 + # preserved in the replacement package and are
647 + # already represented via the preserve_paths
648 + # parameter.
649 + continue
650 + plibs.update(items)
651 + if plibs:
652 + for x in plibs:
653 + args = [BASH_BINARY, "-c", ':'
654 + + '; member="' + x + '"'
655 + + '; archive=${member}'
656 + + '; if [[ ${member##*/} == .*"["*"]" ]]'
657 + + '; then member=${member%/.*}/${member##*/.}'
658 + + '; archive=${member%[*}'
659 + + '; fi'
660 + + '; member=${member#${archive}}'
661 + + '; [[ -r ${archive} ]] || chmod a+r "${archive}"'
662 + + '; eval $(aixdll-query "${archive}${member}" FILE MEMBER FLAGS FORMAT RUNPATH DEPLIBS)'
663 + + '; [[ -n ${member} ]] && needed=${FILE##*/} || needed='
664 + + '; for deplib in ${DEPLIBS}'
665 + + '; do eval deplib=${deplib}'
666 + + '; if [[ ${deplib} != "." && ${deplib} != ".." ]]'
667 + + '; then needed="${needed}${needed:+,}${deplib}"'
668 + + '; fi'
669 + + '; done'
670 + + '; [[ -n ${MEMBER} ]] && MEMBER="[${MEMBER}]"'
671 + + '; [[ " ${FLAGS} " == *" SHROBJ "* ]] && soname=${FILE##*/}${MEMBER} || soname='
672 + + '; echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}}${MEMBER};${soname};${RUNPATH};${needed}"'
673 + + '; [[ -z ${member} && -n ${MEMBER} ]] && echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}};${FILE##*/};;"'
674 + ]
675 + try:
676 + proc = subprocess.Popen(args, stdout=subprocess.PIPE)
677 + except EnvironmentError as e:
678 + if e.errno != errno.ENOENT:
679 + raise
680 + raise CommandNotFound(args[0])
681 + else:
682 + for l in proc.stdout:
683 + try:
684 + l = _unicode_decode(l,
685 + encoding=_encodings['content'], errors='strict')
686 + except UnicodeDecodeError:
687 + l = _unicode_decode(l,
688 + encoding=_encodings['content'], errors='replace')
689 + writemsg_level(_("\nError decoding characters " \
690 + "returned from aixdll-query: %s\n\n") % (l,),
691 + level=logging.ERROR, noiselevel=-1)
692 + l = l.rstrip("\n")
693 + if not l:
694 + continue
695 + fields = l.split(";")
696 + if len(fields) < 5:
697 + writemsg_level(_("\nWrong number of fields " \
698 + "returned from aixdll-query: %s\n\n") % (l,),
699 + level=logging.ERROR, noiselevel=-1)
700 + continue
701 + fields[1] = fields[1][root_len:]
702 + plibs.discard(fields[1])
703 + lines.append(("aixdll-query", ";".join(fields)))
704 + proc.wait()
705 +
706 + if plibs:
707 + # Preserved libraries that did not appear in the bash
708 + # aixdll-query code output. This is known to happen with
709 + # statically linked libraries. Generate dummy lines for
710 + # these, so we can assume that every preserved library has
711 + # an entry in self._obj_properties. This is important in
712 + # order to prevent findConsumers from raising an unwanted
713 + # KeyError.
714 + for x in plibs:
715 + lines.append(("plibs", ";".join(['', x, '', '', ''])))
716 +
717 + for location, l in lines:
718 + l = l.rstrip("\n")
719 + if not l:
720 + continue
721 + fields = l.split(";")
722 + if len(fields) < 5:
723 + writemsg_level(_("\nWrong number of fields " \
724 + "in %s: %s\n\n") % (location, l),
725 + level=logging.ERROR, noiselevel=-1)
726 + continue
727 + arch = fields[0]
728 +
729 + def as_contentmember(obj):
730 + if obj.endswith("]"):
731 + if obj.find("/") >= 0:
732 + return obj[:obj.rfind("/")] + "/." + obj[obj.rfind("/")+1:]
733 + return "." + obj
734 + return obj
735 +
736 + obj = as_contentmember(fields[1])
737 + soname = as_contentmember(fields[2])
738 + path = set([normalize_path(x) \
739 + for x in filter(None, fields[3].replace(
740 + "${ORIGIN}", os.path.dirname(obj)).replace(
741 + "$ORIGIN", os.path.dirname(obj)).split(":"))])
742 + needed = [as_contentmember(x) for x in fields[4].split(",") if x]
743 +
744 + obj_key = self._obj_key(obj)
745 + indexed = True
746 + myprops = obj_properties.get(obj_key)
747 + if myprops is None:
748 + indexed = False
749 + myprops = (arch, needed, path, soname, set())
750 + obj_properties[obj_key] = myprops
751 + # All object paths are added into the obj_properties tuple.
752 + myprops[4].add(obj)
753 +
754 + # Don't index the same file more that once since only one
755 + # set of data can be correct and therefore mixing data
756 + # may corrupt the index (include_file overrides previously
757 + # installed).
758 + if indexed:
759 + continue
760 +
761 + arch_map = libs.get(arch)
762 + if arch_map is None:
763 + arch_map = {}
764 + libs[arch] = arch_map
765 + if soname:
766 + soname_map = arch_map.get(soname)
767 + if soname_map is None:
768 + soname_map = self._soname_map_class(
769 + providers=set(), consumers=set())
770 + arch_map[soname] = soname_map
771 + soname_map.providers.add(obj_key)
772 + for needed_soname in needed:
773 + soname_map = arch_map.get(needed_soname)
774 + if soname_map is None:
775 + soname_map = self._soname_map_class(
776 + providers=set(), consumers=set())
777 + arch_map[needed_soname] = soname_map
778 + soname_map.consumers.add(obj_key)
779 +
780 + def getSoname(self, obj):
781 + """
782 + Return the soname associated with an object.
783 +
784 + @param obj: absolute path to an object
785 + @type obj: string (example: '/usr/bin/bar')
786 + @rtype: string
787 + @return: soname as a string
788 +
789 + """
790 + if not self._libs:
791 + self.rebuild()
792 + if isinstance(obj, self._ObjectKey):
793 + obj_key = obj
794 + if obj_key not in self._obj_properties:
795 + raise KeyError("%s not in object list" % obj_key)
796 + return self._obj_properties[obj_key][3]
797 + if obj not in self._obj_key_cache:
798 + raise KeyError("%s not in object list" % obj)
799 + return self._obj_properties[self._obj_key_cache[obj]][3]
800 +