Merge lp:~mvo/pkgme-devportal/add-configuration-for-library-overrides into lp:pkgme-devportal

Proposed by Michael Vogt
Status: Merged
Approved by: Michael Vogt
Approved revision: 59
Merged at revision: 54
Proposed branch: lp:~mvo/pkgme-devportal/add-configuration-for-library-overrides
Merge into: lp:pkgme-devportal
Diff against target: 366 lines (+153/-64)
6 files modified
devportalbinary/binary.py (+10/-2)
devportalbinary/configuration.py (+69/-0)
devportalbinary/database.py (+1/-53)
devportalbinary/testing.py (+35/-1)
devportalbinary/tests/test_binary.py (+32/-1)
devportalbinary/tests/test_database.py (+6/-7)
To merge this branch: bzr merge lp:~mvo/pkgme-devportal/add-configuration-for-library-overrides
Reviewer Review Type Date Requested Status
James Westby Approve
Michael Vogt (community) Needs Resubmitting
Jonathan Lange Approve
Review via email: mp+115125@code.launchpad.net

Commit message

Allow configuring overrides for the lib->package mapping.

Description of the change

This branch provides a way to override library dependencies. The background for this is bug #1025186. Often a library is provided by multiple alternative versions that can not be co-installed. Common cases are libgl1-mesa-{glx,swx11}. To catch them a simple override mechanism is provided.

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

 * Really like splitting 'configuration' into a different module. Thanks.
 * ``write_config`` should probably be a Fixture that just sets the config. Not necessary to change in this branch, but if you're feeling
 * I would have thought that the config should be '<library>: <recommended package>'. I don't know if I'm right or you're right or even if the patch should be changed at this point in the absence of data. Probably OK to merge.
 * There really ought to be an example configuration that shows this
 * We're probably going to want a web control for this. Pinging LOSAs every time we want to add something is going to suck.

review: Approve
Revision history for this message
James Westby (james-w) wrote :

Hi,

I had the same instinct as jml with the '<library>: <recommended package>' config (making it a set of recommended packages to match the API though). It seems overly broad to do the search, and the dict would likely be quicker
if there were a lot of overrides.

I'm also unsure that a config is the right thing for this, becuase aren't the overrides going
to be the same for everyone everywhere? I guess not, and it's hard to know what will happen, so
let's go with this.

I'm for this landing quickly, but I think because changing the config would be tricky because
of backwards compatibility we should change it to do the dict method rather than the search
method before landing. What do you think?

Thanks,

James

Revision history for this message
Michael Vogt (mvo) wrote :

Thanks to both of you, I like the idea(s) and will change the config format. I'm unsure about the config too TBH, but it seems like guessing on some heuristics is not better so until we find a better solution having a override is probably ok(ish).

I will not address the "add-webinterface" for now as this should be a seperate branch :)

Revision history for this message
Michael Vogt (mvo) wrote :

I addressed the above points one (except for the webinterface). I hope this is in line with what you have in mind, I'm happy to refactor further if needed :)

review: Needs Resubmitting
Revision history for this message
James Westby (james-w) :
review: Approve
Revision history for this message
Canonical CA Tarmac (ca-tarmac) wrote :
Download full text (5.1 KiB)

The attempt to merge lp:~mvo/pkgme-devportal/add-configuration-for-library-overrides into lp:pkgme-devportal failed. Below is the output from the failed tests.

Downloading/unpacking mock (from -r test-dependencies.txt (line 1))
  Running setup.py egg_info for package mock
    warning: no files found matching '*.png' under directory 'docs'
    warning: no files found matching '*.css' under directory 'docs'
    warning: no files found matching '*.html' under directory 'docs'
    warning: no files found matching '*.js' under directory 'docs'
Installing collected packages: mock
  Running setup.py install for mock
    warning: no files found matching '*.png' under directory 'docs'
    warning: no files found matching '*.css' under directory 'docs'
    warning: no files found matching '*.html' under directory 'docs'
    warning: no files found matching '*.js' under directory 'docs'
