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):