Merge lp:~james-w/pkgme-devportal/stormify into lp:pkgme-devportal
- stormify
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 19 |
Proposed branch: | lp:~james-w/pkgme-devportal/stormify |
Merge into: | lp:pkgme-devportal |
Diff against target: |
503 lines (+235/-55) 6 files modified
README (+39/-1) acceptance/tests/__init__.py (+3/-14) devportalbinary/database.py (+116/-27) devportalbinary/testing.py (+23/-2) devportalbinary/tests/test_database.py (+52/-11) setup.py (+2/-0) |
To merge this branch: | bzr merge lp:~james-w/pkgme-devportal/stormify |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
pkgme binary committers | Pending | ||
Review via email: mp+84529@code.launchpad.net |
Commit message
Description of the change
Hi,
This branch stormifies the code, in order to support postgres as well
as sqlite.
It's not the prettiest thing ever, and the postgres code is under-tested, but
I didn't want to deal with using a postgres fixture.
The unicode() changes are so that postgres types match up, and should be
fine as package names and library file names are (have to be?) ascii.
Thanks,
James
Jonathan Lange (jml) wrote : | # |
James Westby (james-w) wrote : | # |
> > + SQLITE = 'sqlite'
> > + POSTGRES = 'postgres'
> > +
> > ENV_VAR = 'PKGME_
>
> Why didn't you delete ENV_VAR?
It's still used as a fallback. I can delete that code if we want
to just go straight for the config file approach?
> > + @classmethod
> > + def get_store_
> > + """Create a storm store based on a config file.
> > +
> > + This method will create a storm store based
> > + on the information in ``~/.config/
> > +
> > + If that file doesn't exist, or it doesn't contain
> > + information about setting up a database then this
> > + method will return None.
> > + """
>
> Really? It looks like it will always return a tuple.
Good catch, I wrote that docstring before writing any code, and
then changed my approach. I'll fix it up.
> We could probably factor this into using different classes to
> represent the different types of database. Would avoid the 'if' here
> and maybe having to pass around the database type. Probably for a
> later branch though.
I think that would be a good change, I'll defer it for now.
> > def setUp(self):
> > super(DatabaseF
> > + # Set a temporary homedir so that any config on the user's
> > + # machine isn't picked up and the environment variable is used
> > + # instead.
> > + self.useFixture
> > tempdir = self.useFixture
> > db_path = os.path.
> > - self.useFixture
> db_path))
> > - self.db = PackageDatabase
> > + config_file_path = os.path.
> > + os.makedirs(
> > + with open(config_
> > + f.write(
> > + self.db = PackageDatabase
> > +
>
> It's a pity we can't use an in-memory database.
Yeah, this is used for testing across processes so there's
not a lot we can do there I don't think. We should restrict
the number of tests that use it to a minimum though I think.
> This should probably be submitted upstream.
I'll do that.
> As far as I can tell, self.home_dir is unused. Best then to not set it.
Good idead.
> Test coverage is good.
>
> In summary,
> * Delete ENV_VAR
> * Change get_store_
What do you think about dropping support for the env var? I kept it
so that any deployment would keep working across the change, but
we can probably have Tom incorporate this change as he'll want it
for postgres support anyway.
Thanks,
James
Jonathan Lange (jml) wrote : | # |
On Tue, Dec 6, 2011 at 4:08 PM, James Westby <email address hidden> wrote:
>
>> > + SQLITE = 'sqlite'
>> > + POSTGRES = 'postgres'
>> > +
>> > ENV_VAR = 'PKGME_
>>
>> Why didn't you delete ENV_VAR?
>
> It's still used as a fallback. I can delete that code if we want
> to just go straight for the config file approach?
>
...
>> Test coverage is good.
>>
>> In summary,
>> * Delete ENV_VAR
>> * Change get_store_
>
> What do you think about dropping support for the env var? I kept it
> so that any deployment would keep working across the change, but
> we can probably have Tom incorporate this change as he'll want it
> for postgres support anyway.
>
Let's leave it in there, and then delete once we've deployed with the
config file.
approve
jml
Preview Diff
1 | === modified file 'README' |
2 | --- README 2011-11-21 16:19:48 +0000 |
3 | +++ README 2011-12-05 21:01:26 +0000 |
4 | @@ -6,6 +6,9 @@ |
5 | |
6 | * pkgme |
7 | * bzr |
8 | + * storm |
9 | + * configglue |
10 | + * launchpadlib (if running fetch-symbol-files) |
11 | |
12 | Tests |
13 | ----- |
14 | @@ -13,8 +16,43 @@ |
15 | * fixtures |
16 | * testtools |
17 | |
18 | +Configuration File |
19 | +================== |
20 | + |
21 | +Behaviour can be controlled by a config file at |
22 | + |
23 | + $HOME/.config/pkgme-binary/conf |
24 | + |
25 | +Currently one section is supported for configuring database access. |
26 | +This can either be sqlite or postgres. |
27 | + |
28 | +SQLite |
29 | +------ |
30 | + |
31 | +The file should look something like:: |
32 | + |
33 | + [database] |
34 | + db_type = sqlite |
35 | + path = /path/to/file.db |
36 | + |
37 | +Postgres |
38 | +-------- |
39 | + |
40 | +The file should look something like:: |
41 | + |
42 | + [database] |
43 | + db_type = postgres |
44 | + host = <db host> |
45 | + port = <db port> |
46 | + username = <db username> |
47 | + password = <db password> |
48 | + |
49 | +When using postgres it expects to be able to use a database |
50 | +called "pkgme_binary_dependencies" but tables within this |
51 | +database will be created by the tool itself. |
52 | + |
53 | Acceptance tests |
54 | ----------------- |
55 | +================ |
56 | |
57 | There is an acceptance test suite that is not run as part of the |
58 | unit tests. You can run these tests with |
59 | |
60 | === modified file 'acceptance/tests/__init__.py' |
61 | --- acceptance/tests/__init__.py 2011-11-15 17:27:30 +0000 |
62 | +++ acceptance/tests/__init__.py 2011-12-05 21:01:26 +0000 |
63 | @@ -1,13 +1,13 @@ |
64 | import os |
65 | import shutil |
66 | |
67 | -from fixtures import EnvironmentVariableFixture, Fixture, MonkeyPatch |
68 | +from fixtures import Fixture, MonkeyPatch |
69 | from testtools import TestCase |
70 | |
71 | import pkgme |
72 | from pkgme.testing import PathExists, TempdirFixture |
73 | |
74 | -from devportalbinary.database import PackageDatabase |
75 | +from devportalbinary.testing import DatabaseFixture |
76 | |
77 | |
78 | class TestData(Fixture): |
79 | @@ -24,17 +24,6 @@ |
80 | shutil.copytree(source_path, self.path) |
81 | |
82 | |
83 | -class DependencyDatabase(Fixture): |
84 | - |
85 | - def setUp(self): |
86 | - Fixture.setUp(self) |
87 | - tempdir = self.useFixture(TempdirFixture()) |
88 | - db_path = os.path.join(tempdir.path, 'db') |
89 | - self.useFixture( |
90 | - EnvironmentVariableFixture(PackageDatabase.ENV_VAR, db_path)) |
91 | - self.db = PackageDatabase.create() |
92 | - |
93 | - |
94 | class AcceptanceTests(TestCase): |
95 | |
96 | def setUp(self): |
97 | @@ -63,7 +52,7 @@ |
98 | |
99 | def test_gtk(self): |
100 | """Runs successfully for a basic GTK+ application.""" |
101 | - dep_db = self.useFixture(DependencyDatabase()) |
102 | + dep_db = self.useFixture(DatabaseFixture()) |
103 | test_data = self.useFixture(TestData("gtk")) |
104 | self.run_pkgme(test_data) |
105 | self.assertThat( |
106 | |
107 | === modified file 'devportalbinary/database.py' |
108 | --- devportalbinary/database.py 2011-10-25 16:45:08 +0000 |
109 | +++ devportalbinary/database.py 2011-12-05 21:01:26 +0000 |
110 | @@ -5,22 +5,22 @@ |
111 | from itertools import chain |
112 | import os |
113 | import shutil |
114 | -import sqlite3 |
115 | import tempfile |
116 | from urllib2 import urlopen |
117 | |
118 | from bzrlib import urlutils |
119 | +from configglue import glue, schema |
120 | from launchpadlib import ( |
121 | uris, |
122 | ) |
123 | from launchpadlib.launchpad import Launchpad |
124 | from pkgme.run_script import run_subprocess |
125 | +from storm.locals import create_database, Store |
126 | |
127 | |
128 | APPLICATION_NAME = 'pkgme-binary' |
129 | SERVICE_ROOT = uris.LPNET_SERVICE_ROOT |
130 | |
131 | - |
132 | def get_lp(): |
133 | return Launchpad.login_anonymously(APPLICATION_NAME, SERVICE_ROOT, tempfile.mkdtemp()) |
134 | |
135 | @@ -201,38 +201,129 @@ |
136 | db.update_source_package(source_package_name, symbols) |
137 | |
138 | |
139 | +class PackageDBSchema(schema.Schema): |
140 | + |
141 | + class database(schema.Section): |
142 | + db_type = schema.StringOption(default='sqlite', |
143 | + help=('The database to use, one of "sqlite", or "postgres"')) |
144 | + host = schema.StringOption( |
145 | + help='The database host (for postgres)') |
146 | + port = schema.StringOption( |
147 | + help='The database port (for postgres)') |
148 | + username = schema.StringOption( |
149 | + help='The database username (for postgres)') |
150 | + password = schema.StringOption( |
151 | + help='The database password (for postgres)') |
152 | + path = schema.StringOption( |
153 | + help='The path to the database file (for sqlite)') |
154 | + |
155 | + |
156 | class PackageDatabase(object): |
157 | |
158 | + SQLITE = 'sqlite' |
159 | + POSTGRES = 'postgres' |
160 | + |
161 | ENV_VAR = 'PKGME_LIB_DEPS_DB_PATH' |
162 | + CONF_FILE = '~/.config/pkgme-binary/conf' |
163 | |
164 | - def __init__(self, sqlite_database): |
165 | - self._sqlite = sqlite_database |
166 | + def __init__(self, store): |
167 | + self._store = store |
168 | |
169 | @classmethod |
170 | - def create(cls, sqlite_path=None): |
171 | - if sqlite_path is None: |
172 | + def _get_storm_sqlite_connection_string(cls, opts): |
173 | + if not opts.database_path: |
174 | try: |
175 | - sqlite_path = os.environ[cls.ENV_VAR] |
176 | + opts.database_path = os.environ[cls.ENV_VAR] |
177 | except KeyError: |
178 | raise ValueError( |
179 | "Cannot create database, no path given and %s not set" |
180 | % (cls.ENV_VAR,)) |
181 | - c = sqlite3.connect(sqlite_path) |
182 | - c.cursor().execute( |
183 | - "CREATE TABLE IF NOT EXISTS libdep (" |
184 | - "source_package_name TEXT, " |
185 | - "library TEXT, " |
186 | - "dependency TEXT, " |
187 | - "CONSTRAINT libdep_uniq UNIQUE (source_package_name, " |
188 | - "library, dependency))") |
189 | - return cls(c) |
190 | + return '%s:%s' % (opts.database_db_type, opts.database_path) |
191 | + |
192 | + @classmethod |
193 | + def _get_storm_postgres_connection_string(cls, opts): |
194 | + for attr in ('database_host', 'database_port', |
195 | + 'database_username', 'database_password'): |
196 | + if not getattr(opts, attr, None): |
197 | + raise AssertionError( |
198 | + "You must specify %s for %s" % ( |
199 | + attr, opts.database_db_type)) |
200 | + return '%s://%s:%s@%s:%s/pkgme_binary_dependencies' % ( |
201 | + opts.database_db_type, opts.database_username, |
202 | + opts.database_password, opts.database_host, |
203 | + opts.database_port) |
204 | + |
205 | + @classmethod |
206 | + def _get_storm_connection_string(cls, opts): |
207 | + if opts.database_db_type == cls.SQLITE: |
208 | + return cls._get_storm_sqlite_connection_string(opts) |
209 | + elif opts.database_db_type == cls.POSTGRES: |
210 | + return cls._get_storm_postgres_connection_string(opts) |
211 | + else: |
212 | + raise AssertionError( |
213 | + "Unsupported database: %s" % opts.database_db_type) |
214 | + |
215 | + @classmethod |
216 | + def get_db_info_from_config(cls): |
217 | + config_location = os.path.expanduser(cls.CONF_FILE) |
218 | + config_files = [] |
219 | + if os.path.exists(config_location): |
220 | + config_files.append(config_location) |
221 | + theglue = glue.configglue(PackageDBSchema, config_files) |
222 | + opts = theglue.options |
223 | + connection_string = cls._get_storm_connection_string(opts) |
224 | + return connection_string, opts.database_db_type |
225 | + |
226 | + @classmethod |
227 | + def get_store_from_config(cls): |
228 | + """Create a storm store based on a config file. |
229 | + |
230 | + This method will create a storm store based |
231 | + on the information in ``~/.config/pkgme-binary/conf`` |
232 | + |
233 | + If that file doesn't exist, or it doesn't contain |
234 | + information about setting up a database then this |
235 | + method will return None. |
236 | + """ |
237 | + connection_string, store_type = cls.get_db_info_from_config() |
238 | + database = create_database(connection_string) |
239 | + return Store(database), store_type |
240 | + |
241 | + @classmethod |
242 | + def create(cls, store=None, store_type='sqlite'): |
243 | + if store is None: |
244 | + store, store_type = cls.get_store_from_config() |
245 | + if store_type == 'sqlite': |
246 | + store.execute( |
247 | + "CREATE TABLE IF NOT EXISTS libdep (" |
248 | + "source_package_name TEXT, " |
249 | + "library TEXT, " |
250 | + "dependency TEXT, " |
251 | + "CONSTRAINT libdep_uniq UNIQUE (source_package_name, " |
252 | + "library, dependency))") |
253 | + elif store_type == 'postgres': |
254 | + # Postgres only supports IF NOT EXISTS starting from 9.1 |
255 | + exists = store.execute( |
256 | + "SELECT COUNT(relname) FROM pg_class WHERE " |
257 | + "relname = 'libdep'").get_one()[0] |
258 | + if not exists: |
259 | + store.execute( |
260 | + "CREATE TABLE libdep (" |
261 | + "source_package_name TEXT, " |
262 | + "library TEXT, " |
263 | + "dependency TEXT, " |
264 | + "CONSTRAINT libdep_uniq UNIQUE (source_package_name, " |
265 | + "library, dependency))") |
266 | + else: |
267 | + raise AssertionError("Unsupported database type: %s" % store_type) |
268 | + store.commit() |
269 | + return cls(store) |
270 | |
271 | def get_dependencies(self, library_name): |
272 | """Get the binary packagaes that provide 'library_name'.""" |
273 | - c = self._sqlite.cursor() |
274 | - c.execute("SELECT dependency FROM libdep WHERE library = ?", |
275 | - (library_name,)) |
276 | - return set([dependency for [dependency] in c]) |
277 | + result = self._store.execute("SELECT dependency FROM libdep WHERE library = ?", |
278 | + (unicode(library_name),)) |
279 | + return set([dependency for [dependency] in result]) |
280 | |
281 | def insert_new_library(self, source_package_name, library_name, dependency): |
282 | """Insert a library and its needed dependency into the database. |
283 | @@ -241,9 +332,8 @@ |
284 | :param dependency: A binary package dependency, possibly including |
285 | version. |
286 | """ |
287 | - c = self._sqlite.cursor() |
288 | - c.execute("INSERT INTO libdep VALUES (?, ?, ?)", |
289 | - (source_package_name, library_name, dependency)) |
290 | + self._store.execute("INSERT INTO libdep VALUES (?, ?, ?)", |
291 | + (unicode(source_package_name), unicode(library_name), unicode(dependency))) |
292 | |
293 | def update_source_package(self, source_package_name, symbols): |
294 | """Update the database with the symbols from 'source_package_name'. |
295 | @@ -254,14 +344,13 @@ |
296 | representation is a list of tuples of library and |
297 | dependency. e.g. [[(libfoo, foo), ...], ...]. |
298 | """ |
299 | - c = self._sqlite.cursor() |
300 | - c.execute("DELETE FROM libdep WHERE source_package_name = ?", |
301 | - (source_package_name,)) |
302 | + self._store.execute("DELETE FROM libdep WHERE source_package_name = ?", |
303 | + (unicode(source_package_name),)) |
304 | for symbols in symbols: |
305 | for library, dependency in symbols: |
306 | self.insert_new_library( |
307 | source_package_name, library, dependency) |
308 | - self._sqlite.commit() |
309 | + self._store.commit() |
310 | |
311 | |
312 | def main(source_package_name): |
313 | |
314 | === modified file 'devportalbinary/testing.py' |
315 | --- devportalbinary/testing.py 2011-10-24 22:01:46 +0000 |
316 | +++ devportalbinary/testing.py 2011-12-05 21:01:26 +0000 |
317 | @@ -17,7 +17,28 @@ |
318 | |
319 | def setUp(self): |
320 | super(DatabaseFixture, self).setUp() |
321 | + # Set a temporary homedir so that any config on the user's |
322 | + # machine isn't picked up and the environment variable is used |
323 | + # instead. |
324 | + self.useFixture(TempHomeDirFixture()) |
325 | tempdir = self.useFixture(TempDir()) |
326 | db_path = os.path.join(tempdir.path, 'test-db') |
327 | - self.useFixture(EnvironmentVariableFixture(PackageDatabase.ENV_VAR, db_path)) |
328 | - self.db = PackageDatabase.create(db_path) |
329 | + config_file_path = os.path.expanduser(PackageDatabase.CONF_FILE) |
330 | + os.makedirs(os.path.dirname(config_file_path)) |
331 | + with open(config_file_path, 'w') as f: |
332 | + f.write('[database]\ndb_type=sqlite\npath=%s\n' % db_path) |
333 | + self.db = PackageDatabase.create() |
334 | + |
335 | + |
336 | +class TempHomeDirFixture(Fixture): |
337 | + """Create a temp directory and set it as $HOME. |
338 | + |
339 | + This provides a known environment for any test that uses |
340 | + $HOME. |
341 | + """ |
342 | + |
343 | + def setUp(self): |
344 | + super(TempHomeDirFixture, self).setUp() |
345 | + tempdir = self.useFixture(TempDir()) |
346 | + self.path = tempdir.path |
347 | + self.useFixture(EnvironmentVariableFixture("HOME", self.path)) |
348 | |
349 | === modified file 'devportalbinary/tests/test_database.py' |
350 | --- devportalbinary/tests/test_database.py 2011-10-24 21:48:58 +0000 |
351 | +++ devportalbinary/tests/test_database.py 2011-12-05 21:01:26 +0000 |
352 | @@ -6,6 +6,7 @@ |
353 | TempDir, |
354 | ) |
355 | from pkgme.testing import PathExists |
356 | +from storm.locals import create_database, Store |
357 | from testtools import TestCase |
358 | from testtools.matchers import ( |
359 | Equals, |
360 | @@ -13,6 +14,7 @@ |
361 | ) |
362 | |
363 | from devportalbinary.database import PackageDatabase |
364 | +from devportalbinary.testing import TempHomeDirFixture |
365 | |
366 | |
367 | class ResultsIn(Matcher): |
368 | @@ -23,55 +25,62 @@ |
369 | |
370 | def match(self, query): |
371 | # XXX: Abstraction violation |
372 | - c = self._db._sqlite.cursor() |
373 | - c.execute(query) |
374 | - results = list(c) |
375 | - return Equals(self._rows).match(results) |
376 | + results = self._db._store.execute(query) |
377 | + return Equals(self._rows).match(list(results)) |
378 | |
379 | |
380 | class TestDatabase(TestCase): |
381 | |
382 | + def setUp(self): |
383 | + super(TestDatabase, self).setUp() |
384 | + self.home_dir = self.useFixture(TempHomeDirFixture()) |
385 | + |
386 | + def get_package_db(self): |
387 | + database = create_database('sqlite:') |
388 | + store = Store(database) |
389 | + return PackageDatabase.create(store, store_type=PackageDatabase.SQLITE) |
390 | + |
391 | def test_insert_new_library(self): |
392 | - db = PackageDatabase.create(':memory:') |
393 | + db = self.get_package_db() |
394 | db.insert_new_library('foo-src', 'libfoo.so.0', 'foo') |
395 | self.assertThat( |
396 | "SELECT source_package_name, library, dependency FROM libdep", |
397 | ResultsIn(db, [('foo-src', 'libfoo.so.0', 'foo')])) |
398 | |
399 | def test_double_insert(self): |
400 | - db = PackageDatabase.create(':memory:') |
401 | + db = self.get_package_db() |
402 | db.insert_new_library('foo-src', 'libfoo.so.0', 'foo') |
403 | self.assertRaises( |
404 | IntegrityError, |
405 | db.insert_new_library, 'foo-src', 'libfoo.so.0', 'foo') |
406 | |
407 | def test_differing_dependencies(self): |
408 | - db = PackageDatabase.create(':memory:') |
409 | + db = self.get_package_db() |
410 | db.insert_new_library('foo-src', 'libfoo.so.0', 'foo') |
411 | db.insert_new_library('foo-src', 'libfoo.so.0', 'bar') |
412 | deps = db.get_dependencies('libfoo.so.0') |
413 | self.assertEqual(deps, set(['foo', 'bar'])) |
414 | |
415 | def test_get_dependencies(self): |
416 | - db = PackageDatabase.create(':memory:') |
417 | + db = self.get_package_db() |
418 | db.insert_new_library('foo-src', 'libfoo.so.0', 'foo') |
419 | deps = db.get_dependencies('libfoo.so.0') |
420 | self.assertEqual(deps, set(['foo'])) |
421 | |
422 | def test_unknown_library(self): |
423 | - db = PackageDatabase.create(':memory:') |
424 | + db = self.get_package_db() |
425 | deps = db.get_dependencies('libfoo.so.0') |
426 | self.assertEqual(deps, set()) |
427 | |
428 | def test_update_source_package(self): |
429 | - db = PackageDatabase.create(':memory:') |
430 | + db = self.get_package_db() |
431 | db.update_source_package( |
432 | 'foo', [[('libfoo.so.1', 'foo-bin')]]) |
433 | deps = db.get_dependencies('libfoo.so.1') |
434 | self.assertEqual(deps, set(['foo-bin'])) |
435 | |
436 | def test_update_existing_source_package_no_libraries(self): |
437 | - db = PackageDatabase.create(':memory:') |
438 | + db = self.get_package_db() |
439 | db.update_source_package('foo', [[('libfoo.so.1', 'foo-bin')]]) |
440 | # Run again, this time with no symbols, representing that a newer |
441 | # version of the package no longer exports any libraries. |
442 | @@ -79,7 +88,24 @@ |
443 | deps = db.get_dependencies('libfoo.so.1') |
444 | self.assertEqual(deps, set()) |
445 | |
446 | + def write_database_config(self, **kwargs): |
447 | + config_path = os.path.expanduser(PackageDatabase.CONF_FILE) |
448 | + os.makedirs(os.path.dirname(config_path)) |
449 | + with open(config_path, 'w') as f: |
450 | + f.write("[database]\n") |
451 | + for key, value in kwargs.items(): |
452 | + f.write("%s=%s\n" % (key, value)) |
453 | + |
454 | + def test_get_db_info_from_config_sqlite(self): |
455 | + other_tempdir = self.useFixture(TempDir()) |
456 | + expected_db_path = os.path.join(other_tempdir.path, 'db') |
457 | + self.write_database_config(db_type='sqlite', path=expected_db_path) |
458 | + connection_string, store_type = PackageDatabase.get_db_info_from_config() |
459 | + self.assertEqual('sqlite', store_type) |
460 | + self.assertEqual('sqlite:%s' % expected_db_path, connection_string) |
461 | + |
462 | def test_default_create_from_env_var_db(self): |
463 | + self.useFixture(TempHomeDirFixture()) |
464 | tempdir = self.useFixture(TempDir()) |
465 | db_path = os.path.join(tempdir.path, 'db') |
466 | self.useFixture( |
467 | @@ -88,6 +114,21 @@ |
468 | self.assertThat(db_path, PathExists()) |
469 | |
470 | def test_default_create_no_env_var_db_set(self): |
471 | + self.useFixture(TempHomeDirFixture()) |
472 | self.useFixture( |
473 | EnvironmentVariableFixture(PackageDatabase.ENV_VAR, None)) |
474 | self.assertRaises(ValueError, PackageDatabase.create) |
475 | + |
476 | + def test_get_db_info_from_config_postgres(self): |
477 | + expected_username = self.getUniqueString() |
478 | + expected_password = self.getUniqueString() |
479 | + expected_host = self.getUniqueString() |
480 | + expected_port = self.getUniqueString() |
481 | + self.write_database_config(db_type='postgres', |
482 | + username=expected_username, password=expected_password, |
483 | + host=expected_host, port=expected_port) |
484 | + connection_string, store_type = PackageDatabase.get_db_info_from_config() |
485 | + self.assertEqual('postgres', store_type) |
486 | + expected_connection_string = "postgres://%s:%s@%s:%s/pkgme_binary_dependencies" % ( |
487 | + expected_username, expected_password, expected_host, expected_port) |
488 | + self.assertEqual(expected_connection_string, connection_string) |
489 | |
490 | === modified file 'setup.py' |
491 | --- setup.py 2011-11-23 12:17:04 +0000 |
492 | +++ setup.py 2011-12-05 21:01:26 +0000 |
493 | @@ -27,8 +27,10 @@ |
494 | test_suite='devportalbinary.tests', |
495 | install_requires = [ |
496 | 'bzr', |
497 | + 'configglue', |
498 | 'launchpadlib', |
499 | 'pkgme', |
500 | + 'storm', |
501 | ], |
502 | entry_points = { |
503 | 'console_scripts': [ |
On Mon, Dec 5, 2011 at 9:02 PM, James Westby <email address hidden> wrote: /code.launchpad .net/~james- w/pkgme- binary/ stormify/ +merge/ 84529 /code.launchpad .net/~james- w/pkgme- binary/ stormify/ +merge/ 84529
> James Westby has proposed merging lp:~james-w/pkgme-binary/stormify into lp:pkgme-binary.
>
> Requested reviews:
> pkgme binary committers (pkgme-binary-dev)
>
> For more details, see:
> https:/
>
> Hi,
>
> This branch stormifies the code, in order to support postgres as well
> as sqlite.
>
> It's not the prettiest thing ever, and the postgres code is under-tested, but
> I didn't want to deal with using a postgres fixture.
>
> The unicode() changes are so that postgres types match up, and should be
> fine as package names and library file names are (have to be?) ascii.
>
> Thanks,
>
> James
>
> --
> https:/
> Your team pkgme binary committers is requested to review the proposed merge of lp:~james-w/pkgme-binary/stormify into lp:pkgme-binary.
>
> === modified file 'README'
> --- README 2011-11-21 16:19:48 +0000
> +++ README 2011-12-05 21:01:26 +0000
> @@ -6,6 +6,9 @@
...
These changes are much appreciated.
> === modified file 'devportalbinar y/database. py' /database. py 2011-10-25 16:45:08 +0000 /database. py 2011-12-05 21:01:26 +0000 source_ package( source_ package_ name, symbols) (schema. Schema) : schema. Section) : StringOption( default= 'sqlite' , StringOption( StringOption( StringOption( StringOption( StringOption( (object) : LIB_DEPS_ DB_PATH'
> --- devportalbinary
> +++ devportalbinary
...
> @@ -201,38 +201,129 @@
> db.update_
>
>
> +class PackageDBSchema
> +
> + class database(
> + db_type = schema.
> + help=('The database to use, one of "sqlite", or "postgres"'))
> + host = schema.
> + help='The database host (for postgres)')
> + port = schema.
> + help='The database port (for postgres)')
> + username = schema.
> + help='The database username (for postgres)')
> + password = schema.
> + help='The database password (for postgres)')
> + path = schema.
> + help='The path to the database file (for sqlite)')
> +
> +
> class PackageDatabase
>
> + SQLITE = 'sqlite'
> + POSTGRES = 'postgres'
> +
> ENV_VAR = 'PKGME_
Why didn't you delete ENV_VAR?
> + CONF_FILE = '~/.config/ pkgme-binary/ conf' sqlite_ connection_ string( cls, opts): cls.ENV_ VAR] cls.ENV_ VAR] connect( sqlite_ path)
>
> - def __init__(self, sqlite_database):
> - self._sqlite = sqlite_database
> + def __init__(self, store):
> + self._store = store
>
> @classmethod
> - def create(cls, sqlite_path=None):
> - if sqlite_path is None:
> + def _get_storm_
> + if not opts.database_path:
> try:
> - sqlite_path = os.environ[
> + opts.database_path = os.environ[
> except KeyError:
> raise ValueError(
> "Cannot create database, no path given and %s not set"
> % (cls.ENV_VAR,))
> - c = sqlite3.
> - c.cursor().execute(
> - "CREATE TABLE IF NOT EXISTS libdep ("
> - "source_pac...