From 5033a0f71617cb6b195361f6fd04844b64c7f924 Mon Sep 17 00:00:00 2001 From: Jamie Lennox Date: Fri, 8 Apr 2016 17:37:01 +1000 Subject: [PATCH] Allow maintaining extras from project A project needs to be able to specify that it depends on a project including extras for that project and still have it's version maintained by global-requirements. Currently if the requirements are seen to mismatch then the string from global requirements is dropped in place of the project string, but this drops any extras specified by project. In the case that extras are different and the version needs updating add a new combined requirement to the project with the original extras and the new version. Closes-Bug: #1567809 Change-Id: Ife48b7963a5e6706289f1b9a47cb95fae7f0bc22 --- openstack_requirements/cmds/update.py | 20 +++++++++++++++++-- openstack_requirements/requirement.py | 22 ++++++++++++++------- openstack_requirements/tests/test_update.py | 20 +++++++++++++++++++ 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/openstack_requirements/cmds/update.py b/openstack_requirements/cmds/update.py index d979aeafcf..ed36f4ff54 100644 --- a/openstack_requirements/cmds/update.py +++ b/openstack_requirements/cmds/update.py @@ -138,8 +138,24 @@ def _sync_requirements_file( # less in globals changes.append(Change(req[0].package, req[1], '')) elif req[0] != ref[0]: - # A change on this entry - changes.append(Change(req[0].package, req[1], ref[1])) + # NOTE(jamielennox): extras are allowed to be specified in + # a project's requirements and the version be updated and + # extras maintained. Create a new ref object the same as + # the original but with the req's extras. + + merged_ref = requirement.Requirement(ref[0].package, + ref[0].location, + ref[0].specifiers, + ref[0].markers, + ref[0].comment, + req[0].extras) + + ref = (merged_ref, merged_ref.to_line()) + + if req[0] != ref[0]: + # A change on this entry + changes.append(Change(req[0].package, req[1], ref[1])) + if ref: output_requirements.append(ref[0]) elif softupdate: diff --git a/openstack_requirements/requirement.py b/openstack_requirements/requirement.py index 18f6b6b1d3..48ece717ba 100644 --- a/openstack_requirements/requirement.py +++ b/openstack_requirements/requirement.py @@ -40,6 +40,20 @@ class Requirement(collections.namedtuple('Requirement', cls, package, location, specifiers, markers, comment, frozenset(extras or ())) + def to_line(self, marker_sep=';', line_prefix=''): + comment_p = ' ' if self.package else '' + comment = (comment_p + self.comment if self.comment else '') + marker = marker_sep + self.markers if self.markers else '' + package = line_prefix + self.package if self.package else '' + location = self.location + '#egg=' if self.location else '' + extras = '[%s]' % ",".join(sorted(self.extras)) if self.extras else '' + return '%s%s%s%s%s%s\n' % (location, + package, + extras, + self.specifiers, + marker, + comment) + Requirements = collections.namedtuple('Requirements', ['reqs']) @@ -135,13 +149,7 @@ def to_content(reqs, marker_sep=';', line_prefix='', prefix=True): if prefix: lines += _REQS_HEADER for req in reqs.reqs: - comment_p = ' ' if req.package else '' - comment = (comment_p + req.comment if req.comment else '') - marker = marker_sep + req.markers if req.markers else '' - package = line_prefix + req.package if req.package else '' - location = req.location + '#egg=' if req.location else '' - lines.append('%s%s%s%s%s\n' % ( - location, package, req.specifiers, marker, comment)) + lines.append(req.to_line(marker_sep, line_prefix)) return u''.join(lines) diff --git a/openstack_requirements/tests/test_update.py b/openstack_requirements/tests/test_update.py index b2ad48f90c..266191c2ce 100644 --- a/openstack_requirements/tests/test_update.py +++ b/openstack_requirements/tests/test_update.py @@ -384,6 +384,26 @@ class TestSyncRequirementsFile(testtools.TestCase): requirement.Requirement('', '', '', '', n)]), reqs) + def test_extras_kept(self): + global_content = textwrap.dedent("""\ + oslo.db>1.4.1 + """) + project_content = textwrap.dedent("""\ + oslo.db[fixture,mysql]>1.3 + """) + global_reqs = requirement.parse(global_content) + project_reqs = list(requirement.to_reqs(project_content)) + actions, reqs = update._sync_requirements_file( + global_reqs, project_reqs, 'f', False, False, False) + self.assertEqual(requirement.Requirements([ + requirement.Requirement( + 'oslo.db', '', '>1.4.1', '', '', ['fixture', 'mysql'])]), + reqs) + self.assertThat(actions, matchers.HasLength(3)) + self.assertEqual(project.StdOut( + " oslo.db[fixture,mysql]>1.3 -> " + "oslo.db[fixture,mysql]>1.4.1\n"), actions[2]) + class TestCopyRequires(testtools.TestCase):