Gentoo Archives: gentoo-commits

From: "Marius Mauch (genone)" <genone@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r10081 - in main/trunk: cnf pym/_emerge pym/portage/dbapi pym/portage/sets
Date: Fri, 02 May 2008 08:20:43
Message-Id: E1JrqVU-0000z8-PN@stork.gentoo.org
1 Author: genone
2 Date: 2008-05-02 08:20:39 +0000 (Fri, 02 May 2008)
3 New Revision: 10081
4
5 Added:
6 main/trunk/pym/portage/sets/libs.py
7 Modified:
8 main/trunk/cnf/sets.conf
9 main/trunk/pym/_emerge/__init__.py
10 main/trunk/pym/portage/dbapi/vartree.py
11 main/trunk/pym/portage/sets/dbapi.py
12 Log:
13 v2 of FEATURES=preserved-libs, using LinkageMap instead of the now removed LibraryPackageMap class
14
15 Modified: main/trunk/cnf/sets.conf
16 ===================================================================
17 --- main/trunk/cnf/sets.conf 2008-05-02 05:09:48 UTC (rev 10080)
18 +++ main/trunk/cnf/sets.conf 2008-05-02 08:20:39 UTC (rev 10081)
19 @@ -39,5 +39,5 @@
20 # Set to rebuild all packages that need a preserved lib that only remains due
21 # to FEATURES=preserve-libs
22 [preserved-rebuild]
23 -class = portage.sets.dbapi.PreservedLibraryConsumerSet
24 +class = portage.sets.libs.PreservedLibraryConsumerSet
25 world-candidate = False
26
27 Modified: main/trunk/pym/_emerge/__init__.py
28 ===================================================================
29 --- main/trunk/pym/_emerge/__init__.py 2008-05-02 05:09:48 UTC (rev 10080)
30 +++ main/trunk/pym/_emerge/__init__.py 2008-05-02 08:20:39 UTC (rev 10081)
31 @@ -7878,6 +7878,7 @@
32 portage.writemsg_stdout(colorize("WARN", "WARNING:")
33 + " AUTOCLEAN is disabled. This can cause serious"
34 + " problems due to overlapping packages.\n")
35 + trees[settings["ROOT"]]["vartree"].dbapi.plib_registry.pruneNonExisting()
36
37 if merge_count and not (buildpkgonly or fetchonly or pretend):
38 post_emerge(trees, mtimedb, retval)
39
40 Modified: main/trunk/pym/portage/dbapi/vartree.py
41 ===================================================================
42 --- main/trunk/pym/portage/dbapi/vartree.py 2008-05-02 05:09:48 UTC (rev 10080)
43 +++ main/trunk/pym/portage/dbapi/vartree.py 2008-05-02 08:20:39 UTC (rev 10081)
44 @@ -27,7 +27,7 @@
45 from portage.elog.messages import ewarn
46 from portage.elog.filtering import filter_mergephases, filter_unmergephases
47
48 -import os, re, sys, stat, errno, commands, copy, time
49 +import os, re, sys, stat, errno, commands, copy, time, subprocess
50 from itertools import izip
51
52 try:
53 @@ -135,38 +135,63 @@
54 def rebuild(self):
55 libs = {}
56 obj_properties = {}
57 + lines = []
58 for cpv in self._dbapi.cpv_all():
59 - lines = grabfile(self._dbapi.getpath(cpv, filename="NEEDED.2"))
60 - for l in lines:
61 - fields = l.strip("\n").split(";")
62 - if len(fields) < 5:
63 - print "Error", fields
64 - # insufficient field length
65 - continue
66 - arch = fields[0]
67 - obj = fields[1]
68 - soname = fields[2]
69 - path = fields[3].replace("${ORIGIN}", os.path.dirname(obj)).replace("$ORIGIN", os.path.dirname(obj)).split(":")
70 - needed = fields[4].split(",")
71 - if soname:
72 - libs.setdefault(soname, {arch: {"providers": [], "consumers": []}})
73 - libs[soname].setdefault(arch, {"providers": [], "consumers": []})
74 - libs[soname][arch]["providers"].append(obj)
75 - for x in needed:
76 - libs.setdefault(x, {arch: {"providers": [], "consumers": []}})
77 - libs[x].setdefault(arch, {"providers": [], "consumers": []})
78 - libs[x][arch]["consumers"].append(obj)
79 - obj_properties[obj] = (arch, path, needed, soname)
80 + lines += grabfile(self._dbapi.getpath(cpv, filename="NEEDED.2"))
81 +
82 + # have to call scanelf for preserved libs here as they aren't
83 + # registered in NEEDED.2 files
84 + if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs():
85 + args = ["/usr/bin/scanelf", "-yqF", "%a;%F;%S;%r;%n"]
86 + for items in self._dbapi.plib_registry.getPreservedLibs().values():
87 + args += items
88 + proc = subprocess.Popen(args, stdout=subprocess.PIPE)
89 + output = [l[3:] for l in proc.communicate()[0].split("\n")]
90 + lines += output
91 +
92 + for l in lines:
93 + if l.strip() == "":
94 + continue
95 + fields = l.strip("\n").split(";")
96 + if len(fields) < 5:
97 + print "Error", fields
98 + # insufficient field length
99 + continue
100 + arch = fields[0]
101 + obj = fields[1]
102 + soname = fields[2]
103 + path = fields[3].replace("${ORIGIN}", os.path.dirname(obj)).replace("$ORIGIN", os.path.dirname(obj)).split(":")
104 + needed = fields[4].split(",")
105 + if soname:
106 + libs.setdefault(soname, {arch: {"providers": [], "consumers": []}})
107 + libs[soname].setdefault(arch, {"providers": [], "consumers": []})
108 + libs[soname][arch]["providers"].append(obj)
109 + for x in needed:
110 + libs.setdefault(x, {arch: {"providers": [], "consumers": []}})
111 + libs[x].setdefault(arch, {"providers": [], "consumers": []})
112 + libs[x][arch]["consumers"].append(obj)
113 + obj_properties[obj] = (arch, needed, path, soname)
114
115 self._libs = libs
116 self._obj_properties = obj_properties
117 +
118 + def listLibraryObjects(self):
119 + rValue = []
120 + if not self._libs:
121 + self.rebuild()
122 + for soname in self._libs:
123 + for arch in self._libs[soname]:
124 + rValue.extend(self._libs[soname][arch]["providers"])
125 + return rValue
126
127 def findProviders(self, obj):
128 + if not self._libs:
129 + self.rebuild()
130 obj = os.path.realpath(obj)
131 rValue = {}
132 if obj not in self._obj_properties:
133 raise KeyError("%s not in object list" % obj)
134 - arch, path, needed, soname = self._obj_properties[obj]
135 + arch, needed, path, soname = self._obj_properties[obj]
136 path.extend(self._defpath)
137 path = [os.path.realpath(x) for x in path]
138 for x in needed:
139 @@ -181,13 +206,15 @@
140 return rValue
141
142 def findConsumers(self, obj):
143 + if not self._libs:
144 + self.rebuild()
145 obj = os.path.realpath(obj)
146 rValue = set()
147 for soname in self._libs:
148 for arch in self._libs[soname]:
149 if obj in self._libs[soname][arch]["providers"]:
150 for x in self._libs[soname][arch]["consumers"]:
151 - path = self._obj_properties[x][1]
152 + path = self._obj_properties[x][2]
153 path = [os.path.realpath(y) for y in path+self._defpath]
154 if soname[0] == os.sep and os.path.realpath(soname) == os.path.realpath(obj):
155 rValue.add(x)
156 @@ -275,7 +302,6 @@
157 self._counter_path = os.path.join(root,
158 CACHE_PATH.lstrip(os.path.sep), "counter")
159
160 - self.libmap = LibraryPackageMap(os.path.join(self.root, CACHE_PATH.lstrip(os.sep), "library_consumers"), self)
161 try:
162 self.plib_registry = PreservedLibsRegistry(
163 os.path.join(self.root, PRIVATE_PATH, "preserved_libs_registry"))
164 @@ -283,6 +309,8 @@
165 # apparently this user isn't allowed to access PRIVATE_PATH
166 self.plib_registry = None
167
168 + self.linkmap = LinkageMap(self)
169 +
170 def getpath(self, mykey, filename=None):
171 rValue = os.path.join(self.root, VDB_PATH, mykey)
172 if filename != None:
173 @@ -1253,31 +1281,18 @@
174 return retval
175
176 # regenerate reverse NEEDED map
177 - self.vartree.dbapi.libmap.update()
178 + self.vartree.dbapi.linkmap.rebuild()
179
180 # remove preserved libraries that don't have any consumers left
181 # FIXME: this code is quite ugly and can likely be optimized in several ways
182 plib_dict = plib_registry.getPreservedLibs()
183 for cpv in plib_dict:
184 - keeplist = []
185 plib_dict[cpv].sort()
186 for f in plib_dict[cpv]:
187 - if not os.path.exists(f) or os.path.realpath(f) in keeplist:
188 + if not os.path.exists(f):
189 continue
190 unlink_list = []
191 - while os.path.islink(f):
192 - if os.path.basename(f) in self.vartree.dbapi.libmap.get():
193 - unlink_list = []
194 - keeplist.append(os.path.realpath(f))
195 - break
196 - else:
197 - unlink_list.append(f)
198 - # only follow symlinks if the target is also a preserved lib object
199 - if os.readlink(f) in plib_dict[cpv]:
200 - f = os.readlink(f)
201 - else:
202 - break
203 - if not os.path.islink(f) and not os.path.basename(f) in self.vartree.dbapi.libmap.get():
204 + if not self.vartree.dbapi.linkmap.findConsumers(f):
205 unlink_list.append(f)
206 for obj in unlink_list:
207 try:
208 @@ -1664,22 +1679,27 @@
209
210 def _preserve_libs(self, srcroot, destroot, mycontents, counter):
211 # read global reverse NEEDED map
212 - libmap = self.vartree.dbapi.libmap.get()
213 + linkmap = self.vartree.dbapi.linkmap
214 + linkmap.rebuild()
215 + liblist = linkmap.listLibraryObjects()
216
217 # get list of libraries from old package instance
218 old_contents = self._installed_instance.getcontents().keys()
219 - old_libs = set([os.path.basename(x) for x in old_contents]).intersection(libmap)
220 + old_libs = set(old_contents).intersection(liblist)
221
222 # get list of libraries from new package instance
223 - mylibs = set([os.path.basename(x) for x in mycontents]).intersection(libmap)
224 + mylibs = set(mycontents).intersection(liblist)
225
226 # check which libs are present in the old, but not the new package instance
227 - preserve_libs = old_libs.difference(mylibs)
228 + candidates = old_libs.difference(mylibs)
229 + for x in old_contents:
230 + if os.path.islink(x) and os.path.realpath(x) in candidates:
231 + candidates.add(x)
232
233 # ignore any libs that are only internally used by the package
234 def has_external_consumers(lib, contents, otherlibs):
235 - consumers = set(libmap[lib])
236 - contents_without_libs = [x for x in contents if not os.path.basename(x) in otherlibs]
237 + consumers = linkmap.findConsumers(lib)
238 + contents_without_libs = [x for x in contents if x not in otherlibs]
239
240 # just used by objects that will be autocleaned
241 if len(consumers.difference(contents_without_libs)) == 0:
242 @@ -1696,23 +1716,34 @@
243 else:
244 return True
245
246 - for lib in list(preserve_libs):
247 - if not has_external_consumers(lib, old_contents, preserve_libs):
248 - preserve_libs.remove(lib)
249 - # only preserve the lib if there is no other copy in the search path
250 - for path in getlibpaths():
251 - fullname = os.path.join(path, lib)
252 - if fullname not in old_contents and os.path.exists(fullname) and lib in preserve_libs:
253 - preserve_libs.remove(lib)
254 -
255 - # get the real paths for the libs
256 - preserve_paths = [x for x in old_contents if os.path.basename(x) in preserve_libs]
257 - del old_contents, old_libs, mylibs, preserve_libs
258 -
259 + for lib in list(candidates):
260 + if not has_external_consumers(lib, old_contents, candidates):
261 + candidates.remove(lib)
262 + # only preserve the lib if there is no other copy to use for each consumer
263 + keep = False
264 + for c in linkmap.findConsumers(lib):
265 + localkeep = True
266 + providers = linkmap.findProviders(c)
267 + for soname in providers:
268 + if lib in providers[soname]:
269 + for p in providers[soname]:
270 + if p not in candidates:
271 + localkeep = False
272 + break
273 + break
274 + if localkeep:
275 + keep = True
276 +
277 + del mylibs, mycontents, old_contents, liblist
278 +
279 # inject files that should be preserved into our image dir
280 import shutil
281 missing_paths = []
282 - for x in preserve_paths:
283 + for x in candidates:
284 + # skip existing files so the 'new' libs aren't overwritten
285 + if os.path.exists(os.path.join(srcroot, x.lstrip(os.sep))):
286 + missing_paths.append(x)
287 + continue
288 print "injecting %s into %s" % (x, srcroot)
289 if not os.path.exists(os.path.join(destroot, x.lstrip(os.sep))):
290 print "%s does not exist so can't be preserved" % x
291 @@ -1730,14 +1761,14 @@
292 os.symlink(linktarget, os.path.join(srcroot, x.lstrip(os.sep)))
293 if linktarget[0] != os.sep:
294 linktarget = os.path.join(os.path.dirname(x), linktarget)
295 - preserve_paths.append(linktarget)
296 + candidates.add(linktarget)
297 else:
298 shutil.copy2(os.path.join(destroot, x.lstrip(os.sep)),
299 os.path.join(srcroot, x.lstrip(os.sep)))
300
301 - preserve_paths = [x for x in preserve_paths if x not in missing_paths]
302 + preserve_paths = [x for x in candidates if x not in missing_paths]
303
304 - del missing_paths
305 + del missing_paths, candidates
306
307 # keep track of the libs we preserved
308 self.vartree.dbapi.plib_registry.register(self.mycpv, self.settings["SLOT"], counter, preserve_paths)
309 @@ -2275,7 +2306,7 @@
310 del conf_mem_file
311
312 # regenerate reverse NEEDED map
313 - self.vartree.dbapi.libmap.update()
314 + self.vartree.dbapi.linkmap.rebuild()
315
316 #do postinst script
317 self.settings["PORTAGE_UPDATE_ENV"] = \
318
319 Modified: main/trunk/pym/portage/sets/dbapi.py
320 ===================================================================
321 --- main/trunk/pym/portage/sets/dbapi.py 2008-05-02 05:09:48 UTC (rev 10080)
322 +++ main/trunk/pym/portage/sets/dbapi.py 2008-05-02 08:20:39 UTC (rev 10081)
323 @@ -2,14 +2,10 @@
324 # Distributed under the terms of the GNU General Public License v2
325 # $Id$
326
327 -from portage.versions import catsplit, catpkgsplit
328 +from portage.versions import catsplit
329 from portage.sets.base import PackageSet
330 from portage.sets import SetConfigError, get_boolean
331 -from portage.dbapi.vartree import dblink
332 -from portage.util import grabfile
333
334 -import os
335 -
336 __all__ = ["CategorySet", "EverythingSet"]
337
338 class EverythingSet(PackageSet):
339 @@ -108,71 +104,3 @@
340 return rValue
341 multiBuilder = classmethod(multiBuilder)
342
343 -class LibraryConsumerSet(PackageSet):
344 - _operations = ["merge", "unmerge"]
345 -
346 - def __init__(self, vardbapi, debug=False):
347 - super(LibraryConsumerSet, self).__init__()
348 - self.dbapi = vardbapi
349 - self.debug = debug
350 -
351 - def mapPathsToAtoms(self, paths):
352 - rValue = set()
353 - for cpv in self.dbapi.cpv_all():
354 - mysplit = catsplit(cpv)
355 - link = dblink(mysplit[0], mysplit[1], myroot=self.dbapi.root, \
356 - mysettings=self.dbapi.settings, treetype='vartree', \
357 - vartree=self.dbapi.vartree)
358 - if paths.intersection(link.getcontents()):
359 - cat, pn = catpkgsplit(cpv)[:2]
360 - slot = self.dbapi.aux_get(cpv, ["SLOT"])[0]
361 - rValue.add("%s/%s:%s" % (cat, pn, slot))
362 - return rValue
363 -
364 -
365 -class PreservedLibraryConsumerSet(LibraryConsumerSet):
366 - def load(self):
367 - reg = self.dbapi.plib_registry
368 - libmap = self.dbapi.libmap.get()
369 - consumers = set()
370 - if reg:
371 - for libs in reg.getPreservedLibs().values():
372 - for lib in libs:
373 - paths = libmap.get(os.path.basename(lib), [])
374 - consumers.update(paths)
375 - else:
376 - return
377 - if not consumers:
378 - return
379 - self._setAtoms(self.mapPathsToAtoms(consumers))
380 -
381 - def singleBuilder(cls, options, settings, trees):
382 - return PreservedLibraryConsumerSet(trees["vartree"].dbapi)
383 - singleBuilder = classmethod(singleBuilder)
384 -
385 -class MissingLibraryConsumerSet(LibraryConsumerSet):
386 - _operations = ["merge", "unmerge"]
387 -
388 - def load(self):
389 - atoms = set()
390 - consumers = set()
391 - for lib in self.dbapi.libmap.get():
392 - found=False
393 - for searchdir in grabfile(os.path.join(os.sep, self.dbapi.root, "etc/ld.so.conf")):
394 - if os.path.exists(os.path.join(searchdir, lib)):
395 - found=True
396 - break
397 - if not found:
398 - print "missing library: %s" % lib
399 - print "consumers:"
400 - for x in self.dbapi.libmap.get()[lib]:
401 - print " ", x
402 - consumers.update(self.dbapi.libmap.get()[lib])
403 - if not consumers:
404 - return
405 - self._setAtoms(self.mapPathsToAtoms(consumers))
406 -
407 - def singleBuilder(cls, options, settings, trees):
408 - debug = get_boolean(options, "debug", False)
409 - return MissingLibraryConsumerSet(trees["vartree"].dbapi, debug=debug)
410 - singleBuilder = classmethod(singleBuilder)
411
412 Added: main/trunk/pym/portage/sets/libs.py
413 ===================================================================
414 --- main/trunk/pym/portage/sets/libs.py (rev 0)
415 +++ main/trunk/pym/portage/sets/libs.py 2008-05-02 08:20:39 UTC (rev 10081)
416 @@ -0,0 +1,50 @@
417 +# Copyright 2007 Gentoo Foundation
418 +# Distributed under the terms of the GNU General Public License v2
419 +# $Id$
420 +
421 +from portage.sets.base import PackageSet
422 +from portage.dbapi.vartree import dblink
423 +from portage.versions import catsplit, catpkgsplit
424 +
425 +import os
426 +
427 +class LibraryConsumerSet(PackageSet):
428 + _operations = ["merge", "unmerge"]
429 +
430 + def __init__(self, vardbapi, debug=False):
431 + super(LibraryConsumerSet, self).__init__()
432 + self.dbapi = vardbapi
433 + self.debug = debug
434 +
435 + def mapPathsToAtoms(self, paths):
436 + rValue = set()
437 + for cpv in self.dbapi.cpv_all():
438 + mysplit = catsplit(cpv)
439 + link = dblink(mysplit[0], mysplit[1], myroot=self.dbapi.root, \
440 + mysettings=self.dbapi.settings, treetype='vartree', \
441 + vartree=self.dbapi.vartree)
442 + if paths.intersection(link.getcontents()):
443 + cat, pn = catpkgsplit(cpv)[:2]
444 + slot = self.dbapi.aux_get(cpv, ["SLOT"])[0]
445 + rValue.add("%s/%s:%s" % (cat, pn, slot))
446 + return rValue
447 +
448 +
449 +class PreservedLibraryConsumerSet(LibraryConsumerSet):
450 + def load(self):
451 + reg = self.dbapi.plib_registry
452 + consumers = set()
453 + if reg:
454 + for libs in reg.getPreservedLibs().values():
455 + for lib in libs:
456 + #print lib, self.dbapi.linkmap.findConsumers(lib)
457 + consumers.update(self.dbapi.linkmap.findConsumers(lib))
458 + else:
459 + return
460 + if not consumers:
461 + return
462 + self._setAtoms(self.mapPathsToAtoms(consumers))
463 +
464 + def singleBuilder(cls, options, settings, trees):
465 + return PreservedLibraryConsumerSet(trees["vartree"].dbapi)
466 + singleBuilder = classmethod(singleBuilder)
467
468
469 Property changes on: main/trunk/pym/portage/sets/libs.py
470 ___________________________________________________________________
471 Name: svn:keywords
472 + Id
473
474 --
475 gentoo-commits@l.g.o mailing list