Successfully installed mock
Cleaning up...
Tests running...
======================================================================
ERROR: tests.test_binary.BinaryBackendTests.test_config_glue_lib_overrides
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mnt/tarmac-tmp/tmp4oMKa_/devportalbinary/tests/test_binary.py", line 305, in test_config_glue_lib_overrides
    self.useFixture(ConfigFileFixture())
  File "/mnt/tarmac-tmp/tmp4oMKa_/virtualenv/lib/python2.6/site-packages/testtools-0.9.15-py2.6.egg/testtools/testcase.py", line 579, in useFixture
    fixture.setUp()
  File "devportalbinary/testing.py", line 126, in setUp
    with open(CONF_FILE, 'w') as f:
IOError: [Errno 2] No such file or directory: '~/.config/pkgme-binary/conf'
======================================================================
ERROR: discover.ModuleImportFailure.testing
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mnt/tarmac-tmp/tmp4oMKa_/virtualenv/lib/python2.6/site-packages/discover.py", line 64, in testFailure
    raise exception
ImportError: Failed to import test module: testing
Traceback (most recent call last):
  File "/mnt/tarmac-tmp/tmp4oMKa_/virtualenv/lib/python2.6/site-packages/discover.py", line 288, in _find_tests
    module = self._get_module_from_name(name)
  File "/mnt/tarmac-tmp/tmp4oMKa_/virtualenv/lib/python2.6/site-packages/discover.py", line 266, in _get_module_from_name
    __import__(name)
  File "/mnt/tarmac-tmp/tmp4oMKa_/devportalbinary/testing.py", line 30, in <module>
    from .configuration import CONF_FILE
ValueError: Attempted relative import in non-package

Ran 115 tests in 0.384s
FAILED (failures=2)

Branched 118 revision(s).
/mnt/tarmac-tmp/tmp4oMKa_/virtualenv/lib/python2.6/site-packages/distribute-0.6.10-py2.6.egg/setuptools/command/bdist_egg.py:422: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
  symbols = dict.fromkeys(iter_symbols(code))
simplejson/_speedups.c: In function 'encoder_listencode_obj':
simplejson/_speedups.c:2269: warning: comparison of distinct pointer types lacks a cast
simplejson/_speedups.c:2269: warning: passing argument 2 of 'PyTyp...

Read more...

58. By Michael Vogt

devportalbinary/testing.py: do not use relative import (tarmac is on py2.6 apparently)

59. By Michael Vogt

devportalbinary/testing.py: add os.path.expanduser() to fix tarmac failure

Revision history for this message
Michael Vogt (mvo) wrote :

