Merge lp:~jml/pkgme-devportal/restore-download-file into lp:pkgme-devportal

Proposed by Jonathan Lange
Status: Merged
Approved by: Jonathan Lange
Approved revision: 180
Merged at revision: 146
Proposed branch: lp:~jml/pkgme-devportal/restore-download-file
Merge into: lp:pkgme-devportal
Diff against target: 798 lines (+15/-665)
7 files modified
NEWS (+3/-0)
devportalbinary/aptfile.py (+0/-226)
devportalbinary/database.py (+5/-131)
devportalbinary/testing.py (+3/-139)
devportalbinary/tests/test_aptfile.py (+0/-53)
devportalbinary/tests/test_database.py (+2/-114)
setup.py (+2/-2)
To merge this branch: bzr merge lp:~jml/pkgme-devportal/restore-download-file
Reviewer Review Type Date Requested Status
Jonathan Lange Approve
Review via email: mp+134116@code.launchpad.net

Commit message

Add download_file back to devportalbinary.database

Description of the change

download_file was being imported by pkgme-service from devportalbinary.database.

Another branch is in progress, removing this particular dependency. In the mean
time, this branch should land, restoring the behaviour so we can bump pkgme-service
to use latest devportal without probs.

To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

Rubberstamp! Proposer approves of own proposal.

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:53:23 +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:53:23 +0000
249@@ -1,134 +1,13 @@
250 # Copyright 2011 Canonical Ltd. This software is licensed under the
251 # GNU Affero General Public License version 3 (see the file LICENSE).
252
253-from storm.expr import And, Column, Select, Table
254-from storm.locals import create_database, Store
255-from storm.uri import URI as StormURI
256-
257-from .aptfile import AptFilePackageDatabase
258-from .configuration import (
259- CONF_FILE_ENV_VAR,
260- get_config_file_path,
261- load_configuration,
262- )
263+from .configuration import load_configuration
264+from .utils import download_file
265
266 from libdep_service_client.client import Client
267
268-
269-class URI(StormURI):
270- """A stand-in for Storm's URI class.
271-
272- This class implements the same interface as `storm.uri.URI`, except
273- that the constructor has a different signature. Storm's version takes
274- a string and parses it, this version can be used when you already
275- have a parsed version and just need to create the object.
276- """
277-
278- # XXX: Only used by PackageDatabase, which is flagged for deletion.
279-
280- def __init__(self, scheme=None, host=None, port=None, username=None,
281- password=None, database=None, options=None):
282- self.scheme = scheme
283- self.host = host
284- self.port = port
285- self.username = username
286- self.password = password
287- self.database = database
288- self.options = options
289- if self.options is None:
290- self.options = dict()
291-
292-
293-class PackageDatabase(object):
294-
295- # XXX: No longer used within pkgme-devportal
296-
297- SQLITE = 'sqlite'
298- POSTGRES = 'postgres'
299-
300- def __init__(self, store):
301- self._store = store
302-
303- @classmethod
304- def _get_storm_sqlite_connection_uri(cls, opts):
305- raise ValueError(
306- "SQLite is no longer supported, you must migrate to postgresql.")
307-
308- @classmethod
309- def _get_storm_postgres_connection_uri(cls, opts):
310- if not getattr(opts, 'database_db_name', None):
311- raise ValueError(
312- "Can't create database, no connection info available. "
313- "You must specify %s. Looked in %s. "
314- "Perhaps %s is set incorrectly?" % (
315- 'db_name', get_config_file_path(), CONF_FILE_ENV_VAR))
316- return URI(scheme=opts.database_db_type,
317- username=opts.database_username,
318- password=opts.database_password,
319- host=opts.database_host,
320- port=opts.database_port,
321- database=opts.database_db_name)
322-
323- @classmethod
324- def _get_storm_connection_uri(cls, opts):
325- if opts.database_db_type == cls.POSTGRES:
326- return cls._get_storm_postgres_connection_uri(opts)
327- elif opts.database_db_type == cls.SQLITE:
328- return cls._get_storm_sqlite_connection_uri(opts)
329- else:
330- raise AssertionError(
331- "Unsupported database: %s" % opts.database_db_type)
332-
333- @classmethod
334- def get_db_info_from_config(cls, opts):
335- return cls._get_storm_connection_uri(opts)
336-
337- @classmethod
338- def get_store_from_config(cls, opts):
339- """Create a storm store based on a config file.
340-
341- This method will create a storm store based
342- on the information in ``~/.config/pkgme-binary/conf``
343-
344- :return: a tuple of (store, store_type), where store_type
345- is one of cls.SQLITE or cls.POSTGRES, indicating what
346- is at the other end of the store.
347- """
348- connection_info = cls.get_db_info_from_config(opts)
349- database = create_database(connection_info)
350- return Store(database)
351-
352- @classmethod
353- def from_options(cls, options):
354- return cls(cls.get_store_from_config(options))
355-
356- def _get_query(self, library_names, arch):
357- return Select(
358- [Column('library'), Column('dependency')],
359- And(Column('architecture') == arch,
360- Column('library').is_in(map(unicode, library_names))),
361- Table('libdep'))
362-
363- def get_multiple_dependencies(self, library_names, arch):
364- """Get the binary packages that provide libraries.
365-
366- :return: (deps, missing), where ``deps`` is a dict mapping library
367- names to sets of packages that provide them, and ``missing`` is a
368- set of library names for which no dependencies could be found.
369- """
370- arch = unicode(arch)
371- result = self._store.execute(self._get_query(library_names, arch))
372- found = {}
373- for row in result:
374- [lib, dependency] = row
375- if lib in found:
376- found[lib].add(dependency)
377- else:
378- found[lib] = set([dependency])
379- return found
380-
381- def close(self):
382- self._store.close()
383+# Shut up pyflakes. Imported because other things use this.
384+download_file
385
386
387 class LibdepServiceClient(object):
388@@ -159,10 +38,5 @@
389
390 def get_dependency_database():
391 """Return an object that can get dependencies."""
392- # XXX: Remove AptFilePackageDatabase from here and simplify the method.
393- databases = {
394- AptFilePackageDatabase.DB_TYPE: AptFilePackageDatabase.from_options,
395- LibdepServiceClient.DB_TYPE: LibdepServiceClient.from_options,
396- }
397 options = load_configuration()
398- return databases[options.database_db_type](options)
399+ return LibdepServiceClient.from_options(options)
400
401=== modified file 'devportalbinary/testing.py'
402--- devportalbinary/testing.py 2012-11-13 11:12:08 +0000
403+++ devportalbinary/testing.py 2012-11-13 14:53:23 +0000
404@@ -1,7 +1,6 @@
405 # Copyright 2011-2012 Canonical Ltd. This software is licensed under the
406 # GNU Affero General Public License version 3 (see the file LICENSE).
407
408-from contextlib import closing
409 import json
410 import os
411 import random
412@@ -21,11 +20,6 @@
413 Fixture,
414 TempDir,
415 )
416-from postgresfixture import ClusterFixture
417-from storm.locals import create_database, Store
418-from testresources import (
419- FixtureResource as _FixtureResource,
420- )
421 from testtools import TestCase
422 from treeshape import (
423 from_rough_spec,
424@@ -33,11 +27,7 @@
425 )
426
427 from devportalbinary.binary import MetadataBackend
428-from devportalbinary.database import (
429- LibdepServiceClient,
430- PackageDatabase,
431- URI,
432- )
433+from devportalbinary.database import LibdepServiceClient
434
435 from devportalbinary.configuration import CONF_FILE_ENV_VAR
436
437@@ -90,133 +80,6 @@
438 im.size[0], im.size[1], im.format))
439
440
441-def get_db_schema_file_path(name):
442- return os.path.join(os.path.dirname(
443- os.path.abspath(__file__)), 'db', name)
444-
445-
446-def get_db_schema_queries(filenames):
447- for filename in filenames:
448- path = get_db_schema_file_path(filename)
449- with open(path) as f:
450- yield f.read()
451-
452-
453-class PostgresDatabaseFixture(Fixture):
454-
455- def __init__(self):
456- super(PostgresDatabaseFixture, self).__init__()
457- self.db_name = "libdep"
458-
459- def drop_db(self):
460- # stub suggests that dropping all tables would be quicker than
461- # dropping the db when the number of tables is small.
462- # select quote_ident(table_schema) || '.' ||
463- # quote_ident(table_name) from information_schema.tables
464- # WHERE table_schema = 'public';
465- self.cluster.dropdb(self.db_name)
466-
467- def create_db(self):
468- self.cluster.createdb(self.db_name)
469- queries = [
470- 'postgres_schema.sql',
471- 'patch-00001.sql',
472- 'patch-00002.sql',
473- ]
474- for patch in get_db_schema_queries(queries):
475- self._execute(patch)
476-
477- def _execute(self, query):
478- with closing(self.cluster.connect(self.db_name)) as conn:
479- cur = conn.cursor()
480- cur.execute(query)
481- conn.commit()
482-
483- def close_connection(self):
484- self.conn.close()
485-
486- def open_connection(self):
487- db = create_database(URI(scheme='postgres',
488- host=self.cluster.datadir, database=self.db_name))
489- self.conn = Store(db)
490- self.addCleanup(self.close_connection)
491-
492- def reset(self):
493- self.close_connection()
494- self.drop_db()
495- self.create_db()
496- self.open_connection()
497-
498- def setUp(self):
499- super(PostgresDatabaseFixture, self).setUp()
500- self.tempdir = self.useFixture(TempDir())
501- self.cluster = self.useFixture(ClusterFixture(self.tempdir.path))
502- self.create_db()
503- self.open_connection()
504-
505-
506-class FixtureResource(_FixtureResource):
507- """The built in FixtureResource doesn't get properly dirtied."""
508- # XXX: workaround for bug 1023423
509-
510- def _get_dirty(self):
511- return True
512-
513- def _set_dirty(self, new_val):
514- pass
515-
516- _dirty = property(_get_dirty, _set_dirty)
517-
518-
519-class PostgresDatabaseResource(FixtureResource):
520-
521- def __init__(self):
522- fixture = PostgresDatabaseFixture()
523- super(PostgresDatabaseResource, self).__init__(fixture)
524-
525- def reset(self, resource, result=None):
526- resource.reset()
527- return resource
528-
529-
530-postgres_db_resource = PostgresDatabaseResource()
531-
532-
533-class DatabaseConfig(Fixture):
534-
535- def __init__(self, db_fixture):
536- super(DatabaseConfig, self).__init__()
537- self.db_fixture = db_fixture
538-
539- def setUp(self):
540- super(DatabaseConfig, self).setUp()
541- self.useFixture(
542- ConfigSettings(
543- ('database', {'db_type': 'postgres',
544- 'host': self.db_fixture.cluster.datadir,
545- 'db_name': self.db_fixture.db_name,
546- })))
547-
548-
549-class DatabaseFixture(Fixture):
550- """Create a temporary database and make it the default.
551-
552- Don't use this twice within a test, otherwise you'll get confused.
553- """
554-
555- def setUp(self):
556- super(DatabaseFixture, self).setUp()
557- pg_db = self.useFixture(PostgresDatabaseFixture())
558- self.useFixture(DatabaseConfig(pg_db))
559- self.db = PackageDatabase(pg_db.conn)
560- self.addCleanup(self.db.close)
561-
562-
563-def ConfigFileFixture(location):
564- """Use a different configuration file."""
565- return EnvironmentVariableFixture(CONF_FILE_ENV_VAR, location)
566-
567-
568 class ConfigSettings(Fixture):
569 """Use a configuration file with different settings."""
570
571@@ -239,7 +102,8 @@
572 tempdir = self.useFixture(TempDir())
573 config_file_path = os.path.join(tempdir.path, 'test.cfg')
574 write_config_file(config_file_path, self._settings)
575- self.useFixture(ConfigFileFixture(config_file_path))
576+ self.useFixture(
577+ EnvironmentVariableFixture(CONF_FILE_ENV_VAR, config_file_path))
578
579
580 class LibdepFixture(Fixture):
581
582=== removed file 'devportalbinary/tests/test_aptfile.py'
583--- devportalbinary/tests/test_aptfile.py 2012-10-26 12:21:03 +0000
584+++ devportalbinary/tests/test_aptfile.py 1970-01-01 00:00:00 +0000
585@@ -1,53 +0,0 @@
586-import gzip
587-import os
588-
589-from mock import patch
590-from fixtures import TempDir
591-from testtools import TestCase
592-
593-from ..aptfile import AptFilePackageDatabase
594-
595-
596-class AptFilePackageDatabaseTestCase(TestCase):
597-
598- # point to our local contents file version that is a tad smaller
599- CONTENTS_CACHE = os.path.join(
600- os.path.dirname(__file__), "data", "apt-file-backend")
601-
602- def setUp(self):
603- super(AptFilePackageDatabaseTestCase, self).setUp()
604- self.db = AptFilePackageDatabase(self.CONTENTS_CACHE)
605-
606- def test_read_fixture_contents_worked(self):
607- """ test that our fixture Contents file works as expected """
608- # our test DB has 4 entries in the default search path
609- self.assertEqual(
610- len(self.db._get_lib_to_pkgs_mapping("oneiric", "i386")), 4)
611-
612- def test_get_dependencies(self):
613- """ Test that data from the fixture dependencies file works """
614- self.assertEqual(
615- self.db.get_multiple_dependencies(["libz.so.1"], 'i386'),
616- ({'libz.so.1': 'zlib1g'}, set()))
617-
618- @patch("urllib.urlretrieve")
619- def test_lazy_downloading(self, mock_urlretrieve):
620- """ test that lazy downloading works """
621- def _put_fixture_contents_file_in_place(url, target):
622- with gzip.open(target, "w") as f:
623- f.write("""
624-Some header text that is ignored
625-FILE LOCATION
626-usr/lib/libfoo.so.2 pkgfoo,pkgbar
627-""")
628- tempdir = self.useFixture(TempDir())
629- db = AptFilePackageDatabase(tempdir.path)
630- mock_urlretrieve.side_effect = _put_fixture_contents_file_in_place
631- self.assertEqual(
632- db.get_multiple_dependencies(["libfoo.so.2"], arch="i386"),
633- ({'libfoo.so.2': set(["pkgfoo", "pkgbar"])}, set()))
634- self.assertEqual(len(db._get_lib_to_pkgs_mapping("oneiric", "i386")), 1)
635-
636- def test_close(self):
637- # Test that there is a close method we can call
638- self.db.close()
639
640=== modified file 'devportalbinary/tests/test_database.py'
641--- devportalbinary/tests/test_database.py 2012-11-13 11:22:16 +0000
642+++ devportalbinary/tests/test_database.py 2012-11-13 14:53:23 +0000
643@@ -1,124 +1,12 @@
644-import os
645
646-from fixtures import TempDir
647-from testresources import ResourcedTestCase
648 from testtools import TestCase
649-from testtools.matchers import (
650- Equals,
651- Matcher,
652- )
653
654-from devportalbinary.database import (
655- AptFilePackageDatabase,
656- get_dependency_database,
657- LibdepServiceClient,
658- load_configuration,
659- PackageDatabase,
660- )
661-from devportalbinary.testing import (
662- ConfigFileFixture,
663- ConfigSettings,
664- get_libdep_service_client,
665- postgres_db_resource,
666- )
667+from devportalbinary.database import LibdepServiceClient
668+from devportalbinary.testing import get_libdep_service_client
669
670 from libdep_service_client.client import Client
671
672
673-class ResultsIn(Matcher):
674-
675- def __init__(self, db, rows):
676- self._db = db
677- self._rows = rows
678-
679- def match(self, query):
680- # XXX: Abstraction violation
681- results = self._db._store.execute(query)
682- return Equals(self._rows).match(list(results))
683-
684-
685-class TestDatabase(TestCase, ResourcedTestCase):
686-
687- resources = [
688- ('db_fixture', postgres_db_resource),
689- ]
690-
691- def get_package_db(self):
692- db = PackageDatabase(self.db_fixture.conn)
693- self.addCleanup(db.close)
694- return db
695-
696- def test_unknown_library(self):
697- db = self.get_package_db()
698- deps = db.get_multiple_dependencies(['libfoo.so.0'], 'i386')
699- self.assertEqual(deps, {})
700-
701- def test_close(self):
702- # Test that we can close the package db.
703- db = PackageDatabase(self.db_fixture.conn)
704- db.close()
705-
706- def test_close_twice(self):
707- # Test that we can close the package db twice with no exception.
708- db = PackageDatabase(self.db_fixture.conn)
709- db.close()
710- db.close()
711-
712-
713-class TestDatabaseConfiguration(TestCase):
714-
715- def use_database_config(self, **db_settings):
716- return self.useFixture(ConfigSettings(('database', db_settings)))
717-
718- def test_get_db_info_from_config_sqlite(self):
719- other_tempdir = self.useFixture(TempDir())
720- expected_db_path = os.path.join(other_tempdir.path, 'db')
721- self.use_database_config(db_type='sqlite', path=expected_db_path)
722- options = load_configuration()
723- self.assertRaises(ValueError, PackageDatabase.get_db_info_from_config,
724- options)
725-
726- def test_default_create_no_config(self):
727- nonexistent = self.getUniqueString()
728- self.useFixture(ConfigFileFixture(nonexistent))
729- self.assertIsInstance(
730- get_dependency_database(), AptFilePackageDatabase)
731-
732- def test_default_create_empty_config(self):
733- self.useFixture(ConfigSettings())
734- self.assertIsInstance(
735- get_dependency_database(), AptFilePackageDatabase)
736-
737- def test_remote_service(self):
738- base_url = 'http://example.com/libdep-service/'
739- self.use_database_config(db_type='libdep-service', base_url=base_url)
740- db = get_dependency_database()
741- self.assertIsInstance(db, LibdepServiceClient)
742- self.assertEqual(base_url, db._client.base_url)
743-
744- def test_get_db_info_from_config_postgres(self):
745- expected_username = self.getUniqueString()
746- expected_password = self.getUniqueString()
747- expected_host = self.getUniqueString()
748- expected_port = self.getUniqueInteger()
749- expected_db_name = self.getUniqueString()
750-
751- self.use_database_config(
752- db_type='postgres',
753- username=expected_username,
754- password=expected_password,
755- host=expected_host,
756- port=expected_port,
757- db_name=expected_db_name)
758- options = load_configuration()
759- uri = PackageDatabase.get_db_info_from_config(options)
760- self.assertEqual(expected_db_name, uri.database)
761- self.assertEqual(expected_port, uri.port)
762- self.assertEqual(expected_host, uri.host)
763- self.assertEqual(expected_password, uri.password)
764- self.assertEqual(expected_username, uri.username)
765-
766-
767 class TestLibdepServiceClient(TestCase):
768
769 TEST_DATA = [('libfoo', {'i386': {'libfoo': 'libfoo-bin'}})]
770
771=== modified file 'setup.py'
772--- setup.py 2012-11-13 09:14:39 +0000
773+++ setup.py 2012-11-13 14:53:23 +0000
774@@ -18,6 +18,8 @@
775 )
776 from setuptools import setup, find_packages
777
778+# XXX: Need to do a trawl to see if we are depending on things that we are no
779+# longer using.
780
781 __version__ = get_version('devportalbinary/__init__.py')
782
783@@ -36,7 +38,6 @@
784 install_requires = [
785 'bzr',
786 'configglue',
787- 'launchpadlib',
788 'libdep-service-python>=0.0.5',
789 'PIL',
790 'pkgme>=0.4.1',
791@@ -45,7 +46,6 @@
792 ],
793 entry_points = {
794 'console_scripts': [
795- 'dump-apt-file-db=devportalbinary.aptfile:dump_apt_file_db',
796 'guess-executable=devportalbinary.binary:print_executable',
797 'guess-deps=devportalbinary.binary:print_dependencies',
798 ],

Subscribers

People subscribed via source and target branches