Merge lp:~jml/pkgme-devportal/remove-database-code into lp:pkgme-devportal

Proposed by Jonathan Lange
Status: Merged
Merged at revision: 146
Proposed branch: lp:~jml/pkgme-devportal/remove-database-code
Merge into: lp:pkgme-devportal
Diff against target: 376 lines (+4/-300)
6 files modified
NEWS (+3/-0)
devportalbinary/aptfile.py (+0/-226)
devportalbinary/database.py (+1/-7)
devportalbinary/tests/test_aptfile.py (+0/-53)
devportalbinary/tests/test_database.py (+0/-12)
setup.py (+0/-2)
To merge this branch: bzr merge lp:~jml/pkgme-devportal/remove-database-code
Reviewer Review Type Date Requested Status
James Westby Approve
Review via email: mp+134099@code.launchpad.net

Commit message

Remove aptfile backend

Description of the change

Removes the apt-file backend, which we don't need any more.

To post a comment you must log in.
175. By Jonathan Lange

Merge versions.cfg change.

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-11-13 11:25:44 +0000
3+++ NEWS 2012-11-13 14:34:20 +0000
4@@ -12,6 +12,9 @@
5 maintain a database of library dependencies based on published packages
6 from Launchpad has been removed. (Jonathan Lange)
7
8+ * ``aptfile`` backend has been removed. (Jonathan Lange)
9+
10+
11 0.4.11 (2012-10-29)
12 ===================
13
14
15=== removed file 'devportalbinary/aptfile.py'
16--- devportalbinary/aptfile.py 2012-11-13 11:25:44 +0000
17+++ devportalbinary/aptfile.py 1970-01-01 00:00:00 +0000
18@@ -1,226 +0,0 @@
19-# Copyright 2012 Canonical Ltd. This software is licensed under the
20-# GNU Affero General Public License version 3 (see the file LICENSE).
21-
22-# XXX: Remove this. No longer used.
23-
24-__all__ = [
25- 'AptFilePackageDatabase',
26- ]
27-
28-import gzip
29-import urllib
30-import argparse
31-import os
32-import re
33-
34-
35-def make_arg_parser():
36- p = argparse.ArgumentParser()
37- p.add_argument('--cache-dir', type=str, default='cache')
38- p.add_argument('output_file', type=argparse.FileType('w'))
39- return p
40-
41-
42-so_filename_re = re.compile(r'\.so(\.[0-9]+)*$')
43-def export_database(db, stream):
44- for library, package, arch in db.iter_database():
45- if so_filename_re.search(library):
46- stream.write(','.join([package, library, package, arch]))
47- stream.write('\n')
48- stream.flush()
49-
50-
51-def dump_apt_file_db():
52- parser = make_arg_parser()
53- args = parser.parse_args()
54- if not os.path.isdir(args.cache_dir):
55- os.path.makedirs(args.cache_dir)
56- db = AptFilePackageDatabase(args.cache_dir)
57- export_database(db, args.output_file)
58- return 0
59-
60-
61-def iter_contents_file(contents):
62- """ Yield (full-library-path, set-of-pkgnames) from a Contents file.
63-
64- It expects a line starting with "FILE" that tells it when the header ends
65- and the actual content starts.
66- """
67- found_start_marker = False
68- for line in contents:
69- if not found_start_marker:
70- if line.startswith("FILE"):
71- found_start_marker = True
72- continue
73- (path, sep, pkgs) = [s.strip() for s in line.rpartition(" ")]
74- # pkgs is formated a bit funny, e.g. universe/pkgname
75- pkgs = set([os.path.basename(pkg) for pkg in pkgs.split(",")])
76- yield (path, pkgs)
77-
78-
79-class AptFilePackageDatabase(object):
80- """Really dumb database that just uses apt-file for local testing """
81-
82- # we could also read /etc/ld.so.conf.d/*.conf but this maybe different on
83- # different distroseries especially if
84- # server-distroseries != target-distroseries
85- # (I wish there was ldconfig --print-search-dirs)
86- LD_SEARCH_PATH = [
87- # standards
88- "lib",
89- "usr/lib",
90- "usr/local/lib",
91- # old biarch
92- "lib32",
93- "usr/lib32",
94- # new multiarch
95- "lib/i686-linux-gnu",
96- "lib/i386-linux-gnu",
97- "lib/x86_64-linux-gnu",
98- "usr/lib/i386-linux-gnu",
99- "usr/lib/i686-linux-gnu",
100- "usr/lib/x86_64-linux-gnu",
101- # ?
102- "usr/lib/x86_64-linux-gnu/fakechroot",
103- "usr/lib/x86_64-linux-gnu/mesa",
104- "usr/lib/x86_64-linux-gnu/mesa-egl",
105- "usr/lib/i386-linux-gnu/mesa",
106- ]
107-
108- DISTROSERIES = "oneiric"
109-
110- # If db_type is set to this in the config, that means use this database.
111- DB_TYPE = 'aptfile'
112-
113- CONTENTS_FILE_URL_LOCATION = (
114- "http://archive.ubuntu.com/ubuntu/dists/%(distroseries)s/"
115- "Contents-%(arch)s.gz")
116-
117- CONTENTS_FILE = "Contents-%(distroseries)s-%(arch)s"
118-
119- def __init__(self, cachedir):
120- self.cachedir = os.path.expanduser(cachedir)
121- self._distroseries_arch_cache = {}
122-
123- @classmethod
124- def from_options(cls, options):
125- return cls(options.database_aptfile_cachedir)
126-
127- def _get_lib_to_pkgs_mapping(self, distroseries, arch):
128- """Returns a dict of { library-name : set([pkg1,pkg2])
129-
130- This function will return a dict to lookup library-name to package
131- dependencies for the given distroseries and architecture
132- """
133- if not (distroseries, arch) in self._distroseries_arch_cache:
134- self._distroseries_arch_cache[(distroseries, arch)] = \
135- self._get_mapping_from_contents_file(distroseries, arch)
136- return self._distroseries_arch_cache[(distroseries, arch)]
137-
138- def _get_contents_file_cache_path(self, distroseries, arch):
139- """Return the path in the cache for the given distroseries, arch """
140- return os.path.join(
141- self.cachedir, self.CONTENTS_FILE % {
142- 'distroseries': distroseries, 'arch': arch})
143-
144- def _get_contents_file_server_url(self, distroseries, arch):
145- """Return the remote server URL for the given distroseries, arch """
146- return self.CONTENTS_FILE_URL_LOCATION % {
147- 'distroseries': distroseries, 'arch': arch}
148-
149- def _get_mapping_from_contents_file(self, distroseries, arch):
150- """Return lib,pkgs mapping from contents file for distroseries, arch
151-
152- This expects the contents file to be in the cachedir already.
153- """
154- lib_to_pkgs = {}
155- path = self._get_contents_file_cache_path(distroseries, arch)
156- with open(path) as f:
157- for path, pkgs in self._iter_contents_file(f):
158- basename = os.path.basename(path)
159- if not basename in lib_to_pkgs:
160- lib_to_pkgs[basename] = set()
161- lib_to_pkgs[basename] |= pkgs
162- return lib_to_pkgs
163-
164- def _download_contents_file_compressed(self, distroseries, arch):
165- """Downloads the content file for distroseries, arch into target """
166- # XXX: we may eventually want to merge the Contents files from
167- # the -updates repository too in addition to the main archive
168- url = self._get_contents_file_server_url(distroseries, arch)
169- target = self._get_contents_file_cache_path(distroseries, arch)
170- compressed_target = target + os.path.splitext(url)[1]
171- # download
172- urllib.urlretrieve(url, compressed_target)
173- return compressed_target
174-
175- def _iter_contents_file(self, in_file):
176- for path, pkgs in iter_contents_file(in_file):
177- if os.path.dirname(path) in self.LD_SEARCH_PATH:
178- yield path, pkgs
179-
180- def _prune_contents_gz_file(self, infile, outfile):
181- """Read a compressed Contents.gz and write out a pruned version.
182-
183- This will use iter_contents_file to go over infile and write
184- the relevant lines that are in the LD_SEARCH_PATH to outfile.
185- """
186- with open(outfile, "w") as outf, gzip.open(infile) as inf:
187- # first write the header
188- outf.write("FILE LOCATION\n")
189- # then iter over all relevant lines and write them out
190- for path, pkgs in self._iter_contents_file(inf):
191- outf.write("%s %s\n" % (path, ",".join(pkgs)))
192-
193- def _download_and_prepare_contents_file_if_needed(self, distroseries, arch):
194- """Ensure there is a usable Contents file in the cachedir
195-
196- This will download, uncompress and prune a Conents file for
197- distroseries, arch so that get_dependencies works.
198- """
199- # mvo: We can (and should eventually) do etag/if-modified-since
200- # matching here. But its not really important as long as
201- # we package for stable distroseries as the Contents file
202- # will not change
203- path = self._get_contents_file_cache_path(distroseries, arch)
204- if not os.path.exists(path):
205- compressed_contents = self._download_contents_file_compressed(
206- distroseries, arch)
207- # and prune from ~300mb to 1mb uncompressed as we are only
208- # interested in the library path parts
209- self._prune_contents_gz_file(compressed_contents, path)
210- os.remove(compressed_contents)
211-
212- def iter_database(self, architectures=('i386', 'amd64'),
213- distroseries=None):
214- """Export the database.
215-
216- Yields (library, package, arch) tuples for everything that we can
217- find.
218- """
219- # XXX: Untested
220- if distroseries is None:
221- distroseries = self.DISTROSERIES
222- for arch in architectures:
223- self._download_and_prepare_contents_file_if_needed(
224- distroseries, arch)
225- mapping = self._get_lib_to_pkgs_mapping(distroseries, arch)
226- for library in mapping:
227- for package in mapping[library]:
228- yield library, package, arch
229-
230- def get_multiple_dependencies(self, library_names, arch):
231- """Get the binary packages that provide libraries.
232-
233- :return: (deps, missing), where ``deps`` is a dict mapping library
234- names to sets of packages that provide them, and ``missing`` is a
235- set of library names for which no dependencies could be found.
236- """
237- self._download_and_prepare_contents_file_if_needed(
238- self.DISTROSERIES, arch)
239- lib_to_pkgs = self._get_lib_to_pkgs_mapping(self.DISTROSERIES, arch)
240- deps = ((lib, lib_to_pkgs.get(lib)) for lib in library_names)
241- return dict((lib, dep) for (lib, dep) in deps if dep)
242-
243- def close(self):
244- pass
245
246=== modified file 'devportalbinary/database.py'
247--- devportalbinary/database.py 2012-11-13 11:28:53 +0000
248+++ devportalbinary/database.py 2012-11-13 14:34:20 +0000
249@@ -5,7 +5,6 @@
250 from storm.locals import create_database, Store
251 from storm.uri import URI as StormURI
252
253-from .aptfile import AptFilePackageDatabase
254 from .configuration import (
255 CONF_FILE_ENV_VAR,
256 get_config_file_path,
257@@ -159,10 +158,5 @@
258
259 def get_dependency_database():
260 """Return an object that can get dependencies."""
261- # XXX: Remove AptFilePackageDatabase from here and simplify the method.
262- databases = {
263- AptFilePackageDatabase.DB_TYPE: AptFilePackageDatabase.from_options,
264- LibdepServiceClient.DB_TYPE: LibdepServiceClient.from_options,
265- }
266 options = load_configuration()
267- return databases[options.database_db_type](options)
268+ return LibdepServiceClient.from_options(options)
269
270=== removed file 'devportalbinary/tests/test_aptfile.py'
271--- devportalbinary/tests/test_aptfile.py 2012-10-26 12:21:03 +0000
272+++ devportalbinary/tests/test_aptfile.py 1970-01-01 00:00:00 +0000
273@@ -1,53 +0,0 @@
274-import gzip
275-import os
276-
277-from mock import patch
278-from fixtures import TempDir
279-from testtools import TestCase
280-
281-from ..aptfile import AptFilePackageDatabase
282-
283-
284-class AptFilePackageDatabaseTestCase(TestCase):
285-
286- # point to our local contents file version that is a tad smaller
287- CONTENTS_CACHE = os.path.join(
288- os.path.dirname(__file__), "data", "apt-file-backend")
289-
290- def setUp(self):
291- super(AptFilePackageDatabaseTestCase, self).setUp()
292- self.db = AptFilePackageDatabase(self.CONTENTS_CACHE)
293-
294- def test_read_fixture_contents_worked(self):
295- """ test that our fixture Contents file works as expected """
296- # our test DB has 4 entries in the default search path
297- self.assertEqual(
298- len(self.db._get_lib_to_pkgs_mapping("oneiric", "i386")), 4)
299-
300- def test_get_dependencies(self):
301- """ Test that data from the fixture dependencies file works """
302- self.assertEqual(
303- self.db.get_multiple_dependencies(["libz.so.1"], 'i386'),
304- ({'libz.so.1': 'zlib1g'}, set()))
305-
306- @patch("urllib.urlretrieve")
307- def test_lazy_downloading(self, mock_urlretrieve):
308- """ test that lazy downloading works """
309- def _put_fixture_contents_file_in_place(url, target):
310- with gzip.open(target, "w") as f:
311- f.write("""
312-Some header text that is ignored
313-FILE LOCATION
314-usr/lib/libfoo.so.2 pkgfoo,pkgbar
315-""")
316- tempdir = self.useFixture(TempDir())
317- db = AptFilePackageDatabase(tempdir.path)
318- mock_urlretrieve.side_effect = _put_fixture_contents_file_in_place
319- self.assertEqual(
320- db.get_multiple_dependencies(["libfoo.so.2"], arch="i386"),
321- ({'libfoo.so.2': set(["pkgfoo", "pkgbar"])}, set()))
322- self.assertEqual(len(db._get_lib_to_pkgs_mapping("oneiric", "i386")), 1)
323-
324- def test_close(self):
325- # Test that there is a close method we can call
326- self.db.close()
327
328=== modified file 'devportalbinary/tests/test_database.py'
329--- devportalbinary/tests/test_database.py 2012-11-13 11:22:16 +0000
330+++ devportalbinary/tests/test_database.py 2012-11-13 14:34:20 +0000
331@@ -9,7 +9,6 @@
332 )
333
334 from devportalbinary.database import (
335- AptFilePackageDatabase,
336 get_dependency_database,
337 LibdepServiceClient,
338 load_configuration,
339@@ -78,17 +77,6 @@
340 self.assertRaises(ValueError, PackageDatabase.get_db_info_from_config,
341 options)
342
343- def test_default_create_no_config(self):
344- nonexistent = self.getUniqueString()
345- self.useFixture(ConfigFileFixture(nonexistent))
346- self.assertIsInstance(
347- get_dependency_database(), AptFilePackageDatabase)
348-
349- def test_default_create_empty_config(self):
350- self.useFixture(ConfigSettings())
351- self.assertIsInstance(
352- get_dependency_database(), AptFilePackageDatabase)
353-
354 def test_remote_service(self):
355 base_url = 'http://example.com/libdep-service/'
356 self.use_database_config(db_type='libdep-service', base_url=base_url)
357
358=== modified file 'setup.py'
359--- setup.py 2012-11-13 09:14:39 +0000
360+++ setup.py 2012-11-13 14:34:20 +0000
361@@ -36,7 +36,6 @@
362 install_requires = [
363 'bzr',
364 'configglue',
365- 'launchpadlib',
366 'libdep-service-python>=0.0.5',
367 'PIL',
368 'pkgme>=0.4.1',
369@@ -45,7 +44,6 @@
370 ],
371 entry_points = {
372 'console_scripts': [
373- 'dump-apt-file-db=devportalbinary.aptfile:dump_apt_file_db',
374 'guess-executable=devportalbinary.binary:print_executable',
375 'guess-deps=devportalbinary.binary:print_dependencies',
376 ],

Subscribers

People subscribed via source and target branches