Merge lp:~jml/pkgme-devportal/multiple-deps into lp:pkgme-devportal

Proposed by Jonathan Lange
Status: Merged
Approved by: James Westby
Approved revision: 156
Merged at revision: 142
Proposed branch: lp:~jml/pkgme-devportal/multiple-deps
Merge into: lp:pkgme-devportal
Diff against target: 341 lines (+111/-62)
7 files modified
NEWS (+16/-0)
devportalbinary/aptfile.py (+9/-4)
devportalbinary/binary.py (+29/-29)
devportalbinary/database.py (+34/-9)
devportalbinary/tests/test_aptfile.py (+4/-3)
devportalbinary/tests/test_binary.py (+1/-1)
devportalbinary/tests/test_database.py (+18/-16)
To merge this branch: bzr merge lp:~jml/pkgme-devportal/multiple-deps
Reviewer Review Type Date Requested Status
James Westby Approve
Review via email: mp+131629@code.launchpad.net

Commit message

Get all the dependencies at once.

Description of the change

Kill get_dependencies and replace with get_multiple_dependencies, that
returns all of the dependencies.

To post a comment you must log in.
Revision history for this message
James Westby (james-w) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2012-10-23 13:56:33 +0000
3+++ NEWS 2012-10-26 14:45:28 +0000
4@@ -2,6 +2,22 @@
5 NEWS for pkgme-devportal
6 ========================
7
8+NEXT
9+====
10+
11+Changes
12+-------
13+
14+ * ``get_dependencies`` is no more. Use ``get_multiple_dependencies``
15+ instead. (Jonathan Lange).
16+
17+Improvements
18+------------
19+
20+ * Added ``get_multiple_dependencies``, which gets dependencies for multiple
21+ libraries in a single operation.
22+
23+
24 0.4.10 (2012-10-23)
25 ===================
26
27
28=== modified file 'devportalbinary/aptfile.py'
29--- devportalbinary/aptfile.py 2012-10-11 13:57:59 +0000
30+++ devportalbinary/aptfile.py 2012-10-26 14:45:28 +0000
31@@ -207,13 +207,18 @@
32 for package in mapping[library]:
33 yield library, package, arch
34
35- def get_dependencies(self, lib, arch="i386"):
36- # do lazy downloading for now, we could also make this part
37- # of bin/fetch-symbols I guess(?)
38+ def get_multiple_dependencies(self, library_names, arch):
39+ """Get the binary packages that provide libraries.
40+
41+ :return: (deps, missing), where ``deps`` is a dict mapping library
42+ names to sets of packages that provide them, and ``missing`` is a
43+ set of library names for which no dependencies could be found.
44+ """
45 self._download_and_prepare_contents_file_if_needed(
46 self.DISTROSERIES, arch)
47 lib_to_pkgs = self._get_lib_to_pkgs_mapping(self.DISTROSERIES, arch)
48- return lib_to_pkgs.get(lib)
49+ deps = ((lib, lib_to_pkgs.get(lib)) for lib in library_names)
50+ return dict((lib, dep) for (lib, dep) in deps if dep)
51
52 def close(self):
53 pass
54
55=== modified file 'devportalbinary/binary.py'
56--- devportalbinary/binary.py 2012-10-11 10:15:33 +0000
57+++ devportalbinary/binary.py 2012-10-26 14:45:28 +0000
58@@ -80,6 +80,11 @@
59 class UnknownDependency(PkgmeError):
60 """Raised when we do not know which dependency to add."""
61
62+ def __init__(self, libraries):
63+ super(UnknownDependency, self).__init__(
64+ "Can't find dependency for %s." %
65+ ', '.join('"%s"' % lib for lib in libraries))
66+
67
68 class UnsupportedArchitecture(PkgmeError):
69 """Raised when we find a unsupported architecture."""
70@@ -276,29 +281,30 @@
71
72
73 def get_packages_for_libraries(library_names, arch):
74+ """Get packages that provide libraries.
75+
76+ :param library_names: A set of library names.
77+ :param arch: A single architecture to get packages for.
78+ :return: A set of package names that are dependencies that provide
79+ the libraries.
80+ """
81 conf = load_configuration()
82 lib_overrides = conf.libraries_overrides
83+ needs_overrides = set(lib_overrides.keys()) & library_names
84+ library_names -= needs_overrides
85+ # ensure that overrides always "trump" the existing set if they
86+ # are found
87+ # XXX: we don't consider arch in overrides, do we need to?
88+ # -- james_w
89+ deps = set(lib_overrides[lib] for lib in needs_overrides)
90 with closing(get_dependency_database()) as db:
91- deps = set()
92- for lib in library_names:
93- # ensure that overrides always "trump" the existing set if they
94- # are found
95- # XXX: we don't consider arch in overrides, do we need to?
96- # -- james_w
97- if lib in lib_overrides:
98- new_deps = set([lib_overrides[lib]])
99- trace.log(
100- "found dependencies '%s' for lib '%s' via override" % (
101- new_deps, lib))
102- else:
103- new_deps = db.get_dependencies(lib, arch)
104- trace.log(
105- "found dependencies '%s' for lib '%s'" % (new_deps, lib))
106-
107- if not new_deps:
108- raise UnknownDependency('Can\'t find dependency for "%s".' % lib)
109- deps |= new_deps
110- return deps
111+ found = db.get_multiple_dependencies(library_names, arch)
112+ missing = library_names - set(found.keys())
113+ if missing:
114+ raise UnknownDependency(missing)
115+ for lib_deps in found.values():
116+ deps |= lib_deps
117+ return deps
118
119
120 def find_bundled_libraries(path, libraries):
121@@ -318,10 +324,7 @@
122 return libraries_to_path
123
124
125-def guess_embedded_libs_search_paths(
126- path,
127- library_finder=needed_libraries_from_objdump,
128- libraries_to_deps=get_packages_for_libraries):
129+def guess_embedded_libs_search_paths(path):
130 binaries = iter_binaries(path)
131 libraries, arch = get_shared_library_dependencies(binaries)
132 libraries_to_paths = find_bundled_libraries(path, libraries)
133@@ -353,17 +356,14 @@
134 return extra_targets
135
136
137-def guess_dependencies(
138- path,
139- library_finder=needed_libraries_from_objdump,
140- libraries_to_deps=get_packages_for_libraries):
141+def guess_dependencies(path):
142 binaries = iter_binaries(path)
143 libraries, arch = get_shared_library_dependencies(binaries)
144 # find/filter out the embedded libs
145 libraries_to_paths = find_bundled_libraries(path, libraries)
146 libraries = set(libraries) - set(libraries_to_paths.keys())
147 # go over the rest
148- deps = libraries_to_deps(libraries, arch)
149+ deps = get_packages_for_libraries(libraries, arch)
150 return deps, arch
151
152
153
154=== modified file 'devportalbinary/database.py'
155--- devportalbinary/database.py 2012-10-23 12:23:27 +0000
156+++ devportalbinary/database.py 2012-10-26 14:45:28 +0000
157@@ -19,6 +19,7 @@
158 )
159 from launchpadlib.launchpad import Launchpad
160 from pkgme.run_script import run_subprocess
161+from storm.expr import And, Column, Select, Table
162 from storm.locals import create_database, Store
163 from storm.uri import URI as StormURI
164
165@@ -442,12 +443,30 @@
166 def from_options(cls, options):
167 return cls(cls.get_store_from_config(options))
168
169- def get_dependencies(self, library_name, arch='i386'):
170- """Get the binary packages that provide 'library_name'."""
171- result = self._store.execute(
172- "SELECT dependency FROM libdep WHERE library = ? AND architecture = ?",
173- (unicode(library_name), unicode(arch)))
174- return set([dependency for [dependency] in result])
175+ def _get_query(self, library_names, arch):
176+ return Select(
177+ [Column('library'), Column('dependency')],
178+ And(Column('architecture') == arch,
179+ Column('library').is_in(map(unicode, library_names))),
180+ Table('libdep'))
181+
182+ def get_multiple_dependencies(self, library_names, arch):
183+ """Get the binary packages that provide libraries.
184+
185+ :return: (deps, missing), where ``deps`` is a dict mapping library
186+ names to sets of packages that provide them, and ``missing`` is a
187+ set of library names for which no dependencies could be found.
188+ """
189+ arch = unicode(arch)
190+ result = self._store.execute(self._get_query(library_names, arch))
191+ found = {}
192+ for row in result:
193+ [lib, dependency] = row
194+ if lib in found:
195+ found[lib].add(dependency)
196+ else:
197+ found[lib] = set([dependency])
198+ return found
199
200 def insert_new_library(self, package_name, library_name,
201 dependency, arch):
202@@ -499,9 +518,15 @@
203 def from_options(cls, options):
204 return cls(Client(options.database_base_url))
205
206- def get_dependencies(self, library_name, arch='i386'):
207- deps = self._client.get_binaries_for_libraries([library_name], [arch])
208- return set(deps[arch].get(library_name, []))
209+ def get_multiple_dependencies(self, library_names, arch):
210+ """Get the binary packages that provide libraries.
211+
212+ :return: (deps, missing), where ``deps`` is a dict mapping library
213+ names to sets of packages that provide them, and ``missing`` is a
214+ set of library names for which no dependencies could be found.
215+ """
216+ deps = self._client.get_binaries_for_libraries(library_names, [arch])
217+ return dict((lib, set(dep)) for (lib, dep) in deps[arch].items())
218
219 def close(self):
220 pass
221
222=== modified file 'devportalbinary/tests/test_aptfile.py'
223--- devportalbinary/tests/test_aptfile.py 2012-09-17 15:31:20 +0000
224+++ devportalbinary/tests/test_aptfile.py 2012-10-26 14:45:28 +0000
225@@ -27,7 +27,8 @@
226 def test_get_dependencies(self):
227 """ Test that data from the fixture dependencies file works """
228 self.assertEqual(
229- self.db.get_dependencies("libz.so.1"), set(["zlib1g"]))
230+ self.db.get_multiple_dependencies(["libz.so.1"], 'i386'),
231+ ({'libz.so.1': 'zlib1g'}, set()))
232
233 @patch("urllib.urlretrieve")
234 def test_lazy_downloading(self, mock_urlretrieve):
235@@ -43,8 +44,8 @@
236 db = AptFilePackageDatabase(tempdir.path)
237 mock_urlretrieve.side_effect = _put_fixture_contents_file_in_place
238 self.assertEqual(
239- db.get_dependencies("libfoo.so.2", arch="i386"),
240- set(["pkgfoo", "pkgbar"]))
241+ db.get_multiple_dependencies(["libfoo.so.2"], arch="i386"),
242+ ({'libfoo.so.2': set(["pkgfoo", "pkgbar"])}, set()))
243 self.assertEqual(len(db._get_lib_to_pkgs_mapping("oneiric", "i386")), 1)
244
245 def test_close(self):
246
247=== modified file 'devportalbinary/tests/test_binary.py'
248--- devportalbinary/tests/test_binary.py 2012-09-27 21:50:03 +0000
249+++ devportalbinary/tests/test_binary.py 2012-10-26 14:45:28 +0000
250@@ -378,7 +378,7 @@
251 with closing(PackageDatabase(self.db_fixture.conn)) as db:
252 db.update_package('foo', {'i386': {'libasound.so.2': 'libfoo'}})
253 self.assertEqual(
254- get_packages_for_libraries(["libasound.so.2"], "i386"),
255+ get_packages_for_libraries(set(["libasound.so.2"]), "i386"),
256 set(["libasound2"]))
257
258 def test_architecture(self):
259
260=== modified file 'devportalbinary/tests/test_database.py'
261--- devportalbinary/tests/test_database.py 2012-10-23 12:23:27 +0000
262+++ devportalbinary/tests/test_database.py 2012-10-26 14:45:28 +0000
263@@ -86,33 +86,33 @@
264 db = self.get_package_db()
265 db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
266 db.insert_new_library('foo-src', 'libfoo.so.0', 'bar', 'i386')
267- deps = db.get_dependencies('libfoo.so.0')
268- self.assertEqual(deps, set(['foo', 'bar']))
269+ deps = db.get_multiple_dependencies(['libfoo.so.0'], 'i386')
270+ self.assertEqual(deps, {'libfoo.so.0': set(['foo', 'bar'])})
271
272 def test_get_dependencies(self):
273 db = self.get_package_db()
274 db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
275- deps = db.get_dependencies('libfoo.so.0')
276- self.assertEqual(deps, set(['foo']))
277+ deps = db.get_multiple_dependencies(['libfoo.so.0'], 'i386')
278+ self.assertEqual(deps, {'libfoo.so.0': set(['foo'])})
279
280 def test_respects_architecture(self):
281 db = self.get_package_db()
282 db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
283 db.insert_new_library('foo-src', 'libfoo.so.0', 'foo-amd64', 'amd64')
284- deps = db.get_dependencies('libfoo.so.0', arch='amd64')
285- self.assertEqual(deps, set(['foo-amd64']))
286+ deps = db.get_multiple_dependencies(['libfoo.so.0'], arch='amd64')
287+ self.assertEqual(deps, {'libfoo.so.0': set(['foo-amd64'])})
288
289 def test_unknown_library(self):
290 db = self.get_package_db()
291- deps = db.get_dependencies('libfoo.so.0')
292- self.assertEqual(deps, set())
293+ deps = db.get_multiple_dependencies(['libfoo.so.0'], 'i386')
294+ self.assertEqual(deps, {})
295
296 def test_update_package(self):
297 db = self.get_package_db()
298 db.update_package(
299 'foo', {'i386': {'libfoo.so.1': 'foo-bin'}})
300- deps = db.get_dependencies('libfoo.so.1')
301- self.assertEqual(deps, set(['foo-bin']))
302+ deps = db.get_multiple_dependencies(['libfoo.so.1'], 'i386')
303+ self.assertEqual(deps, {'libfoo.so.1': set(['foo-bin'])})
304
305 def test_update_existing_package_no_libraries(self):
306 db = self.get_package_db()
307@@ -120,8 +120,8 @@
308 # Run again, this time with no symbols, representing that a newer
309 # version of the package no longer exports any libraries.
310 db.update_package('foo', {'i386': {}})
311- deps = db.get_dependencies('libfoo.so.1')
312- self.assertEqual(deps, set())
313+ deps = db.get_multiple_dependencies(['libfoo.so.1'], 'i386')
314+ self.assertEqual(deps, {})
315
316 def test_update_package_two_architectures(self):
317 # If two architectures are updated separately then they
318@@ -129,8 +129,8 @@
319 db = self.get_package_db()
320 db.update_package('foo', {'i386': {'libfoo.so.1': 'foo-bin'}})
321 db.update_package('foo', {'amd64': {'libfoo.so.1': 'foo-bin-amd64'}})
322- deps = db.get_dependencies('libfoo.so.1', arch='i386')
323- self.assertEqual(deps, set(['foo-bin']))
324+ deps = db.get_multiple_dependencies(['libfoo.so.1'], arch='i386')
325+ self.assertEqual(deps, {'libfoo.so.1': set(['foo-bin'])})
326
327 def test_close(self):
328 # Test that we can close the package db.
329@@ -459,8 +459,10 @@
330 client = Client(double.base_url)
331 wrapper = LibdepServiceClient(client)
332 self.assertEqual(
333- set(['libfoo-bin']), wrapper.get_dependencies('libfoo', 'i386'))
334- self.assertEqual(set(), wrapper.get_dependencies('libbar', 'i386'))
335+ {'libfoo': set(['libfoo-bin'])},
336+ wrapper.get_multiple_dependencies(['libfoo'], 'i386'))
337+ self.assertEqual(
338+ {}, wrapper.get_multiple_dependencies(['libbar'], 'i386'))
339
340 def test_has_close_method(self):
341 client = Client('http://localhost/')

Subscribers

People subscribed via source and target branches