Merge lp:~frankban/juju-quickstart/jujubundlelib into lp:juju-quickstart
- jujubundlelib
- Merge into trunk
Proposed by
Francesco Banconi
Status: | Merged |
---|---|
Merged at revision: | 125 |
Proposed branch: | lp:~frankban/juju-quickstart/jujubundlelib |
Merge into: | lp:juju-quickstart |
Diff against target: |
908 lines (+27/-639) 13 files modified
quickstart/app.py (+1/-1) quickstart/charmstore.py (+3/-3) quickstart/jujutools.py (+5/-4) quickstart/manage.py (+2/-1) quickstart/models/bundles.py (+4/-3) quickstart/models/references.py (+0/-215) quickstart/tests/models/test_bundles.py (+2/-4) quickstart/tests/models/test_references.py (+0/-400) quickstart/tests/test_app.py (+2/-4) quickstart/tests/test_charmstore.py (+2/-2) quickstart/tests/test_jujutools.py (+1/-1) quickstart/tests/test_manage.py (+1/-1) tox.ini (+4/-0) |
To merge this branch: | bzr merge lp:~frankban/juju-quickstart/jujubundlelib |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email: mp+256906@code.launchpad.net |
Commit message
Description of the change
Introduce jujubundlelib dependency.
Use the Reference model defined there.
To post a comment you must log in.
Revision history for this message
Francesco Banconi (frankban) wrote : | # |
Revision history for this message
Madison Scott-Clary (makyo) wrote : | # |
LGTM, thanks for the work - we'll need to update tox.ini with versions
as tasks shake out from jujubundlelib, but that's fine.
Revision history for this message
Francesco Banconi (frankban) wrote : | # |
On 2015/04/22 15:34:12, matthew.scott wrote:
> LGTM, thanks for the work - we'll need to update tox.ini with versions
as tasks
> shake out from jujubundlelib, but that's fine.
Indeed, I'll update the bundlelib version in follow up branches.
Thanks for the review Madison!
Revision history for this message
Francesco Banconi (frankban) wrote : | # |
*** Submitted:
Introduce jujubundlelib dependency.
Use the Reference model defined there.
R=matthew.scott
CC=
https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'quickstart/app.py' |
2 | --- quickstart/app.py 2015-03-09 17:50:28 +0000 |
3 | +++ quickstart/app.py 2015-04-21 10:32:19 +0000 |
4 | @@ -411,7 +411,7 @@ |
5 | Return a tuple including the following values: |
6 | - charm_ref: the entity reference of the charm that will be used to |
7 | deploy the service, as an instance of |
8 | - "quickstart.models.references.Reference"; |
9 | + "jujubundlelib.references.Reference"; |
10 | - machine: the machine where to deploy to (e.g. "0") or None if a new |
11 | machine must be created; |
12 | - service_data: the service info as returned by the mega-watcher for |
13 | |
14 | === modified file 'quickstart/charmstore.py' |
15 | --- quickstart/charmstore.py 2015-03-10 10:18:58 +0000 |
16 | +++ quickstart/charmstore.py 2015-04-21 10:32:19 +0000 |
17 | @@ -59,7 +59,7 @@ |
18 | """Retrieve the charm store contents for the given reference and path. |
19 | |
20 | The reference argument identifies a charm or bundle entity and must be an |
21 | - instance of "quickstart.models.references.Reference". |
22 | + instance of "jujubundlelib.references.Reference". |
23 | |
24 | For instance, to retrieve the hash of a charm reference, use the following: |
25 | |
26 | @@ -101,7 +101,7 @@ |
27 | |
28 | The bundle data is returned as a YAML decoded value. |
29 | The reference argument identifies a bundle entity and must be an instance |
30 | - of "quickstart.models.references.Reference". |
31 | + of "jujubundlelib.references.Reference". |
32 | |
33 | Raise a ValueError if the returned content is not a valid YAML, or if the |
34 | given reference does not represent a bundle. |
35 | @@ -119,7 +119,7 @@ |
36 | The bundle data is returned as a YAML decoded value and represents the |
37 | legacy bundle with a top level bundle name node. |
38 | The reference argument identifies a bundle entity and must be an instance |
39 | - of "quickstart.models.references.Reference". |
40 | + of "jujubundlelib.references.Reference". |
41 | |
42 | Raise a ValueError if the returned content is not a valid YAML, or if the |
43 | given reference does not represent a bundle. |
44 | |
45 | === modified file 'quickstart/jujutools.py' |
46 | --- quickstart/jujutools.py 2015-02-26 11:02:57 +0000 |
47 | +++ quickstart/jujutools.py 2015-04-21 10:32:19 +0000 |
48 | @@ -23,11 +23,12 @@ |
49 | |
50 | import logging |
51 | |
52 | +from jujubundlelib import references |
53 | + |
54 | from quickstart import ( |
55 | serializers, |
56 | settings, |
57 | ) |
58 | -from quickstart.models import references |
59 | |
60 | |
61 | def get_api_url( |
62 | @@ -40,8 +41,8 @@ |
63 | Optionally receive a prefix to be used in the path. |
64 | |
65 | Optionally also receive the Juju GUI charm reference as an instance of |
66 | - "quickstart.models.references.Reference". If provided, the function checks |
67 | - that the corresponding Juju GUI charm supports the new Juju API endpoint. |
68 | + "jujubundlelib.references.Reference". If provided, the function checks that |
69 | + the corresponding Juju GUI charm supports the new Juju API endpoint. |
70 | If not supported, the old endpoint is returned. |
71 | |
72 | The environment UUID can be None, in which case the old-style API URL |
73 | @@ -104,7 +105,7 @@ |
74 | Print (to stdout or to logs) info and warnings about the charm URL. |
75 | |
76 | Return the parsed charm reference object as an instance of |
77 | - "quickstart.models.references.Reference". |
78 | + "jujubundlelib.references.Reference". |
79 | """ |
80 | print('charm URL: {}'.format(charm_url)) |
81 | ref = references.Reference.from_fully_qualified_url(charm_url) |
82 | |
83 | === modified file 'quickstart/manage.py' |
84 | --- quickstart/manage.py 2015-03-09 18:53:52 +0000 |
85 | +++ quickstart/manage.py 2015-04-21 10:32:19 +0000 |
86 | @@ -28,6 +28,8 @@ |
87 | import sys |
88 | import webbrowser |
89 | |
90 | +from jujubundlelib import references |
91 | + |
92 | import quickstart |
93 | from quickstart import ( |
94 | app, |
95 | @@ -45,7 +47,6 @@ |
96 | bundles, |
97 | envs, |
98 | jenv, |
99 | - references, |
100 | ) |
101 | |
102 | |
103 | |
104 | === modified file 'quickstart/models/bundles.py' |
105 | --- quickstart/models/bundles.py 2015-03-10 13:13:42 +0000 |
106 | +++ quickstart/models/bundles.py 2015-04-21 10:32:19 +0000 |
107 | @@ -22,7 +22,7 @@ |
108 | |
109 | Published bundles are identified by a charm store id and by the corresponding |
110 | URL in jujucharms.com, just like regular charms. The reference object in |
111 | -"quickstart.models.references.Reference" can be used to identify a bundle. |
112 | +"jujubundlelib.references.Reference" can be used to identify a bundle. |
113 | |
114 | In this module, the Bundle class represents a bundle that may or may not have |
115 | a specific reference id. For instance, a reference is not set on a bundle if |
116 | @@ -46,13 +46,14 @@ |
117 | import os |
118 | import re |
119 | |
120 | +from jujubundlelib import references |
121 | + |
122 | from quickstart import ( |
123 | charmstore, |
124 | netutils, |
125 | serializers, |
126 | settings, |
127 | ) |
128 | -from quickstart.models import references |
129 | |
130 | |
131 | class Bundle(object): |
132 | @@ -63,7 +64,7 @@ |
133 | |
134 | The data argument is the bundle YAML decoded content. |
135 | An optional entity reference can be provided as an instance of |
136 | - "quickstart.models.references.Reference". |
137 | + "jujubundlelib.references.Reference". |
138 | """ |
139 | self.data = data |
140 | self.reference = reference |
141 | |
142 | === removed file 'quickstart/models/references.py' |
143 | --- quickstart/models/references.py 2015-03-06 17:55:40 +0000 |
144 | +++ quickstart/models/references.py 1970-01-01 00:00:00 +0000 |
145 | @@ -1,215 +0,0 @@ |
146 | -# This file is part of the Juju Quickstart Plugin, which lets users set up a |
147 | -# Juju environment in very few steps (https://launchpad.net/juju-quickstart). |
148 | -# Copyright (C) 2013 Canonical Ltd. |
149 | -# |
150 | -# This program is free software: you can redistribute it and/or modify it under |
151 | -# the terms of the GNU Affero General Public License version 3, as published by |
152 | -# the Free Software Foundation. |
153 | -# |
154 | -# This program is distributed in the hope that it will be useful, but WITHOUT |
155 | -# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
156 | -# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
157 | -# Affero General Public License for more details. |
158 | -# |
159 | -# You should have received a copy of the GNU Affero General Public License |
160 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
161 | - |
162 | -"""Juju Quickstart charm and bundle references management.""" |
163 | - |
164 | -from __future__ import unicode_literals |
165 | - |
166 | -import re |
167 | - |
168 | -from quickstart import settings |
169 | - |
170 | - |
171 | -# The following regular expressions are the same used in juju-core: see |
172 | -# http://bazaar.launchpad.net/~go-bot/juju-core/trunk/view/head:/charm/url.go. |
173 | -USER_PATTERN = r'[a-z0-9][a-zA-Z0-9+.-]+' |
174 | -SERIES_PATTERN = r'[a-z]+(?:[a-z-]+[a-z])?' |
175 | -NAME_PATTERN = r'[a-z][a-z0-9]*(?:-[a-z0-9]*[a-z][a-z0-9]*)*' |
176 | - |
177 | -# Define the callables used to check if entity reference components are valid. |
178 | -_valid_user = re.compile(r'^{}$'.format(USER_PATTERN)).match |
179 | -_valid_series = re.compile(r'^{}$'.format(SERIES_PATTERN)).match |
180 | -_valid_name = re.compile(r'^{}$'.format(NAME_PATTERN)).match |
181 | - |
182 | -# Compile the regular expression used to parse new jujucharms entity URLs. |
183 | -_jujucharms_url_expression = re.compile(r""" |
184 | - ^ # Beginning of the line. |
185 | - (?: |
186 | - (?:{jujucharms})? # Optional jujucharms.com URL. |
187 | - | |
188 | - /? # Optional leading slash. |
189 | - )? |
190 | - (?:u/({user_pattern})/)? # Optional user name. |
191 | - ({name_pattern}) # Bundle name. |
192 | - (?:/({series_pattern}))? # Optional series. |
193 | - (?:/(\d+))? # Optional bundle revision number. |
194 | - /? # Optional trailing slash. |
195 | - $ # End of the line. |
196 | -""".format( |
197 | - jujucharms=settings.JUJUCHARMS_URL, |
198 | - name_pattern=NAME_PATTERN, |
199 | - series_pattern=SERIES_PATTERN, |
200 | - user_pattern=USER_PATTERN, |
201 | -), re.VERBOSE) |
202 | - |
203 | - |
204 | -class Reference(object): |
205 | - """Represent a charm or bundle URL reference.""" |
206 | - |
207 | - def __init__(self, schema, user, series, name, revision): |
208 | - """Initialize the reference. Receives the URL fragments.""" |
209 | - self.schema = schema |
210 | - self.user = user |
211 | - self.series = series |
212 | - self.name = name |
213 | - if revision is not None: |
214 | - revision = int(revision) |
215 | - self.revision = revision |
216 | - # XXX frankban 2015-02-26: remove the following attribute when |
217 | - # switching to the new bundle format, and when we have a better way |
218 | - # to increase bundle deployments count. |
219 | - self.charmworld_id = None |
220 | - |
221 | - @classmethod |
222 | - def from_fully_qualified_url(cls, url): |
223 | - """Given an entity URL as a string, create and return a Reference. |
224 | - |
225 | - Fully qualified URLs represent the regular entity reference |
226 | - representation in Juju, e.g.: "cs:`~who/vivid/django-42" or |
227 | - "local:bundle/wordpress-0". |
228 | - |
229 | - Raise a ValueError if the provided value is not a valid and fully |
230 | - qualified URL, also including the schema and the revision. |
231 | - """ |
232 | - return cls(*_parse_fully_qualified_url(url)) |
233 | - |
234 | - @classmethod |
235 | - def from_jujucharms_url(cls, url): |
236 | - """Create and return a Reference from the given jujucharms.com URL. |
237 | - |
238 | - These are the preferred way to refer to a charm or bundle in Juju |
239 | - Quickstart. They basically look like the URL paths in jujucharms.com, |
240 | - e.g. "u/who/django", "mediawiki/42" or just "mediawiki". The full HTTP |
241 | - URL can be also provided, for instance "https://jujucharms.com/django". |
242 | - |
243 | - Raise a ValueError if the provided URL is not valid. |
244 | - """ |
245 | - match = _jujucharms_url_expression.match(url) |
246 | - if match is None: |
247 | - msg = 'invalid bundle URL: {}'.format(url) |
248 | - raise ValueError(msg.encode('utf-8')) |
249 | - user, name, series, revision = match.groups() |
250 | - return cls('cs', user, series or 'bundle', name, revision) |
251 | - |
252 | - def __str__(self): |
253 | - """The string representation of a reference is its URL string.""" |
254 | - return self.__unicode__().encode('utf-8') |
255 | - |
256 | - def __unicode__(self): |
257 | - """The unicode representation of a reference is its URL string.""" |
258 | - return self.id() |
259 | - |
260 | - def __repr__(self): |
261 | - return b'<Reference: {}>'.format(bytes(self)) |
262 | - |
263 | - def __eq__(self, other): |
264 | - """Two refs are equal if they have the same string representation.""" |
265 | - return isinstance(other, self.__class__) and self.id() == other.id() |
266 | - |
267 | - def path(self): |
268 | - """Return the reference as a string without the schema.""" |
269 | - user_part = '~{}/'.format(self.user) if self.user else '' |
270 | - revision_part = '' |
271 | - if self.revision is not None: |
272 | - revision_part = '-{}'.format(self.revision) |
273 | - return '{}{}/{}{}'.format( |
274 | - user_part, self.series, self.name, revision_part) |
275 | - |
276 | - def id(self): |
277 | - """Return the reference URL as a string.""" |
278 | - return '{}:{}'.format(self.schema, self.path()) |
279 | - |
280 | - def jujucharms_id(self): |
281 | - """Return the identifier of this reference in jujucharms.com.""" |
282 | - user_part = 'u/{}/'.format(self.user) if self.user else '' |
283 | - series_part = '' if self.is_bundle() else '/{}'.format(self.series) |
284 | - revision_part = '' |
285 | - if self.revision is not None: |
286 | - revision_part = '/{}'.format(self.revision) |
287 | - return '{}{}{}{}'.format( |
288 | - user_part, self.name, series_part, revision_part) |
289 | - |
290 | - def jujucharms_url(self): |
291 | - """Return the URL where this entity lives in jujucharms.com.""" |
292 | - return settings.JUJUCHARMS_URL + self.jujucharms_id() |
293 | - |
294 | - def is_bundle(self): |
295 | - """Report whether this reference refers to a bundle entity.""" |
296 | - return self.series == 'bundle' |
297 | - |
298 | - def is_local(self): |
299 | - """Return True if this refers to a local entity, False otherwise.""" |
300 | - return self.schema == 'local' |
301 | - |
302 | - |
303 | -def _parse_fully_qualified_url(url): |
304 | - """Parse the given charm or bundle URL, provided as a string. |
305 | - |
306 | - Return a tuple containing the entity reference fragments: schema, user, |
307 | - series, name and revision. Each fragment is a string except revision (int). |
308 | - |
309 | - Raise a ValueError with a descriptive message if the given URL is not a |
310 | - valid and fully qualified entity URL. |
311 | - """ |
312 | - # Retrieve the schema. |
313 | - try: |
314 | - schema, remaining = url.split(':', 1) |
315 | - except ValueError: |
316 | - msg = 'URL has no schema: {}'.format(url) |
317 | - raise ValueError(msg.encode('utf-8')) |
318 | - if schema not in ('cs', 'local'): |
319 | - msg = 'URL has invalid schema: {}'.format(schema) |
320 | - raise ValueError(msg.encode('utf-8')) |
321 | - # Retrieve the optional user, the series, name and revision. |
322 | - parts = remaining.split('/') |
323 | - parts_length = len(parts) |
324 | - if parts_length == 3: |
325 | - user, series, name_revision = parts |
326 | - if not user.startswith('~'): |
327 | - msg = 'URL has invalid user name form: {}'.format(user) |
328 | - raise ValueError(msg.encode('utf-8')) |
329 | - user = user[1:] |
330 | - if not _valid_user(user): |
331 | - msg = 'URL has invalid user name: {}'.format(user) |
332 | - raise ValueError(msg.encode('utf-8')) |
333 | - if schema == 'local': |
334 | - msg = 'local entity URL with user name: {}'.format(url) |
335 | - raise ValueError(msg.encode('utf-8')) |
336 | - elif parts_length == 2: |
337 | - user = '' |
338 | - series, name_revision = parts |
339 | - else: |
340 | - msg = 'URL has invalid form: {}'.format(url) |
341 | - raise ValueError(msg.encode('utf-8')) |
342 | - # Validate the series. |
343 | - if not _valid_series(series): |
344 | - msg = 'URL has invalid series: {}'.format(series) |
345 | - raise ValueError(msg.encode('utf-8')) |
346 | - # Validate name and revision. |
347 | - try: |
348 | - name, revision = name_revision.rsplit('-', 1) |
349 | - except ValueError: |
350 | - msg = 'URL has no revision: {}'.format(url) |
351 | - raise ValueError(msg.encode('utf-8')) |
352 | - if not _valid_name(name): |
353 | - msg = 'URL has invalid name: {}'.format(name) |
354 | - raise ValueError(msg.encode('utf-8')) |
355 | - try: |
356 | - revision = int(revision) |
357 | - except ValueError: |
358 | - msg = 'URL has invalid revision: {}'.format(revision) |
359 | - raise ValueError(msg.encode('utf-8')) |
360 | - return schema, user, series, name, revision |
361 | |
362 | === modified file 'quickstart/tests/models/test_bundles.py' |
363 | --- quickstart/tests/models/test_bundles.py 2015-03-10 13:13:42 +0000 |
364 | +++ quickstart/tests/models/test_bundles.py 2015-04-21 10:32:19 +0000 |
365 | @@ -21,6 +21,7 @@ |
366 | import json |
367 | import unittest |
368 | |
369 | +from jujubundlelib import references |
370 | import mock |
371 | import yaml |
372 | |
373 | @@ -28,10 +29,7 @@ |
374 | netutils, |
375 | settings, |
376 | ) |
377 | -from quickstart.models import ( |
378 | - bundles, |
379 | - references, |
380 | -) |
381 | +from quickstart.models import bundles |
382 | from quickstart.tests import helpers |
383 | |
384 | |
385 | |
386 | === removed file 'quickstart/tests/models/test_references.py' |
387 | --- quickstart/tests/models/test_references.py 2015-03-09 17:50:28 +0000 |
388 | +++ quickstart/tests/models/test_references.py 1970-01-01 00:00:00 +0000 |
389 | @@ -1,400 +0,0 @@ |
390 | -# This file is part of the Juju Quickstart Plugin, which lets users set up a |
391 | -# Juju environment in very few steps (https://launchpad.net/juju-quickstart). |
392 | -# Copyright (C) 2013 Canonical Ltd. |
393 | -# |
394 | -# This program is free software: you can redistribute it and/or modify it under |
395 | -# the terms of the GNU Affero General Public License version 3, as published by |
396 | -# the Free Software Foundation. |
397 | -# |
398 | -# This program is distributed in the hope that it will be useful, but WITHOUT |
399 | -# ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
400 | -# SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
401 | -# Affero General Public License for more details. |
402 | -# |
403 | -# You should have received a copy of the GNU Affero General Public License |
404 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
405 | - |
406 | -"""Tests for the Juju Quickstart charm and bundle references management.""" |
407 | - |
408 | -from __future__ import unicode_literals |
409 | - |
410 | -import unittest |
411 | - |
412 | -from quickstart import settings |
413 | -from quickstart.models import references |
414 | -from quickstart.tests import helpers |
415 | - |
416 | - |
417 | -def make_reference( |
418 | - schema='cs', user='myuser', series='precise', name='juju-gui', |
419 | - revision=42): |
420 | - """Create and return a Reference instance.""" |
421 | - return references.Reference(schema, user, series, name, revision) |
422 | - |
423 | - |
424 | -class TestReference(unittest.TestCase): |
425 | - |
426 | - def test_attributes(self): |
427 | - # All reference attributes are correctly stored. |
428 | - ref = make_reference() |
429 | - self.assertEqual('cs', ref.schema) |
430 | - self.assertEqual('myuser', ref.user) |
431 | - self.assertEqual('precise', ref.series) |
432 | - self.assertEqual('juju-gui', ref.name) |
433 | - self.assertEqual(42, ref.revision) |
434 | - |
435 | - def test_revision_as_string(self): |
436 | - # The reference revision is converted to an int. |
437 | - ref = make_reference(revision='47') |
438 | - self.assertEqual(47, ref.revision) |
439 | - |
440 | - def test_string(self): |
441 | - # The string representation of a reference is its URL. |
442 | - tests = ( |
443 | - (make_reference(), |
444 | - 'cs:~myuser/precise/juju-gui-42'), |
445 | - (make_reference(schema='local'), |
446 | - 'local:~myuser/precise/juju-gui-42'), |
447 | - (make_reference(user=''), |
448 | - 'cs:precise/juju-gui-42'), |
449 | - (make_reference(user='dalek', revision=None, series='bundle'), |
450 | - 'cs:~dalek/bundle/juju-gui'), |
451 | - (make_reference(name='django', series='vivid', revision=0), |
452 | - 'cs:~myuser/vivid/django-0'), |
453 | - (make_reference(user='', revision=None), |
454 | - 'cs:precise/juju-gui'), |
455 | - ) |
456 | - for ref, expected_value in tests: |
457 | - self.assertEqual(expected_value, bytes(ref)) |
458 | - |
459 | - def test_repr(self): |
460 | - # A reference is correctly represented. |
461 | - tests = ( |
462 | - (make_reference(), |
463 | - '<Reference: cs:~myuser/precise/juju-gui-42>'), |
464 | - (make_reference(schema='local'), |
465 | - '<Reference: local:~myuser/precise/juju-gui-42>'), |
466 | - (make_reference(user=''), |
467 | - '<Reference: cs:precise/juju-gui-42>'), |
468 | - (make_reference(user='dalek', revision=None, series='bundle'), |
469 | - '<Reference: cs:~dalek/bundle/juju-gui>'), |
470 | - (make_reference(name='django', series='vivid', revision=0), |
471 | - '<Reference: cs:~myuser/vivid/django-0>'), |
472 | - (make_reference(user='', revision=None), |
473 | - '<Reference: cs:precise/juju-gui>'), |
474 | - ) |
475 | - for ref, expected_value in tests: |
476 | - self.assertEqual(expected_value, repr(ref)) |
477 | - |
478 | - def test_path(self): |
479 | - # The reference path is properly returned as a URL string without the |
480 | - # schema. |
481 | - tests = ( |
482 | - (make_reference(), |
483 | - '~myuser/precise/juju-gui-42'), |
484 | - (make_reference(schema='local'), |
485 | - '~myuser/precise/juju-gui-42'), |
486 | - (make_reference(user=''), |
487 | - 'precise/juju-gui-42'), |
488 | - (make_reference(user='dalek', revision=None, series='bundle'), |
489 | - '~dalek/bundle/juju-gui'), |
490 | - (make_reference(name='django', series='vivid', revision=0), |
491 | - '~myuser/vivid/django-0'), |
492 | - (make_reference(user='', revision=None), |
493 | - 'precise/juju-gui'), |
494 | - ) |
495 | - for ref, expected_value in tests: |
496 | - self.assertEqual(expected_value, ref.path()) |
497 | - |
498 | - def test_id(self): |
499 | - # The reference id is correctly returned. |
500 | - tests = ( |
501 | - (make_reference(), |
502 | - 'cs:~myuser/precise/juju-gui-42'), |
503 | - (make_reference(schema='local'), |
504 | - 'local:~myuser/precise/juju-gui-42'), |
505 | - (make_reference(user=''), |
506 | - 'cs:precise/juju-gui-42'), |
507 | - (make_reference(user='dalek', revision=None, series='bundle'), |
508 | - 'cs:~dalek/bundle/juju-gui'), |
509 | - (make_reference(name='django', series='vivid', revision=0), |
510 | - 'cs:~myuser/vivid/django-0'), |
511 | - (make_reference(user='', revision=None), |
512 | - 'cs:precise/juju-gui'), |
513 | - ) |
514 | - for ref, expected_value in tests: |
515 | - self.assertEqual(expected_value, ref.id()) |
516 | - |
517 | - def test_jujucharms_id(self): |
518 | - # It is possible to return the reference identifier in jujucharms.com. |
519 | - tests = ( |
520 | - (make_reference(), |
521 | - 'u/myuser/juju-gui/precise/42'), |
522 | - (make_reference(schema='local'), |
523 | - 'u/myuser/juju-gui/precise/42'), |
524 | - (make_reference(user=''), |
525 | - 'juju-gui/precise/42'), |
526 | - (make_reference(user='dalek', revision=None, series='bundle'), |
527 | - 'u/dalek/juju-gui'), |
528 | - (make_reference(name='django', series='vivid', revision=0), |
529 | - 'u/myuser/django/vivid/0'), |
530 | - (make_reference(user='', revision=None), |
531 | - 'juju-gui/precise'), |
532 | - (make_reference(user='', series='bundle', revision=None), |
533 | - 'juju-gui'), |
534 | - ) |
535 | - for ref, expected_value in tests: |
536 | - self.assertEqual(expected_value, ref.jujucharms_id()) |
537 | - |
538 | - def test_jujucharms_url(self): |
539 | - # The corresponding charm or bundle page in jujucharms.com is correctly |
540 | - # returned. |
541 | - tests = ( |
542 | - (make_reference(), |
543 | - 'u/myuser/juju-gui/precise/42'), |
544 | - (make_reference(schema='local'), |
545 | - 'u/myuser/juju-gui/precise/42'), |
546 | - (make_reference(user=''), |
547 | - 'juju-gui/precise/42'), |
548 | - (make_reference(user='dalek', revision=None, series='bundle'), |
549 | - 'u/dalek/juju-gui'), |
550 | - (make_reference(name='django', series='vivid', revision=0), |
551 | - 'u/myuser/django/vivid/0'), |
552 | - (make_reference(user='', revision=None), |
553 | - 'juju-gui/precise'), |
554 | - (make_reference(user='', series='bundle', revision=None), |
555 | - 'juju-gui'), |
556 | - ) |
557 | - for ref, expected_value in tests: |
558 | - expected_url = settings.JUJUCHARMS_URL + expected_value |
559 | - self.assertEqual(expected_url, ref.jujucharms_url()) |
560 | - |
561 | - def test_charm_entity(self): |
562 | - # The is_bundle method returns False for charm references. |
563 | - ref = make_reference(series='vivid') |
564 | - self.assertFalse(ref.is_bundle()) |
565 | - |
566 | - def test_bundle_entity(self): |
567 | - # The is_bundle method returns True for bundle references. |
568 | - ref = make_reference(series='bundle') |
569 | - self.assertTrue(ref.is_bundle()) |
570 | - |
571 | - def test_charm_store_entity(self): |
572 | - # The is_local method returns False for charm store references. |
573 | - ref = make_reference(schema='cs') |
574 | - self.assertFalse(ref.is_local()) |
575 | - |
576 | - def test_local_entity(self): |
577 | - # The is_local method returns True for local references. |
578 | - ref = make_reference(schema='local') |
579 | - self.assertTrue(ref.is_local()) |
580 | - |
581 | - def test_equality(self): |
582 | - # Two references are equal if they have the same URL. |
583 | - self.assertEqual(make_reference(), make_reference()) |
584 | - self.assertEqual(make_reference(user=''), make_reference(user='')) |
585 | - self.assertEqual( |
586 | - make_reference(revision=None), make_reference(revision=None)) |
587 | - |
588 | - def test_equality_different_references(self): |
589 | - # Two references with different attributes are not equal. |
590 | - tests = ( |
591 | - (make_reference(schema='cs'), |
592 | - make_reference(schema='local')), |
593 | - (make_reference(user=''), |
594 | - make_reference(user='who')), |
595 | - (make_reference(series='trusty'), |
596 | - make_reference(series='vivid')), |
597 | - (make_reference(name='django'), |
598 | - make_reference(name='rails')), |
599 | - (make_reference(revision=0), |
600 | - make_reference(revision=1)), |
601 | - (make_reference(revision=None), |
602 | - make_reference(revision=42)), |
603 | - ) |
604 | - for ref1, ref2 in tests: |
605 | - self.assertNotEqual(ref1, ref2) |
606 | - |
607 | - def test_equality_different_types(self): |
608 | - # A reference never equals a non-reference object. |
609 | - self.assertNotEqual(make_reference(), 42) |
610 | - self.assertNotEqual(make_reference(), True) |
611 | - self.assertNotEqual(make_reference(), 'oranges') |
612 | - |
613 | - def test_charmworld_id(self): |
614 | - # By default, the reference id in charmworld is set to None. |
615 | - # XXX frankban 2015-02-26: remove this test once we get rid of the |
616 | - # charmworld id concept. |
617 | - ref = make_reference() |
618 | - self.assertIsNone(ref.charmworld_id) |
619 | - |
620 | - |
621 | -class TestReferenceFromFullyQualifiedUrl( |
622 | - helpers.ValueErrorTestsMixin, unittest.TestCase): |
623 | - |
624 | - def test_no_schema_error(self): |
625 | - # A ValueError is raised if the URL schema is missing. |
626 | - expected_error = 'URL has no schema: precise/juju-gui' |
627 | - with self.assert_value_error(expected_error): |
628 | - references.Reference.from_fully_qualified_url('precise/juju-gui') |
629 | - |
630 | - def test_invalid_schema_error(self): |
631 | - # A ValueError is raised if the URL schema is not valid. |
632 | - expected_error = 'URL has invalid schema: http' |
633 | - with self.assert_value_error(expected_error): |
634 | - references.Reference.from_fully_qualified_url( |
635 | - 'http:precise/juju-gui') |
636 | - |
637 | - def test_invalid_user_form_error(self): |
638 | - # A ValueError is raised if the user form is not valid. |
639 | - expected_error = 'URL has invalid user name form: jean-luc' |
640 | - with self.assert_value_error(expected_error): |
641 | - references.Reference.from_fully_qualified_url( |
642 | - 'cs:jean-luc/precise/juju-gui') |
643 | - |
644 | - def test_invalid_user_name_error(self): |
645 | - # A ValueError is raised if the user name is not valid. |
646 | - expected_error = 'URL has invalid user name: jean:luc' |
647 | - with self.assert_value_error(expected_error): |
648 | - references.Reference.from_fully_qualified_url( |
649 | - 'cs:~jean:luc/precise/juju-gui') |
650 | - |
651 | - def test_local_user_name_error(self): |
652 | - # A ValueError is raised if a user is specified on a local entity. |
653 | - expected_error = ( |
654 | - 'local entity URL with user name: ' |
655 | - 'local:~jean-luc/precise/juju-gui') |
656 | - with self.assert_value_error(expected_error): |
657 | - references.Reference.from_fully_qualified_url( |
658 | - 'local:~jean-luc/precise/juju-gui') |
659 | - |
660 | - def test_invalid_form_error(self): |
661 | - # A ValueError is raised if the URL is not valid. |
662 | - expected_error = 'URL has invalid form: cs:~user/series/name/what-?' |
663 | - with self.assert_value_error(expected_error): |
664 | - references.Reference.from_fully_qualified_url( |
665 | - 'cs:~user/series/name/what-?') |
666 | - |
667 | - def test_invalid_series_error(self): |
668 | - # A ValueError is raised if the series is not valid. |
669 | - expected_error = 'URL has invalid series: boo!' |
670 | - with self.assert_value_error(expected_error): |
671 | - references.Reference.from_fully_qualified_url( |
672 | - 'cs:boo!/juju-gui-42') |
673 | - |
674 | - def test_no_revision_error(self): |
675 | - # A ValueError is raised if the entity revision is missing. |
676 | - expected_error = 'URL has no revision: cs:series/name' |
677 | - with self.assert_value_error(expected_error): |
678 | - references.Reference.from_fully_qualified_url('cs:series/name') |
679 | - |
680 | - def test_invalid_revision_error(self): |
681 | - # A ValueError is raised if the charm or bundle revision is not valid. |
682 | - expected_error = 'URL has invalid revision: revision' |
683 | - with self.assert_value_error(expected_error): |
684 | - references.Reference.from_fully_qualified_url( |
685 | - 'cs:series/name-revision') |
686 | - |
687 | - def test_invalid_name_error(self): |
688 | - # A ValueError is raised if the entity name is not valid. |
689 | - expected_error = 'URL has invalid name: not:valid' |
690 | - with self.assert_value_error(expected_error): |
691 | - references.Reference.from_fully_qualified_url( |
692 | - 'cs:precise/not:valid-42') |
693 | - |
694 | - def test_success(self): |
695 | - # References are correctly instantiated by parsing the fully qualified |
696 | - # URL. |
697 | - tests = ( |
698 | - ('cs:~myuser/precise/juju-gui-42', |
699 | - make_reference()), |
700 | - ('cs:trusty/juju-gui-42', |
701 | - make_reference(user='', series='trusty')), |
702 | - ('local:precise/juju-gui-42', |
703 | - make_reference(schema='local', user='')), |
704 | - ) |
705 | - for url, expected_ref in tests: |
706 | - ref = references.Reference.from_fully_qualified_url(url) |
707 | - self.assertEqual(expected_ref, ref) |
708 | - |
709 | - |
710 | -class TestReferenceFromJujucharmsUrl( |
711 | - helpers.ValueErrorTestsMixin, unittest.TestCase): |
712 | - |
713 | - def test_invalid_form(self): |
714 | - # A ValueError is raised if the URL is not valid. |
715 | - expected_error = 'invalid bundle URL: bad wolf' |
716 | - with self.assert_value_error(expected_error): |
717 | - references.Reference.from_jujucharms_url('bad wolf') |
718 | - |
719 | - def test_success(self): |
720 | - # A reference is correctly created from a jujucharms.com identifier or |
721 | - # complete URL. |
722 | - tests = ( |
723 | - # Check with both user and revision. |
724 | - ('u/myuser/mediawiki/42', |
725 | - make_reference(series='bundle', name='mediawiki')), |
726 | - ('/u/myuser/mediawiki/42', |
727 | - make_reference(series='bundle', name='mediawiki')), |
728 | - ('u/myuser/django-scalable/42/', |
729 | - make_reference(series='bundle', name='django-scalable')), |
730 | - ('{}u/myuser/mediawiki/42'.format(settings.JUJUCHARMS_URL), |
731 | - make_reference(series='bundle', name='mediawiki')), |
732 | - ('{}u/myuser/mediawiki/42/'.format(settings.JUJUCHARMS_URL), |
733 | - make_reference(series='bundle', name='mediawiki')), |
734 | - |
735 | - # Check without revision. |
736 | - ('u/myuser/mediawiki', |
737 | - make_reference(series='bundle', name='mediawiki', revision=None)), |
738 | - ('/u/myuser/wordpress', |
739 | - make_reference(series='bundle', name='wordpress', revision=None)), |
740 | - ('u/myuser/mediawiki/', |
741 | - make_reference(series='bundle', name='mediawiki', revision=None)), |
742 | - ('{}u/myuser/django'.format(settings.JUJUCHARMS_URL), |
743 | - make_reference(series='bundle', name='django', revision=None)), |
744 | - ('{}u/myuser/mediawiki/'.format(settings.JUJUCHARMS_URL), |
745 | - make_reference(series='bundle', name='mediawiki', revision=None)), |
746 | - |
747 | - # Check without the user. |
748 | - ('rails-single/42', |
749 | - make_reference(user='', series='bundle', name='rails-single')), |
750 | - ('/mediawiki/42', |
751 | - make_reference(user='', series='bundle', name='mediawiki')), |
752 | - ('rails-scalable/42/', |
753 | - make_reference(user='', series='bundle', name='rails-scalable')), |
754 | - ('{}mediawiki/42'.format(settings.JUJUCHARMS_URL), |
755 | - make_reference(user='', series='bundle', name='mediawiki')), |
756 | - ('{}django/42/'.format(settings.JUJUCHARMS_URL), |
757 | - make_reference(user='', series='bundle', name='django')), |
758 | - |
759 | - # Check without user and revision. |
760 | - ('mediawiki', |
761 | - make_reference(user='', series='bundle', name='mediawiki', |
762 | - revision=None)), |
763 | - ('/wordpress', |
764 | - make_reference(user='', series='bundle', name='wordpress', |
765 | - revision=None)), |
766 | - ('mediawiki/', |
767 | - make_reference(user='', series='bundle', name='mediawiki', |
768 | - revision=None)), |
769 | - ('{}django'.format(settings.JUJUCHARMS_URL), |
770 | - make_reference(user='', series='bundle', name='django', |
771 | - revision=None)), |
772 | - ('{}mediawiki/'.format(settings.JUJUCHARMS_URL), |
773 | - make_reference(user='', series='bundle', name='mediawiki', |
774 | - revision=None)), |
775 | - |
776 | - # Check charm entities. |
777 | - ('mediawiki/trusty/0', |
778 | - make_reference(user='', series='trusty', name='mediawiki', |
779 | - revision=0)), |
780 | - ('/wordpress/precise', |
781 | - make_reference(user='', series='precise', name='wordpress', |
782 | - revision=None)), |
783 | - ('u/who/rails/vivid', |
784 | - make_reference(user='who', series='vivid', name='rails', |
785 | - revision=None)), |
786 | - ) |
787 | - for url, expected_ref in tests: |
788 | - ref = references.Reference.from_jujucharms_url(url) |
789 | - self.assertEqual(expected_ref, ref) |
790 | |
791 | === modified file 'quickstart/tests/test_app.py' |
792 | --- quickstart/tests/test_app.py 2015-03-10 11:08:00 +0000 |
793 | +++ quickstart/tests/test_app.py 2015-04-21 10:32:19 +0000 |
794 | @@ -23,6 +23,7 @@ |
795 | import os |
796 | import unittest |
797 | |
798 | +from jujubundlelib import references |
799 | import jujuclient |
800 | import mock |
801 | import yaml |
802 | @@ -32,10 +33,7 @@ |
803 | platform_support, |
804 | settings, |
805 | ) |
806 | -from quickstart.models import ( |
807 | - bundles, |
808 | - references, |
809 | -) |
810 | +from quickstart.models import bundles |
811 | from quickstart.tests import helpers |
812 | |
813 | |
814 | |
815 | === modified file 'quickstart/tests/test_charmstore.py' |
816 | --- quickstart/tests/test_charmstore.py 2015-03-10 10:18:58 +0000 |
817 | +++ quickstart/tests/test_charmstore.py 2015-04-21 10:32:19 +0000 |
818 | @@ -18,16 +18,16 @@ |
819 | |
820 | from __future__ import unicode_literals |
821 | |
822 | +import json |
823 | import unittest |
824 | |
825 | -import json |
826 | +from jujubundlelib import references |
827 | |
828 | from quickstart import ( |
829 | charmstore, |
830 | netutils, |
831 | settings, |
832 | ) |
833 | -from quickstart.models import references |
834 | from quickstart.tests import helpers |
835 | |
836 | |
837 | |
838 | === modified file 'quickstart/tests/test_jujutools.py' |
839 | --- quickstart/tests/test_jujutools.py 2015-02-26 18:57:25 +0000 |
840 | +++ quickstart/tests/test_jujutools.py 2015-04-21 10:32:19 +0000 |
841 | @@ -20,11 +20,11 @@ |
842 | |
843 | import unittest |
844 | |
845 | +from jujubundlelib import references |
846 | import mock |
847 | import yaml |
848 | |
849 | from quickstart import jujutools |
850 | -from quickstart.models import references |
851 | from quickstart.tests import helpers |
852 | |
853 | |
854 | |
855 | === modified file 'quickstart/tests/test_manage.py' |
856 | --- quickstart/tests/test_manage.py 2015-02-26 19:12:17 +0000 |
857 | +++ quickstart/tests/test_manage.py 2015-04-21 10:32:19 +0000 |
858 | @@ -26,6 +26,7 @@ |
859 | import StringIO as io |
860 | import unittest |
861 | |
862 | +from jujubundlelib import references |
863 | import mock |
864 | import yaml |
865 | |
866 | @@ -42,7 +43,6 @@ |
867 | bundles, |
868 | envs, |
869 | jenv, |
870 | - references, |
871 | ) |
872 | from quickstart.tests import helpers |
873 | |
874 | |
875 | === modified file 'tox.ini' |
876 | --- tox.ini 2015-02-27 10:30:20 +0000 |
877 | +++ tox.ini 2015-04-21 10:32:19 +0000 |
878 | @@ -72,6 +72,7 @@ |
879 | # See https://launchpad.net/~juju/+archive/ubuntu/stable. |
880 | websocket-client==0.18.0 |
881 | jujuclient==0.50.1 |
882 | + jujubundlelib==0.1.1 |
883 | urwid==1.2.1 |
884 | # The distribution PyYAML requirement is used in this case. |
885 | |
886 | @@ -81,6 +82,7 @@ |
887 | # Ubuntu 14.04 (trusty) distro dependencies. |
888 | websocket-client==0.12.0 |
889 | jujuclient==0.17.5 |
890 | + jujubundlelib==0.1.1 |
891 | PyYAML==3.10 |
892 | urwid==1.1.1 |
893 | |
894 | @@ -90,6 +92,7 @@ |
895 | # Ubuntu 14.10 (utopic) distro dependencies. |
896 | websocket-client==0.12.0 |
897 | jujuclient==0.17.5 |
898 | + jujubundlelib==0.1.1 |
899 | PyYAML==3.11 |
900 | urwid==1.2.1 |
901 | |
902 | @@ -99,6 +102,7 @@ |
903 | # Ubuntu 15.04 (vivid) distro dependencies. |
904 | websocket-client==0.18.0 |
905 | jujuclient==0.18.5 |
906 | + jujubundlelib==0.1.1 |
907 | PyYAML==3.11 |
908 | urwid==1.2.1 |
909 |
Reviewers: mp+256906_ code.launchpad. net,
Message:
Please take a look.
Description:
Introduce jujubundlelib dependency.
Use the Reference model defined there.
https:/ /code.launchpad .net/~frankban/ juju-quickstart /jujubundlelib/ +merge/ 256906
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/228460043/
Affected files (+29, -639 lines): charmstore. py jujutools. py manage. py models/ bundles. py models/ references. py tests/models/ test_bundles. py tests/models/ test_references .py tests/test_ app.py tests/test_ charmstore. py tests/test_ jujutools. py tests/test_ manage. py
A [revision details]
M quickstart/app.py
M quickstart/
M quickstart/
M quickstart/
M quickstart/
D quickstart/
M quickstart/
D quickstart/
M quickstart/
M quickstart/
M quickstart/
M quickstart/
M tox.ini