Setting back to approved to let tarmac try again.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'devportalbinary/binary.py'
2--- devportalbinary/binary.py 2012-03-28 16:34:58 +0000
3+++ devportalbinary/binary.py 2012-07-16 18:51:18 +0000
4@@ -40,11 +40,11 @@
5 from pkgme.errors import PkgmeError
6 from pkgme.run_script import run_subprocess
7
8+from devportalbinary.configuration import load_configuration
9 from devportalbinary.database import PackageDatabase
10 from devportalbinary.metadata import MetadataBackend
11
12
13-
14 # XXX: No idea about how icons will be there. Ignoring for now.
15
16
17@@ -160,10 +160,18 @@
18
19
20 def get_packages_for_libraries(library_names, arch):
21+ conf = load_configuration()
22+ lib_overrides = conf.options.lib_overrides_overrides
23 db = PackageDatabase.create()
24 deps = set()
25 for lib in library_names:
26- new_deps = db.get_dependencies(lib)
27+ # ensure that overrides always "trump" the existing set if they
28+ # are found
29+ if lib in lib_overrides:
30+ new_deps = set([lib_overrides[lib]])
31+ else:
32+ new_deps = db.get_dependencies(lib)
33+
34 if not new_deps:
35 raise UnknownDependency('Can\'t find dependency for "%s".' % lib)
36 deps |= new_deps
37
38=== added file 'devportalbinary/configuration.py'
39--- devportalbinary/configuration.py 1970-01-01 00:00:00 +0000
40+++ devportalbinary/configuration.py 2012-07-16 18:51:18 +0000
41@@ -0,0 +1,69 @@
42+import os
43+
44+try:
45+ from configglue import glue
46+except ImportError:
47+ from configglue.pyschema import glue
48+
49+try:
50+ from configglue.schema import (
51+ Schema,
52+ Section,
53+ DictOption,
54+ StringOption,
55+ )
56+except ImportError:
57+ from configglue.pyschema.schema import (
58+ Schema,
59+ ConfigSection as Section,
60+ DictConfigOption as DictOption,
61+ StringConfigOption as StringOption,
62+ )
63+
64+
65+# XXX: 'pkgme-binary' is the historic name of this package. Change this
66+# to look first in ~/.config/pkgme-devportal/conf and then fall back to
67+# this one. Once production systems are updated to the new config, remove
68+# the fallback.
69+CONF_FILE = '~/.config/pkgme-binary/conf'
70+
71+
72+class DevportalSchema(Schema):
73+
74+ # database
75+ database = Section()
76+ database.db_type = StringOption(default='sqlite',
77+ help=('The database to use, one of "sqlite", or "postgres"'))
78+ database.host = StringOption(
79+ help='The database host (for postgres)')
80+ database.port = StringOption(
81+ help='The database port (for postgres)')
82+ database.username = StringOption(
83+ help='The database username (for postgres)')
84+ database.password = StringOption(
85+ help='The database password (for postgres)')
86+ database.db_name = StringOption(
87+ help='The database name (for postgres)')
88+ database.path = StringOption(
89+ help='The path to the database file (for sqlite)')
90+
91+ scan_mode = StringOption(
92+ help='To scan binary or source packages.')
93+
94+ # overrides
95+ lib_overrides = Section()
96+ overrides = { 'libasound.so.2': 'libasound2',
97+ 'libgl.so.1': 'libgl1-mesa-glx',
98+ }
99+ lib_overrides.overrides = DictOption(
100+ default=overrides,
101+ help='mapping of library name to pkgname to force picking selected '
102+ 'dependencies')
103+
104+
105+def load_configuration():
106+ config_location = os.path.expanduser(CONF_FILE)
107+ config_files = []
108+ if os.path.exists(config_location):
109+ config_files.append(config_location)
110+ return glue.configglue(DevportalSchema, config_files)
111
112=== modified file 'devportalbinary/database.py'
113--- devportalbinary/database.py 2012-04-26 12:10:00 +0000
114+++ devportalbinary/database.py 2012-07-16 18:51:18 +0000
115@@ -8,23 +8,6 @@
116 import tempfile
117
118 from bzrlib import urlutils
119-try:
120- from configglue import glue
121-except ImportError:
122- from configglue.pyschema import glue
123-
124-try:
125- from configglue.schema import (
126- Schema,
127- Section,
128- StringOption,
129- )
130-except ImportError:
131- from configglue.pyschema.schema import (
132- Schema,
133- ConfigSection as Section,
134- StringConfigOption as StringOption,
135- )
136 from fixtures import (
137 Fixture,
138 TempDir,
139@@ -37,6 +20,7 @@
140 from pkgme.run_script import run_subprocess
141 from storm.locals import create_database, Store
142
143+from .configuration import load_configuration
144 from .utils import download_file
145
146
147@@ -274,47 +258,11 @@
148 yield library, dependency
149
150
151-class PackageDBSchema(Schema):
152-
153- database = Section()
154- database.db_type = StringOption(default='sqlite',
155- help=('The database to use, one of "sqlite", or "postgres"'))
156- database.host = StringOption(
157- help='The database host (for postgres)')
158- database.port = StringOption(
159- help='The database port (for postgres)')
160- database.username = StringOption(
161- help='The database username (for postgres)')
162- database.password = StringOption(
163- help='The database password (for postgres)')
164- database.db_name = StringOption(
165- help='The database name (for postgres)')
166- database.path = StringOption(
167- help='The path to the database file (for sqlite)')
168-
169- scan_mode = StringOption(
170- help='To scan binary or source packages.')
171-
172-
173-def load_configuration():
174- config_location = os.path.expanduser(PackageDatabase.CONF_FILE)
175- config_files = []
176- if os.path.exists(config_location):
177- config_files.append(config_location)
178- return glue.configglue(PackageDBSchema, config_files)
179-
180-
181 class PackageDatabase(object):
182
183 SQLITE = 'sqlite'
184 POSTGRES = 'postgres'
185
186- # XXX: 'pkgme-binary' is the historic name of this package. Change this
187- # to look first in ~/.config/pkgme-devportal/conf and then fall back to
188- # this one. Once production systems are updated to the new config, remove
189- # the fallback.
190- CONF_FILE = '~/.config/pkgme-binary/conf'
191-
192 def __init__(self, store):
193 self._store = store
194
195
196=== modified file 'devportalbinary/testing.py'
197--- devportalbinary/testing.py 2012-07-05 07:11:28 +0000
198+++ devportalbinary/testing.py 2012-07-16 18:51:18 +0000
199@@ -27,6 +27,8 @@
200 from devportalbinary.binary import MetadataBackend
201 from devportalbinary.database import PackageDatabase
202
203+from devportalbinary.configuration import CONF_FILE
204+
205 class IsChildPath(Matcher):
206
207 def __init__(self, parent_path):
208@@ -86,7 +88,7 @@
209 self.useFixture(TempHomeDirFixture())
210 tempdir = self.useFixture(TempDir())
211 db_path = os.path.join(tempdir.path, 'test-db')
212- config_file_path = os.path.expanduser(PackageDatabase.CONF_FILE)
213+ config_file_path = os.path.expanduser(CONF_FILE)
214 os.makedirs(os.path.dirname(config_file_path))
215 with open(config_file_path, 'w') as f:
216 f.write('[database]\ndb_type=sqlite\npath=%s\n' % db_path)
217@@ -107,6 +109,28 @@
218 self.useFixture(EnvironmentVariableFixture("HOME", self.path))
219
220
221+class ConfigFileFixture(TempHomeDirFixture):
222+ """Create a lib_overrides config file.
223+
224+ This also provides a example for the [lib_overrides] section syntax
225+ """
226+
227+ # for the test, needs to be in sync with the config file below
228+ TEST_LIBS = { 'libasound.so.2' : 'libasound2',
229+ 'libgl.so.1' : 'libgl1-mesa-glx',
230+ }
231+
232+ def setUp(self):
233+ super(ConfigFileFixture, self).setUp()
234+ os.makedirs(os.path.dirname(os.path.expanduser(CONF_FILE)))
235+ with open(os.path.expanduser(CONF_FILE), 'w') as f:
236+ f.write("""
237+[lib_overrides]
238+libasound.so.2 = libasound2
239+libgl1.so.1 = libglx-mesa-dri
240+""")
241+
242+
243 class MetadataFixture(Fixture):
244 """Create a metadata file to use.
245
246@@ -188,3 +212,13 @@
247 if path is None:
248 path = self.useFixture(TempdirFixture()).path
249 return self.BACKEND(path)
250+
251+
252+def write_config(conf_file, conf_key, **kwargs):
253+ config_path = os.path.expanduser(conf_file)
254+ if not os.path.isdir(os.path.dirname(config_path)):
255+ os.makedirs(os.path.dirname(config_path))
256+ with open(config_path, 'w') as f:
257+ f.write("[%s]\n" % conf_key)
258+ for key, value in kwargs.items():
259+ f.write("%s=%s\n" % (key, value))
260
261=== modified file 'devportalbinary/tests/test_binary.py'
262--- devportalbinary/tests/test_binary.py 2012-03-16 14:08:44 +0000
263+++ devportalbinary/tests/test_binary.py 2012-07-16 18:51:18 +0000
264@@ -1,18 +1,22 @@
265 # Copyright 2011-2012 Canonical Ltd. This software is licensed under the
266 # GNU Affero General Public License version 3 (see the file LICENSE).
267
268+import json
269 import os
270 import shutil
271
272 from testtools import TestCase
273 from testtools.matchers import StartsWith
274
275-from pkgme.testing import TempdirFixture
276+from pkgme.testing import (
277+ TempdirFixture,
278+ )
279
280 from devportalbinary.binary import (
281 BinaryBackend,
282 get_file_type,
283 get_file_types,
284+ get_packages_for_libraries,
285 get_shared_library_dependencies,
286 guess_dependencies,
287 guess_executable,
288@@ -22,16 +26,23 @@
289 NoBinariesFound,
290 UnknownDependency,
291 )
292+from devportalbinary.configuration import (
293+ CONF_FILE,
294+ load_configuration,
295+ )
296 from devportalbinary.metadata import (
297 MetadataBackend,
298 )
299 from devportalbinary.testing import (
300 BackendTests,
301 BinaryFileFixture,
302+ ConfigFileFixture,
303 DatabaseFixture,
304 get_test_data_dir_path,
305 get_test_data_file_path,
306 MetadataFixture,
307+ TempHomeDirFixture,
308+ write_config,
309 )
310
311
312@@ -288,3 +299,23 @@
313 self.assertEqual(
314 '/opt/%s/the-best' % (package_name,),
315 backend.get_executable(package_name))
316+
317+ def test_config_glue_lib_overrides(self):
318+ # XXX: this needs to be in sync with testing.py:ConfigFileFixture
319+ self.useFixture(ConfigFileFixture())
320+ conf = load_configuration()
321+ self.assertEqual(
322+ conf.options.lib_overrides_overrides, ConfigFileFixture.TEST_LIBS)
323+
324+ def test_get_lib_overrides_for_packages_for_libraries(self):
325+ """Test that the configuration file overrides the found
326+ library dependencies
327+ """
328+ db = self.useFixture(DatabaseFixture()).db
329+ db.update_source_package('foo', [
330+ [('libasound.so.2', 'libfoo')],
331+ [('libasound.so.2', 'libbar')],
332+ ])
333+ self.assertEqual(
334+ get_packages_for_libraries(["libasound.so.2"], "i386"),
335+ set(["libasound2"]))
336
337=== modified file 'devportalbinary/tests/test_database.py'
338--- devportalbinary/tests/test_database.py 2012-01-20 16:17:16 +0000
339+++ devportalbinary/tests/test_database.py 2012-07-16 18:51:18 +0000
340@@ -17,7 +17,11 @@
341 load_configuration,
342 PackageDatabase,
343 )
344-from devportalbinary.testing import TempHomeDirFixture
345+from devportalbinary.configuration import CONF_FILE
346+from devportalbinary.testing import (
347+ TempHomeDirFixture,
348+ write_config,
349+ )
350
351
352 class ResultsIn(Matcher):
353@@ -92,12 +96,7 @@
354 self.assertEqual(deps, set())
355
356 def write_database_config(self, **kwargs):
357- config_path = os.path.expanduser(PackageDatabase.CONF_FILE)
358- os.makedirs(os.path.dirname(config_path))
359- with open(config_path, 'w') as f:
360- f.write("[database]\n")
361- for key, value in kwargs.items():
362- f.write("%s=%s\n" % (key, value))
363+ write_config(CONF_FILE, "database", **kwargs)
364
365 def test_get_db_info_from_config_sqlite(self):
366 other_tempdir = self.useFixture(TempDir())

Subscribers

People subscribed via source and target branches