1 # Copyright 2008 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
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")
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
= {}
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.
45 matchedLibraries
= set()
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
)
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
))
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
)
79 print "atoms to be emerged:"
80 for x
in sorted(atoms
):
85 timeStart
= time
.time()
86 brokenDependencies
= self
.linkmap
.listBrokenDependencies()
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.
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
):
108 f
= open(os
.path
.join(libMaskDir
, file), "r")
110 lines
.extend(f
.readlines())
113 except IOError: # OSError?
115 # The following parses SEARCH_DIRS_MASK and LD_LIBRARY_MASK variables
116 # from /etc/revdep-rebuild/*
118 matchDir
= _dirMask_re_
.match(line
)
119 matchLib
= _libMask_re_
.match(line
)
121 dirMask
.extend(matchDir
.group(1).split())
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
:
139 print "The following are masked:"
140 for binary
, libSet
in brokenDependencies
.items():
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
]
147 print "dirMask:",binary
149 # Check if all the required libraries are masked.
150 if binary
in brokenDependencies
and libSet
.issubset(set(libMask
)):
151 del brokenDependencies
[binary
]
153 print "libMask:", binary
, libSet
& set(libMask
)
155 timeMask
= time
.time() - timeStart
157 # Determine atoms to emerge based on broken binaries in brokenDependencies.
159 timeStart
= time
.time()
160 if brokenDependencies
:
161 atoms
= self
.mapPathsToAtoms(set(brokenDependencies
.keys()))
163 timeAtoms
= time
.time() - timeStart
168 print "Directory mask:", dirMask
170 print "Library mask:", libMask
172 print len(brokenDependencies
), "brokenDependencies:"
173 for x
in sorted(brokenDependencies
.keys()):
176 print '\t', brokenDependencies
[x
]
178 print "atoms to be emerged:"
179 for x
in sorted(atoms
):
182 print "listBrokenBinaries time:", timeListBrokenBinaries
184 print "Mask time:", timeMask
186 print "Atoms time:", timeAtoms
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
)