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

Proposed by Jonathan Lange
Status: Merged
Approved by: James Westby
Approved revision: 170
Merged at revision: 144
Proposed branch: lp:~jml/pkgme-devportal/remove-database-code
Merge into: lp:pkgme-devportal
Diff against target: 1182 lines (+69/-825)
10 files modified
NEWS (+10/-0)
bin/fetch-symbol-files (+0/-26)
devportalbinary/acceptance/tests/__init__.py (+10/-9)
devportalbinary/aptfile.py (+2/-0)
devportalbinary/database.py (+5/-427)
devportalbinary/testing.py (+30/-1)
devportalbinary/tests/test_binary.py (+9/-26)
devportalbinary/tests/test_database.py (+2/-335)
devportalbinary/utils.py (+1/-0)
setup.py (+0/-1)
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+134083@code.launchpad.net

Commit message

Remove fetch-symbol-files and all of the code it uses

Description of the change

This is the first branch of many.

It removes fetch-symbol-files and all of the code that it calls that
is not used by others.

Other things that are now probably safe to remove are marked up with
XXX comments, and should be deleted in future branches.

I have tried to be careful and remove absolutely everything.

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-29 16:31:07 +0000
3+++ NEWS 2012-11-13 12:03:23 +0000
4@@ -2,6 +2,16 @@
5 NEWS for pkgme-devportal
6 ========================
7
8+NEXT
9+====
10+
11+Changes
12+-------
13+
14+ * ``fetch-symbol-files`` and everything needed to parse symbol files and
15+ maintain a database of library dependencies based on published packages
16+ from Launchpad has been removed. (Jonathan Lange)
17+
18 0.4.11 (2012-10-29)
19 ===================
20
21
22=== removed file 'bin/fetch-symbol-files'
23--- bin/fetch-symbol-files 2012-08-30 12:35:31 +0000
24+++ bin/fetch-symbol-files 1970-01-01 00:00:00 +0000
25@@ -1,26 +0,0 @@
26-#!/usr/bin/python2.7 -S
27-
28-import os
29-
30-join = os.path.join
31-base = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
32-base = os.path.dirname(base)
33-
34-import sys
35-sys.path[0:0] = [
36- join(base, 'parts/scripts'),
37- ]
38-
39-
40-import os
41-path = sys.path[0]
42-if os.environ.get('PYTHONPATH'):
43- os.environ['BUILDOUT_ORIGINAL_PYTHONPATH'] = os.environ['PYTHONPATH']
44- path = os.pathsep.join([path, os.environ['PYTHONPATH']])
45-os.environ['PYTHONPATH'] = path
46-import site # imports custom buildout-generated site.py
47-
48-import devportalbinary.database
49-
50-if __name__ == '__main__':
51- devportalbinary.database.main()
52
53=== modified file 'devportalbinary/acceptance/tests/__init__.py'
54--- devportalbinary/acceptance/tests/__init__.py 2012-09-17 16:20:42 +0000
55+++ devportalbinary/acceptance/tests/__init__.py 2012-11-13 12:03:23 +0000
56@@ -15,7 +15,10 @@
57 from pkgme.debuild import build_source_package
58 from pkgme.run_script import ScriptUserError
59
60-from devportalbinary.testing import DatabaseFixture, IsImage
61+from devportalbinary.testing import (
62+ IsImage,
63+ LibdepFixture,
64+ )
65
66
67 class TestData(Fixture):
68@@ -76,20 +79,18 @@
69
70 def test_gtk(self):
71 """Runs successfully for a basic GTK+ application."""
72- dep_db = self.useFixture(DatabaseFixture())
73- dep_db.db.update_package("pthreads",
74- {'i386': {"libpthread.so.0": "libpthread0"}})
75- dep_db.db.update_package("eglibc",
76- {'i386': {"libc.so.6": "libc6"}})
77+ self.useFixture(
78+ LibdepFixture(
79+ [("libpthread0", {'i386': {"libpthread.so.0": "libpthread0"}}),
80+ ("libc6", {'i386': {"libc.so.6": "libc6"}})]))
81 test_data = self.useFixture(TestData("gtk"))
82 run_pkgme(test_data)
83 self.assertThat(test_data.path, HasFileTree({'debian/control': {}}))
84
85 def test_bundled_library(self):
86 """Runs successfully for a basic bundled libary."""
87- dep_db = self.useFixture(DatabaseFixture())
88- dep_db.db.update_package("eglibc",
89- {'i386': {"libc.so.6": "libc6"}})
90+ self.useFixture(
91+ LibdepFixture([("libc6", {'i386': {"libc.so.6": "libc6"}})]))
92 test_data = self.useFixture(TestData("bundled_lib"))
93 run_pkgme(test_data)
94 self.assertThat(
95
96=== modified file 'devportalbinary/aptfile.py'
97--- devportalbinary/aptfile.py 2012-10-26 14:38:49 +0000
98+++ devportalbinary/aptfile.py 2012-11-13 12:03:23 +0000
99@@ -1,6 +1,8 @@
100 # Copyright 2012 Canonical Ltd. This software is licensed under the
101 # GNU Affero General Public License version 3 (see the file LICENSE).
102
103+# XXX: Remove this. No longer used.
104+
105 __all__ = [
106 'AptFilePackageDatabase',
107 ]
108
109=== modified file 'devportalbinary/database.py'
110--- devportalbinary/database.py 2012-10-26 14:38:49 +0000
111+++ devportalbinary/database.py 2012-11-13 12:03:23 +0000
112@@ -1,24 +1,6 @@
113 # Copyright 2011 Canonical Ltd. This software is licensed under the
114 # GNU Affero General Public License version 3 (see the file LICENSE).
115
116-from contextlib import closing, contextmanager
117-import errno
118-from itertools import chain
119-import os
120-import shutil
121-import tempfile
122-
123-from bzrlib import urlutils
124-from fixtures import (
125- Fixture,
126- TempDir,
127- )
128-
129-from launchpadlib import (
130- uris,
131- )
132-from launchpadlib.launchpad import Launchpad
133-from pkgme.run_script import run_subprocess
134 from storm.expr import And, Column, Select, Table
135 from storm.locals import create_database, Store
136 from storm.uri import URI as StormURI
137@@ -28,338 +10,11 @@
138 CONF_FILE_ENV_VAR,
139 get_config_file_path,
140 load_configuration,
141- load_configuration_with_command_line,
142 )
143-from .utils import download_file
144
145 from libdep_service_client.client import Client
146
147
148-# XXX: Historic name of this package. Update to 'pkgme-devportal' and
149-# re-authorize.
150-APPLICATION_NAME = 'pkgme-binary'
151-SERVICE_ROOT = uris.LPNET_SERVICE_ROOT
152-
153-SHLIBS_FILENAME = 'shlibs'
154-SYMBOLS_FILENAME = 'symbols'
155-
156-
157-# A list of package names that don't match lib*, but which we want
158-# to scan anyway.
159-PACKAGE_NAME_WHITELIST = [
160- "e2fslibs",
161- "odbcinst1debian2",
162- "python2.7-dbg",
163- "uno-libs3",
164- "zlib1g",
165- ]
166-
167-
168-def is_library_package(url):
169- """Is ``url`` likely to contain libraries?"""
170- filename = os.path.splitext(urlutils.basename(url))[0]
171- if filename.startswith('lib'):
172- return True
173- for prefix in PACKAGE_NAME_WHITELIST:
174- if filename.startswith(prefix):
175- return True
176- return False
177-
178-
179-class LaunchpadFixture(Fixture):
180-
181- def __init__(self, application_name, service_root):
182- super(LaunchpadFixture, self).__init__()
183- self._app_name = application_name
184- self._service_root = service_root
185-
186- def setUp(self):
187- super(LaunchpadFixture, self).setUp()
188- tempdir = self.useFixture(TempDir())
189- self.anonymous = Launchpad.login_anonymously(
190- self._app_name, self._service_root, tempdir.path)
191-
192-
193-def iter_published_binaries(lp, since=None, name=None, exact_match=True):
194- architectures = load_configuration().architectures_supported
195- ubuntu = lp.distributions['ubuntu']
196- archive = ubuntu.main_archive
197- # XXX: oneiric is a puppy that is just for christmas. Specifically, it's a
198- # bug that this is looking in oneiric, should instead be looking in
199- # ... well, we don't know.
200- oneiric = ubuntu.getSeries(name_or_version='oneiric')
201- our_series = (
202- oneiric.getDistroArchSeries(archtag=tag) for tag in architectures)
203- filters = dict(status='Published')
204- if since:
205- filters['created_since_date'] = since
206- if name:
207- filters['binary_name'] = name
208- filters['exact_match'] = exact_match
209- return chain(
210- *[archive.getPublishedBinaries(distro_arch_series=series, **filters)
211- for series in our_series])
212-
213-
214-def possible_sonames_for_shared_object(libname, version):
215- """Return the possible sonames gives info about a shared object.
216-
217- :return: a set of candidate sonames (as strings).
218- """
219- candidates = set(['{0}-{1}.so'.format(libname, version)])
220- if '.' not in version:
221- candidates.add('{0}.so.{1}'.format(libname, version))
222- return candidates
223-
224-
225-def find_file_under_dir(filename, directory):
226- """Find `filename` under `directory`.
227-
228- :return: the path of the first matching file, or None if the file
229- wasn't found.
230- """
231- for dirpath, dirnames, filenames in os.walk(directory):
232- if filename in filenames:
233- return os.path.join(dirpath, filename)
234-
235-
236-class NoSharedObject(Exception):
237-
238- def __init__(self, libname, version, candidates):
239- super(NoSharedObject, self).__init__(
240- "No shared object matching {0} {1} could be found, "
241- "looked for {2}".format(libname, version, candidates))
242-
243-
244-class TooManySharedObjects(Exception):
245-
246- def __init__(self, libname, version, candidates):
247- super(TooManySharedObjects, self).__init__(
248- "Too many objects matching {0} {1} could be found, "
249- "found {2}".format(libname, version, candidates))
250-
251-
252-
253-def shared_object_info_to_soname(libname, version, directory):
254- """Resolve a (libname, version) tuple to a soname.
255-
256- Using the files from a package decide on the soname that
257- the shared object info refers to. E.g. if the info is ("libfoo", "1")
258- and there is a file named "libfoo.so.1" then that is the soname.
259-
260- :param directory: a directory of files to use to resolve.
261- :return: the soname as a string
262- :raises NoSharedObject: if a file corresponding to the info can't be
263- found.
264- :raises TooManySharedObjects: if multiple files matching the shared object
265- info in different ways are found (mutliple files matching in
266- the same manner are ignored.)
267- """
268- candidates = possible_sonames_for_shared_object(libname, version)
269- files = {soname: find_file_under_dir(soname, directory) for soname in candidates}
270- found_files = dict(filter(lambda (x, y): y is not None, files.items()))
271- if len(found_files) < 1:
272- raise NoSharedObject(libname, version, candidates)
273- elif len(found_files) > 1:
274- raise TooManySharedObjects(libname, version, found_files.values())
275- return found_files.keys()[0]
276-
277-
278-
279-def libdep_mapping_for_deb(deb_file):
280- """Returns the library -> dependency mapping information from a package.
281-
282- The symbols file will be read in preference to the shlibs file.
283- If neither is present an empty dict will be returned indicating
284- that there are no libraries.
285-
286- If there are libraries the dict will map from the library names
287- to the package dependencies that should be used to get the
288- library, e.g.
289-
290- {'libfoo.so.1': 'libfoo1', ...}
291- """
292- with extract_deb_control(deb_file) as control_dir:
293- # Try symbols
294- symbols_path = os.path.join(control_dir, SYMBOLS_FILENAME)
295- symbols = get_file_contents(symbols_path)
296- if symbols is not None:
297- return libdep_mapping_from_symbols(symbols)
298-
299- # Try shlibs
300- shlibs_path = os.path.join(control_dir, SHLIBS_FILENAME)
301- shlibs = get_file_contents(shlibs_path)
302- if shlibs is not None:
303- shared_object_mapping = shared_objects_from_shlibs(shlibs)
304- if shared_object_mapping:
305- with extract_deb_content(deb_file) as deb_content:
306- def resolve_shared_objects(map_entry):
307- (libname, version), dependency = map_entry
308- soname = shared_object_info_to_soname(libname, version,
309- deb_content)
310- return soname, dependency
311- return dict(
312- map(resolve_shared_objects,
313- shared_object_mapping.items())
314- )
315- return {}
316-
317-
318-def deb_file_url_for_publication(bpph):
319- """Get the download URL for a binary package."""
320- version = bpph.binary_package_version
321- if ':' in version:
322- version = version[version.index(':')+1:]
323- arch = bpph.distro_arch_series.architecture_tag
324- if not bpph.architecture_specific:
325- arch = 'all'
326- return '%s/+files/%s_%s_%s.deb' % (
327- bpph.archive.web_link,
328- bpph.binary_package_name,
329- version,
330- arch,
331- )
332-
333-
334-def get_package_info_from_publication(bpph):
335- arch = bpph.distro_arch_series.architecture_tag
336- url = deb_file_url_for_publication(bpph)
337- return url, arch
338-
339-
340-def get_libdep_mapping_for_package(url):
341- """Return the library -> dependency mapping for the package at url.
342-
343- :return: a dict mapping library names to dependencies, e.g.
344- {'libfoo.so.1': 'libfoo1', ...}
345- """
346- directory = tempfile.mkdtemp()
347- try:
348- deb_file = download_file(url, directory)
349- return libdep_mapping_for_deb(deb_file)
350- finally:
351- shutil.rmtree(directory)
352-
353-
354-@contextmanager
355-def extract_deb_control(binary_package_path):
356- """Extract a deb control archive, returning the extracted path.
357-
358- This is a context manager, and the tempdir will be cleaned up when closed.
359- """
360- temp_dir = tempfile.mkdtemp()
361- try:
362- run_subprocess(['dpkg-deb', '-e', binary_package_path, temp_dir])
363- yield temp_dir
364- finally:
365- shutil.rmtree(temp_dir)
366-
367-
368-@contextmanager
369-def extract_deb_content(binary_package_path):
370- """Extract the files from a .deb package to a tempdir.
371-
372- This is a context manager, the path to the tempdir will be yielded
373- to the caller, and the tempdir will be cleaned up when closed.
374- """
375- temp_dir = tempfile.mkdtemp()
376- try:
377- run_subprocess(['dpkg-deb', '-x', binary_package_path, temp_dir])
378- yield temp_dir
379- finally:
380- shutil.rmtree(temp_dir)
381-
382-
383-def get_file_contents(path):
384- """Read the contents of the file at `path`.
385-
386- :return: the contents of the file, or None if there was
387- no such file.
388- :raises: Any errors opening or reading the file.
389- """
390- try:
391- return open(path).read()
392- except (OSError, IOError), e:
393- if e.errno == errno.ENOENT:
394- return
395- raise
396-
397-
398-def libdep_mapping_from_symbols(symbol_contents):
399- """Returns a dict mapping libraries to dependencies based on the symbols
400-
401- Ignores versions and a whole bunch of other stuff and is probably the
402- wrong API even.
403- """
404-
405- # XXX: This is going to yield sonames and package names for now. Really,
406- # there should be something parsing the symbols file and another thing to
407- # somehow turn those into dependencies with versions.
408-
409- # Doesn't know how to handle lines like this:
410- #
411- # libformw.so.5 #PACKAGE#.
412- #
413- # This is OK, as we're only processing symbols files from binary packages
414- # rather than source packages.
415-
416- mapping = {}
417- for line in symbol_contents.splitlines():
418- if not line:
419- # Blank lines are skipped
420- continue
421- if line.startswith('|'):
422- # Alternative dependency template
423- # e.g. | libgl1-mesa-glx #MINVER#
424- continue
425- if line.startswith('*'):
426- # Meta-information
427- # e.g. * Build-Depends-Package: libgl1-mesa-dev
428- continue
429- if line.startswith(' '):
430- # Symbol
431- # e.g. gdk_add_client_message_filter@Base 2.8.0
432- continue
433- if line.startswith('#'):
434- # Lines starting with '#' are comments. There are also DEPRECATED
435- # and MISSING, and jml doesn't really know what they mean
436- continue
437- library, dependency = tuple(line.split()[:2])
438- if '#include' in library:
439- # To skip lines that are includes. XXX: Properly ought to process
440- # the tags that might appear before the include
441- # line.
442- #
443- # e.g. (arch=!armel)#include "libdiagnostics0.symbols.backtrace"
444- continue
445- mapping[library] = dependency
446- return mapping
447-
448-
449-def shared_objects_from_shlibs(shlibs_contents):
450- """Get the shared object info from the shlibs file.
451-
452- http://www.debian.org/doc/debian-policy/ch-sharedlibs.html#s-sharedlibs-shlibdeps
453- defines the format.
454-
455- :return: a dict mapping (libname, soname) to dependencies.
456- """
457- mapping = {}
458- for line in shlibs_contents.splitlines():
459- line = line.strip()
460- if not line:
461- continue
462- if line.startswith("#"):
463- continue
464- libname, soname, dependency = line.split(' ', 2)
465- if libname.endswith(':'):
466- # This is a 'type' marker, currently only udeb is used, and
467- # we don't want those
468- continue
469- mapping[(libname, soname)] = dependency
470- return mapping
471-
472-
473 class URI(StormURI):
474 """A stand-in for Storm's URI class.
475
476@@ -369,6 +24,8 @@
477 have a parsed version and just need to create the object.
478 """
479
480+ # XXX: Only used by PackageDatabase, which is flagged for deletion.
481+
482 def __init__(self, scheme=None, host=None, port=None, username=None,
483 password=None, database=None, options=None):
484 self.scheme = scheme
485@@ -384,6 +41,8 @@
486
487 class PackageDatabase(object):
488
489+ # XXX: No longer used within pkgme-devportal
490+
491 SQLITE = 'sqlite'
492 POSTGRES = 'postgres'
493
494@@ -468,40 +127,6 @@
495 found[lib] = set([dependency])
496 return found
497
498- def insert_new_library(self, package_name, library_name,
499- dependency, arch):
500- """Insert a library and its needed dependency into the database.
501-
502- :param library_name: A full soname, e.g. libfoo.so.1.
503- :param dependency: A binary package dependency, possibly including
504- version.
505- """
506- self._store.execute(
507- "INSERT INTO libdep VALUES (?, ?, ?, ?)",
508- (unicode(package_name),
509- unicode(library_name),
510- unicode(dependency),
511- unicode(arch)))
512-
513- def update_package(self, package_name, arch_libdep_mapping):
514- """Update the database with the libdep info from 'package_name'.
515-
516- :param package_name: The name of the package where the
517- symbols came from.
518- :param arch_libdep_mapping: a dict mapping architecture tags to dicts
519- mapping library names to dependencies, e.g.
520- {'amd64': {'libfoo.so.1': 'libfoo1', ...}, ...}
521- """
522- for arch, libdep_mapping in arch_libdep_mapping.items():
523- self._store.execute(
524- "DELETE FROM libdep WHERE source_package_name = ? "
525- "AND architecture = ?",
526- (unicode(package_name), unicode(arch)))
527- for library, dependency in libdep_mapping.items():
528- self.insert_new_library(
529- package_name, library, dependency, arch)
530- self._store.commit()
531-
532 def close(self):
533 self._store.close()
534
535@@ -534,57 +159,10 @@
536
537 def get_dependency_database():
538 """Return an object that can get dependencies."""
539- # TODO: Change this to return LibdepServiceClient sometimes
540+ # XXX: Remove AptFilePackageDatabase from here and simplify the method.
541 databases = {
542 AptFilePackageDatabase.DB_TYPE: AptFilePackageDatabase.from_options,
543- PackageDatabase.POSTGRES: PackageDatabase.from_options,
544- PackageDatabase.SQLITE: PackageDatabase.from_options,
545 LibdepServiceClient.DB_TYPE: LibdepServiceClient.from_options,
546 }
547 options = load_configuration()
548 return databases[options.database_db_type](options)
549-
550-
551-def dict_add(*dicts):
552- """Add dicts, with later dicts taking precedence."""
553- result = dict()
554- for d in dicts:
555- result.update(d)
556- return result
557-
558-
559-def publishings_to_package_info(publishings):
560- """Takes a list of publishings and returns the info for the library packages.
561-
562- :param publishings: an iterable of launchpadlib
563- binary_package_publishing_history objects.
564- :return: an iterable of (.deb url, arch tag) for the publishings
565- that represent a library package.
566- """
567- packages_info = map(get_package_info_from_publication, publishings)
568- return filter(
569- lambda (url, arch): is_library_package(url),
570- packages_info)
571-
572-
573-def fetch_symbol_files(scan_mode, package_name, db):
574- """Insert the libdep info for ``package_name`` into ``db``."""
575- if scan_mode != 'binary':
576- raise AssertionError("Unsupported scan mode: {0}".format(scan_mode))
577- with LaunchpadFixture(APPLICATION_NAME, SERVICE_ROOT) as lp:
578- publishings = iter_published_binaries(lp.anonymous, name=package_name)
579- lib_packages_info = publishings_to_package_info(publishings)
580- def arch_libdep_for_package((url, arch)):
581- return {arch: get_libdep_mapping_for_package(url)}
582- arch_libdep_mapping = dict_add(
583- *map(arch_libdep_for_package, lib_packages_info))
584- db.update_package(package_name, arch_libdep_mapping)
585-
586-
587-def main():
588- """Import the symbol files for 'package_name'."""
589- glue = load_configuration_with_command_line()
590- with closing(PackageDatabase.get_store_from_config(glue.options)) as store:
591- package_name = glue.args[0]
592- db = PackageDatabase(store)
593- fetch_symbol_files(glue.options.scan_mode, package_name, db)
594
595=== modified file 'devportalbinary/testing.py'
596--- devportalbinary/testing.py 2012-09-12 08:45:38 +0000
597+++ devportalbinary/testing.py 2012-11-13 12:03:23 +0000
598@@ -33,10 +33,17 @@
599 )
600
601 from devportalbinary.binary import MetadataBackend
602-from devportalbinary.database import PackageDatabase, URI
603+from devportalbinary.database import (
604+ LibdepServiceClient,
605+ PackageDatabase,
606+ URI,
607+ )
608
609 from devportalbinary.configuration import CONF_FILE_ENV_VAR
610
611+from djlibdep.test_double import LibdepServiceDouble
612+from libdep_service_client.client import Client
613+
614
615 class IsChildPath(Matcher):
616
617@@ -235,6 +242,23 @@
618 self.useFixture(ConfigFileFixture(config_file_path))
619
620
621+class LibdepFixture(Fixture):
622+
623+ def __init__(self, data):
624+ super(LibdepFixture, self).__init__()
625+ self._data = data
626+
627+ def setUp(self):
628+ super(LibdepFixture, self).setUp()
629+ double = self.useFixture(LibdepServiceDouble(self._data))
630+ self.useFixture(
631+ ConfigSettings(
632+ ('database', {'db_type': 'libdep-service',
633+ 'base_url': double.base_url,
634+ })))
635+ self.client = LibdepServiceClient(Client(double.base_url))
636+
637+
638 def LibsConfigSettings(test_libs):
639 """Create a lib_overrides config file."""
640 return ConfigSettings(
641@@ -355,3 +379,8 @@
642 for section, values in settings:
643 f.write(make_config_section(section, values))
644 f.write('\n')
645+
646+
647+def get_libdep_service_client(fixture, test_data):
648+ double = fixture.useFixture(LibdepServiceDouble(test_data))
649+ return LibdepServiceClient(Client(double.base_url))
650
651=== modified file 'devportalbinary/tests/test_binary.py'
652--- devportalbinary/tests/test_binary.py 2012-10-26 11:47:52 +0000
653+++ devportalbinary/tests/test_binary.py 2012-11-13 12:03:23 +0000
654@@ -1,12 +1,10 @@
655 # Copyright 2011-2012 Canonical Ltd. This software is licensed under the
656 # GNU Affero General Public License version 3 (see the file LICENSE).
657
658-from contextlib import closing
659 import os
660 import shutil
661
662 from fixtures import TempDir
663-from testresources import ResourcedTestCase
664 from testtools import TestCase
665 from testtools.matchers import (
666 SameMembers,
667@@ -39,19 +37,17 @@
668 UnknownDependency,
669 )
670 from devportalbinary.configuration import load_configuration
671-from devportalbinary.database import PackageDatabase
672 from devportalbinary.metadata import (
673 MetadataBackend,
674 )
675 from devportalbinary.testing import (
676 BackendTests,
677 BinaryFileFixture,
678- DatabaseConfig,
679 get_test_data_dir_path,
680 get_test_data_file_path,
681+ LibdepFixture,
682 LibsConfigSettings,
683 MetadataFixture,
684- postgres_db_resource,
685 )
686
687
688@@ -258,21 +254,16 @@
689 { "libfoo.so.1" : ["."], "libbar.so.2" : ["."]}, found)
690
691
692-class GuessDependenciesTests(TestCase, ResourcedTestCase):
693-
694- resources = [
695- ('db_fixture', postgres_db_resource),
696- ]
697+class GuessDependenciesTests(TestCase):
698
699 def test_guess_dependencies(self):
700- self.useFixture(DatabaseConfig(self.db_fixture))
701- with closing(PackageDatabase(self.db_fixture.conn)) as db:
702- db.update_package('eglibc', {'i386': {'libc.so.6': 'libc6'}})
703+ self.useFixture(
704+ LibdepFixture([('libc6', {'i386': {'libc.so.6': 'libc6'}})]))
705 deps, arch = guess_dependencies(get_test_data_dir_path('hello'))
706 self.assertEqual(set(['libc6']), deps)
707
708 def test_guess_dependencies_error_on_unknown_dependency(self):
709- self.useFixture(DatabaseConfig(self.db_fixture))
710+ self.useFixture(LibdepFixture([]))
711 e = self.assertRaises(UnknownDependency,
712 guess_dependencies, get_test_data_dir_path('hello'))
713 self.assertEqual('Can\'t find dependency for "libc.so.6".', str(e))
714@@ -286,17 +277,15 @@
715 self.assertEqual(set(["."]), paths)
716
717
718-class BinaryBackendTests(BackendTests, ResourcedTestCase):
719+class BinaryBackendTests(BackendTests):
720
721 BACKEND = BinaryBackend
722
723- resources = [
724- ('db_fixture', postgres_db_resource),
725- ]
726-
727 def setUp(self):
728 super(BinaryBackendTests, self).setUp()
729- self.useFixture(DatabaseConfig(self.db_fixture))
730+ self.useFixture(
731+ LibdepFixture([('libc6', {'i386': {'libc.so.6': 'libc6'}}),
732+ ('libfoo', {'i386': {'libasound.so.2': 'libfoo'}})]))
733
734 def test_want_with_metadata_and_binaries(self):
735 # If we detect a binary, then we score 10. The way we determine if
736@@ -338,8 +327,6 @@
737 backend = self.make_backend()
738 shutil.copy(
739 get_test_data_file_path('hello', 'hello'), backend.path)
740- with closing(PackageDatabase(self.db_fixture.conn)) as db:
741- db.update_package('eglibc', {'i386': {'libc.so.6': 'libc6'}})
742 deps, arch = guess_dependencies(backend.path)
743 expected_deps = ', '.join(deps)
744 build_deps = backend.get_build_depends()
745@@ -375,8 +362,6 @@
746
747 def test_get_lib_overrides_for_packages_for_libraries(self):
748 # The configuration file overrides the found library dependencies.
749- with closing(PackageDatabase(self.db_fixture.conn)) as db:
750- db.update_package('foo', {'i386': {'libasound.so.2': 'libfoo'}})
751 self.assertEqual(
752 get_packages_for_libraries(set(["libasound.so.2"]), "i386"),
753 set(["libasound2"]))
754@@ -389,8 +374,6 @@
755 path = self.useFixture(MetadataFixture({})).path
756 self.useFixture(BinaryFileFixture(path))
757 backend = self.make_backend(path)
758- with closing(PackageDatabase(self.db_fixture.conn)) as db:
759- db.update_package('eglibc', {'i386': {'libc.so.6': 'libc6'}})
760 self.assertEqual(backend.get_architecture(), "i386")
761
762 def test_get_extra_targets_makes_executable_executable(self):
763
764=== modified file 'devportalbinary/tests/test_database.py'
765--- devportalbinary/tests/test_database.py 2012-10-26 14:38:49 +0000
766+++ devportalbinary/tests/test_database.py 2012-11-13 12:03:23 +0000
767@@ -1,47 +1,27 @@
768-from collections import namedtuple
769 import os
770
771 from fixtures import TempDir
772-from storm.databases.postgres import psycopg2
773-from storm.exceptions import ClosedError
774 from testresources import ResourcedTestCase
775 from testtools import TestCase
776 from testtools.matchers import (
777 Equals,
778 Matcher,
779 )
780-from treeshape import (
781- CONTENT,
782- FileTree,
783- )
784
785 from devportalbinary.database import (
786 AptFilePackageDatabase,
787- deb_file_url_for_publication,
788- dict_add,
789- find_file_under_dir,
790 get_dependency_database,
791- get_file_contents,
792- get_package_info_from_publication,
793- is_library_package,
794 LibdepServiceClient,
795- libdep_mapping_from_symbols,
796 load_configuration,
797- NoSharedObject,
798- possible_sonames_for_shared_object,
799 PackageDatabase,
800- publishings_to_package_info,
801- shared_object_info_to_soname,
802- shared_objects_from_shlibs,
803- TooManySharedObjects,
804 )
805 from devportalbinary.testing import (
806 ConfigFileFixture,
807 ConfigSettings,
808+ get_libdep_service_client,
809 postgres_db_resource,
810 )
811
812-from djlibdep.test_double import LibdepServiceDouble
813 from libdep_service_client.client import Client
814
815
816@@ -68,76 +48,15 @@
817 self.addCleanup(db.close)
818 return db
819
820- def test_insert_new_library(self):
821- db = self.get_package_db()
822- db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
823- self.assertThat(
824- "SELECT source_package_name, library, dependency, architecture FROM libdep",
825- ResultsIn(db, [('foo-src', 'libfoo.so.0', 'foo', 'i386')]))
826-
827- def test_double_insert(self):
828- db = self.get_package_db()
829- db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
830- self.assertRaises(
831- psycopg2.IntegrityError,
832- db.insert_new_library, 'foo-src', 'libfoo.so.0', 'foo', 'i386')
833-
834- def test_differing_dependencies(self):
835- db = self.get_package_db()
836- db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
837- db.insert_new_library('foo-src', 'libfoo.so.0', 'bar', 'i386')
838- deps = db.get_multiple_dependencies(['libfoo.so.0'], 'i386')
839- self.assertEqual(deps, {'libfoo.so.0': set(['foo', 'bar'])})
840-
841- def test_get_dependencies(self):
842- db = self.get_package_db()
843- db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
844- deps = db.get_multiple_dependencies(['libfoo.so.0'], 'i386')
845- self.assertEqual(deps, {'libfoo.so.0': set(['foo'])})
846-
847- def test_respects_architecture(self):
848- db = self.get_package_db()
849- db.insert_new_library('foo-src', 'libfoo.so.0', 'foo', 'i386')
850- db.insert_new_library('foo-src', 'libfoo.so.0', 'foo-amd64', 'amd64')
851- deps = db.get_multiple_dependencies(['libfoo.so.0'], arch='amd64')
852- self.assertEqual(deps, {'libfoo.so.0': set(['foo-amd64'])})
853-
854 def test_unknown_library(self):
855 db = self.get_package_db()
856 deps = db.get_multiple_dependencies(['libfoo.so.0'], 'i386')
857 self.assertEqual(deps, {})
858
859- def test_update_package(self):
860- db = self.get_package_db()
861- db.update_package(
862- 'foo', {'i386': {'libfoo.so.1': 'foo-bin'}})
863- deps = db.get_multiple_dependencies(['libfoo.so.1'], 'i386')
864- self.assertEqual(deps, {'libfoo.so.1': set(['foo-bin'])})
865-
866- def test_update_existing_package_no_libraries(self):
867- db = self.get_package_db()
868- db.update_package('foo', {'i386': {'libfoo.so.1': 'foo-bin'}})
869- # Run again, this time with no symbols, representing that a newer
870- # version of the package no longer exports any libraries.
871- db.update_package('foo', {'i386': {}})
872- deps = db.get_multiple_dependencies(['libfoo.so.1'], 'i386')
873- self.assertEqual(deps, {})
874-
875- def test_update_package_two_architectures(self):
876- # If two architectures are updated separately then they
877- # shouldn't interfere
878- db = self.get_package_db()
879- db.update_package('foo', {'i386': {'libfoo.so.1': 'foo-bin'}})
880- db.update_package('foo', {'amd64': {'libfoo.so.1': 'foo-bin-amd64'}})
881- deps = db.get_multiple_dependencies(['libfoo.so.1'], arch='i386')
882- self.assertEqual(deps, {'libfoo.so.1': set(['foo-bin'])})
883-
884 def test_close(self):
885 # Test that we can close the package db.
886 db = PackageDatabase(self.db_fixture.conn)
887 db.close()
888- self.assertRaises(ClosedError, db.insert_new_library, 'foo',
889- 'libfoo.so.1', 'foo-bin', 'i386')
890
891 def test_close_twice(self):
892 # Test that we can close the package db twice with no exception.
893@@ -200,264 +119,12 @@
894 self.assertEqual(expected_username, uri.username)
895
896
897-class FakeBPPH(object):
898-
899- def __init__(self):
900- self.archive = namedtuple(
901- 'Archive', 'web_link')('http://lp.net/archive')
902- self.distro_arch_series = namedtuple(
903- 'DistroArchSeries', 'architecture_tag')('i386')
904- self.binary_package_name = 'foo'
905- self.binary_package_version = '1'
906- self.architecture_specific = True
907-
908-
909-class TestDebFileUrlForPublication(TestCase):
910-
911- def test_get_url(self):
912- bpph = FakeBPPH()
913- expected_url = '%s/+files/%s_%s_%s.deb' % (
914- bpph.archive.web_link,
915- bpph.binary_package_name,
916- bpph.binary_package_version,
917- bpph.distro_arch_series.architecture_tag,
918- )
919- self.assertEqual(expected_url, deb_file_url_for_publication(bpph))
920-
921- def test_get_url_with_epoch(self):
922- # epochs are stripped from the version number
923- bpph = FakeBPPH()
924- bpph.binary_package_version = '1:1'
925- expected_url = '%s/+files/%s_%s_%s.deb' % (
926- bpph.archive.web_link,
927- bpph.binary_package_name,
928- '1',
929- bpph.distro_arch_series.architecture_tag,
930- )
931- self.assertEqual(expected_url, deb_file_url_for_publication(bpph))
932-
933- def test_get_url_for_arch_indep(self):
934- # epochs are stripped from the version number
935- bpph = FakeBPPH()
936- bpph.architecture_specific = False
937- expected_url = '%s/+files/%s_%s_all.deb' % (
938- bpph.archive.web_link,
939- bpph.binary_package_name,
940- '1',
941- )
942- self.assertEqual(expected_url, deb_file_url_for_publication(bpph))
943-
944-
945-class TestShlibs(TestCase):
946-
947- def test_empty(self):
948- self.assertEqual({}, shared_objects_from_shlibs(""))
949-
950- def test_comments(self):
951- self.assertEqual({}, shared_objects_from_shlibs("# aaaaa\n"))
952-
953- def test_blank_line(self):
954- self.assertEqual({}, shared_objects_from_shlibs("\n"))
955-
956- def test_whitespace_line(self):
957- self.assertEqual({}, shared_objects_from_shlibs(" \n"))
958-
959- def test_udeb_skipped(self):
960- self.assertEqual({},
961- shared_objects_from_shlibs("udeb: libfoo 1 libfoo\n"))
962-
963- def test_simple_soname(self):
964- self.assertEqual({('libfoo', '1'): 'libfoo'},
965- shared_objects_from_shlibs("libfoo 1 libfoo\n"))
966-
967- def test_other_type_of_soname(self):
968- self.assertEqual({('libfoo', '4.8'): 'libfoo'},
969- shared_objects_from_shlibs("libfoo 4.8 libfoo\n"))
970-
971-
972-class TestPossibleSonamesForSharedObject(TestCase):
973-
974- def test_no_dot(self):
975- self.assertEqual(
976- set(['libfoo.so.1', 'libfoo-1.so']),
977- possible_sonames_for_shared_object('libfoo', '1'))
978-
979- def test_dot(self):
980- self.assertEqual(
981- set(['libfoo-1.0.so']),
982- possible_sonames_for_shared_object('libfoo', '1.0'))
983-
984-
985-class TestFindFileUnderDir(TestCase):
986-
987- def test_file_missing(self):
988- tree = {}
989- path = self.useFixture(FileTree(tree)).path
990- self.assertEqual(None, find_file_under_dir('nothere', path))
991-
992- def test_file_in_basedir(self):
993- filename = 'here'
994- tree = {filename: {}}
995- built_tree = self.useFixture(FileTree(tree))
996- self.assertEqual(built_tree.join(filename),
997- find_file_under_dir(filename, built_tree.path))
998-
999- def test_file_in_subdir(self):
1000- filename = 'here'
1001- relpath = 'there/' + filename
1002- tree = {relpath: {}}
1003- built_tree = self.useFixture(FileTree(tree))
1004- self.assertEqual(built_tree.join(relpath),
1005- find_file_under_dir(filename, built_tree.path))
1006-
1007- def test_handles_multiple_matches(self):
1008- filename = 'here'
1009- relpath = 'there/' + filename
1010- tree = {filename: {}, relpath: {}}
1011- built_tree = self.useFixture(FileTree(tree))
1012- self.assertEqual(built_tree.join(filename),
1013- find_file_under_dir(filename, built_tree.path))
1014-
1015-
1016-class TestSharedObjectInfoToSoname(TestCase):
1017-
1018- def test_no_files(self):
1019- tree = {}
1020- path = self.useFixture(FileTree(tree)).path
1021- self.assertRaises(NoSharedObject,
1022- shared_object_info_to_soname, 'libfoo', '1', path)
1023-
1024- def test_too_many_files(self):
1025- libname = 'libfoo'
1026- version = '1'
1027- possible_sonames = possible_sonames_for_shared_object(libname, version)
1028- tree = dict((name, {}) for name in possible_sonames)
1029- path = self.useFixture(FileTree(tree)).path
1030- self.assertRaises(TooManySharedObjects,
1031- shared_object_info_to_soname, libname, version, path)
1032-
1033- def test_file_found(self):
1034- libname = 'libfoo'
1035- version = '1'
1036- expected_soname = '{0}.so.{1}'.format(libname, version)
1037- tree = {expected_soname: {}}
1038- path = self.useFixture(FileTree(tree)).path
1039- self.assertEqual(expected_soname,
1040- shared_object_info_to_soname(libname, version, path))
1041-
1042-
1043-class TestDictAdd(TestCase):
1044-
1045- def test_no_dicts(self):
1046- self.assertEqual({}, dict_add())
1047-
1048- def test_one_dict(self):
1049- self.assertEqual(dict(a=1), dict_add(dict(a=1)))
1050-
1051- def test_two_dicts(self):
1052- self.assertEqual(dict(a=1, b=2), dict_add(dict(a=1), dict(b=2)))
1053-
1054- def test_precedence(self):
1055- self.assertEqual(dict(a=2), dict_add(dict(a=1), dict(a=2)))
1056-
1057-
1058-class TestIsLibraryPackage(TestCase):
1059-
1060- def test_lib_filename(self):
1061- self.assertEqual(True,
1062- is_library_package('http://launchpad.net/libfoo.deb'))
1063-
1064- def test_whitelisted(self):
1065- self.assertEqual(True,
1066- is_library_package('http://launchpad.net/zlib1g.deb'))
1067-
1068- def test_other(self):
1069- self.assertEqual(False,
1070- is_library_package('http://launchpad.net/bzr.deb'))
1071-
1072-
1073-class TestGetPackageInfoFromPublication(TestCase):
1074-
1075- def test_returns_url_and_arch(self):
1076- bpph = FakeBPPH()
1077- self.assertEqual(
1078- (deb_file_url_for_publication(bpph),
1079- bpph.distro_arch_series.architecture_tag),
1080- get_package_info_from_publication(bpph))
1081-
1082-
1083-class TestPublishingsToPackageInfo(TestCase):
1084-
1085- def test_integration(self):
1086- # This function is split out as it is the testable part of
1087- # fetch symbols files. This tests that the functions glue
1088- # together
1089- publishings = [FakeBPPH(), FakeBPPH()]
1090- expected_bpph = publishings[1]
1091- expected_bpph.binary_package_name = 'libfoo'
1092- expected_info = (deb_file_url_for_publication(expected_bpph),
1093- expected_bpph.distro_arch_series.architecture_tag)
1094- self.assertEqual([expected_info],
1095- publishings_to_package_info(publishings))
1096-
1097-
1098-class TestGetFileContents(TestCase):
1099-
1100- def test_exists(self):
1101- expected_content = 'boring content\n'
1102- filename = 'foo.txt'
1103- tree = {filename: {CONTENT: expected_content}}
1104- path = self.useFixture(FileTree(tree)).join(filename)
1105- self.assertEqual(expected_content, get_file_contents(path))
1106-
1107- def test_not_exists(self):
1108- tree = {}
1109- path = self.useFixture(FileTree(tree)).join('nothere')
1110- self.assertEqual(None, get_file_contents(path))
1111-
1112- def test_directory(self):
1113- tree = {}
1114- path = self.useFixture(FileTree(tree)).path
1115- self.assertRaises(IOError, get_file_contents, path)
1116-
1117-
1118-class TestLibdepMappingFromSymbols(TestCase):
1119-
1120- def test_empty(self):
1121- self.assertEqual({}, libdep_mapping_from_symbols(''))
1122-
1123- def test_blank_line_ignored(self):
1124- self.assertEqual({}, libdep_mapping_from_symbols('\n'))
1125-
1126- def test_alternate_template_ignored(self):
1127- self.assertEqual({}, libdep_mapping_from_symbols('| foo\n'))
1128-
1129- def test_meta_information_ignored(self):
1130- self.assertEqual({}, libdep_mapping_from_symbols('* foo\n'))
1131-
1132- def test_symbols_ignored(self):
1133- self.assertEqual({}, libdep_mapping_from_symbols(' foo\n'))
1134-
1135- def test_comments_ignored(self):
1136- self.assertEqual({}, libdep_mapping_from_symbols('# foo\n'))
1137-
1138- def test_include_ignored(self):
1139- self.assertEqual({},
1140- libdep_mapping_from_symbols('(arch=!armel)#include foo\n'))
1141-
1142- def test_includes_mapping(self):
1143- self.assertEqual({'libfoo.so.1': 'libfoo'},
1144- libdep_mapping_from_symbols('libfoo.so.1 libfoo #MINVER#\n'))
1145-
1146-
1147 class TestLibdepServiceClient(TestCase):
1148
1149 TEST_DATA = [('libfoo', {'i386': {'libfoo': 'libfoo-bin'}})]
1150
1151 def test_wraps_libdep_service(self):
1152- double = self.useFixture(LibdepServiceDouble(self.TEST_DATA))
1153- client = Client(double.base_url)
1154- wrapper = LibdepServiceClient(client)
1155+ wrapper = get_libdep_service_client(self, self.TEST_DATA)
1156 self.assertEqual(
1157 {'libfoo': set(['libfoo-bin'])},
1158 wrapper.get_multiple_dependencies(['libfoo'], 'i386'))
1159
1160=== modified file 'devportalbinary/utils.py'
1161--- devportalbinary/utils.py 2012-09-12 15:07:16 +0000
1162+++ devportalbinary/utils.py 2012-11-13 12:03:23 +0000
1163@@ -68,6 +68,7 @@
1164 def download_file(url, directory=None, name=None, working_dir=None,
1165 bufsize=4 * 2 ** 10, headers=None):
1166 """Download 'url' into 'directory'."""
1167+ # XXX: download_file is no longer used within pkgme-devportal
1168 request = Request(url)
1169 if headers is not None:
1170 for h in headers:
1171
1172=== modified file 'setup.py'
1173--- setup.py 2012-10-18 13:36:37 +0000
1174+++ setup.py 2012-11-13 12:03:23 +0000
1175@@ -46,7 +46,6 @@
1176 entry_points = {
1177 'console_scripts': [
1178 'dump-apt-file-db=devportalbinary.aptfile:dump_apt_file_db',
1179- 'fetch-symbol-files=devportalbinary.database:main',
1180 'guess-executable=devportalbinary.binary:print_executable',
1181 'guess-deps=devportalbinary.binary:print_dependencies',
1182 ],

Subscribers

People subscribed via source and target branches