several minor changes
[revdep-rebuild-reimplementation.git] / pym / portage / sets / revdep.py
blob12895d1a390ea8e0432a105e350c98284a85ba9d
1 # Copyright 2008 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 import os
5 import re
6 import time
7 import subprocess
9 from portage.sets.libs import LibraryConsumerSet
10 from portage.sets import get_boolean
11 from portage.versions import catsplit
12 from portage.dbapi.vartree import dblink
14 __all__ = ["MissingLibraryConsumerSet"]
16 class MissingLibraryConsumerSet(LibraryConsumerSet):
17 description = "set of packages to emerge due to missing libraries"
18 _operations = ["merge"]
20 def __init__(self, vardbapi, debug=False):
21 super(MissingLibraryConsumerSet, self).__init__(vardbapi, debug)
22 # FIXME Since we can't get command line arguments from the user, the
23 # soname can be passed through an environment variable for now.
24 self.root = self.dbapi.root
25 self.linkmap = self.dbapi.linkmap
26 self.searchSoname = os.getenv("LIBRARY")
28 def load(self):
29 # brokenDependencies: binary -> set-of-unsatisfied-sonames,
30 # where binary is an installed binary/library and
31 # set-of-unsatisfied-sonames are sonames required by the binary but
32 # have no corresponding libraries to fulfill the dependency.
33 brokenDependencies = {}
34 atoms = set()
35 dirMask = []
36 libMask = []
37 lines = []
38 _dirMask_re_ = re.compile(r'SEARCH_DIRS_MASK\s*=\s*"([^"]*)"')
39 _libMask_re_ = re.compile(r'LD_LIBRARY_MASK\s*=\s*"([^"]*)"')
41 # If library is given through the LIBRARY environment variable, the
42 # resulting package set will be the set of consumers of the library.
43 if self.searchSoname:
44 consumers = set()
45 matchedLibraries = set()
46 libraryObjects = []
47 # Python regular expressions are acceptable LIBRARY variables.
48 _searchSoname_re_ = re.compile(self.searchSoname)
50 # Find libraries matching searchSoname.
51 libraryObjects = self.linkmap.listLibraryObjects()
52 for obj in libraryObjects:
53 m = _searchSoname_re_.search(obj)
54 if m:
55 matchedLibraries.add(obj)
56 # TODO Add pretty output for user.
57 # Find consumers of the matched libraries.
58 for library in matchedLibraries:
59 consumers.update(self.linkmap.findConsumers(library))
61 if consumers:
62 # XXX This may or may not be necessary (or helpful). Currently,
63 # I'm not convinced that it's a bad idea to emerge library owners
64 # when said owner contains a binary that depends on the library
65 # that the user has specified via LIBRARY.
67 # The following prevents emerging the packages that provide the
68 # matched libraries. Note that this will prevent updating the
69 # packages owning the libraries if there are newer versions
70 # available in the installed slot. See bug #30095
71 atoms = self.mapPathsToAtoms(consumers)
72 libOwners = self.mapPathsToAtoms(matchedLibraries)
73 atoms.difference_update(libOwners)
75 self._setAtoms(atoms)
77 if self.debug:
78 print
79 print "atoms to be emerged:"
80 for x in sorted(atoms):
81 print x
82 return
84 if self.debug:
85 timeStart = time.time()
86 brokenDependencies = self.linkmap.listBrokenDependencies()
87 if self.debug:
88 timeListBrokenBinaries = time.time() - timeStart
90 # FIXME Currently, too many atoms may being emerged because binary
91 # packages are not being handled properly eg openoffice, nvidia-drivers,
92 # sun-jdk. Certain binaries are run in an environment where additional
93 # library paths are added via LD_LIBRARY_PATH. Since these paths aren't
94 # registered in _obj_properties, they appear broken (and are if not run
95 # in the correct environment). I have to determine if libraries and lib
96 # paths should be masked using /etc/revdep-rebuild/* as done in
97 # revdep-rebuild or if there is a better way to identify and deal with
98 # these problematic packages (or if something entirely different should be
99 # done). For now directory and library masks are used.
101 if self.debug:
102 timeStart = time.time()
103 # The following reads the contents of /etc/revdep-rebuild/*
104 libMaskDir = os.path.join(self.root, "etc", "revdep-rebuild")
105 if os.path.exists(libMaskDir):
106 for file in os.listdir(libMaskDir):
107 try:
108 f = open(os.path.join(libMaskDir, file), "r")
109 try:
110 lines.extend(f.readlines())
111 finally:
112 f.close()
113 except IOError: # OSError?
114 continue
115 # The following parses SEARCH_DIRS_MASK and LD_LIBRARY_MASK variables
116 # from /etc/revdep-rebuild/*
117 for line in lines:
118 matchDir = _dirMask_re_.match(line)
119 matchLib = _libMask_re_.match(line)
120 if matchDir:
121 dirMask.extend(matchDir.group(1).split())
122 if matchLib:
123 libMask.extend(matchLib.group(1).split())
124 # These directories contain binaries with missing shared libraries.
125 # app-emulation/vmware-workstation-6.0.1.55017
126 dirMask.append('/opt/vmware/workstation/lib')
127 # app-emulation/vmware-server-console-1.0.6.91891
128 dirMask.append('/opt/vmware/server/console/lib')
129 # www-client/mozilla-firefox-2.0.0.15
130 dirMask.append('/usr/lib/mozilla-firefox/plugins')
131 dirMask.append('/usr/lib64/mozilla-firefox/plugins')
133 # # app-emulation/emul-linux-x86-soundlibs-20080418
134 # libMask.append('libqt-mt.so.3')
136 # Remove brokenDependencies entries that are masked.
137 if dirMask or libMask:
138 if self.debug:
139 print "The following are masked:"
140 for binary, libSet in brokenDependencies.items():
141 for dir in dirMask:
142 # Check if the broken binary lies within the masked directory or
143 # its subdirectories.
144 if os.path.commonprefix([dir, binary]) == dir:
145 del brokenDependencies[binary]
146 if self.debug:
147 print "dirMask:",binary
148 break
149 # Check if all the required libraries are masked.
150 if binary in brokenDependencies and libSet.issubset(set(libMask)):
151 del brokenDependencies[binary]
152 if self.debug:
153 print "libMask:", binary, libSet & set(libMask)
154 if self.debug:
155 timeMask = time.time() - timeStart
157 # Determine atoms to emerge based on broken binaries in brokenDependencies.
158 if self.debug:
159 timeStart = time.time()
160 if brokenDependencies:
161 atoms = self.mapPathsToAtoms(set(brokenDependencies.keys()))
162 if self.debug:
163 timeAtoms = time.time() - timeStart
165 # Debug output
166 if self.debug:
167 print
168 print "Directory mask:", dirMask
169 print
170 print "Library mask:", libMask
171 print
172 print len(brokenDependencies), "brokenDependencies:"
173 for x in sorted(brokenDependencies.keys()):
174 print
175 print x, "->"
176 print '\t', brokenDependencies[x]
177 print
178 print "atoms to be emerged:"
179 for x in sorted(atoms):
180 print x
181 print
182 print "listBrokenBinaries time:", timeListBrokenBinaries
183 print
184 print "Mask time:", timeMask
185 print
186 print "Atoms time:", timeAtoms
187 print
189 self._setAtoms(atoms)
191 def singleBuilder(self, options, settings, trees):
192 debug = get_boolean(options, "debug", False)
193 return MissingLibraryConsumerSet(trees["vartree"].dbapi, debug)
194 singleBuilder = classmethod(singleBuilder)