def test_multiple_lines_separated_in_project(self): global_content = textwrap.dedent("""\ foo<2;python_version=='2.7' foo>1;python_version!='2.7' """) project_content = textwrap.dedent("""\ foo<1.8;python_version=='2.7' # mumbo gumbo foo>0.9;python_version!='2.7' """) 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('foo', '', '<2', "python_version=='2.7'", ''), requirement.Requirement('foo', '', '>1', "python_version!='2.7'", ''), requirement.Requirement('', '', '', '', "# mumbo gumbo") ]), reqs) self.assertEqual( project.StdOut(" foo<1.8;python_version=='2.7' -> " "foo<2;python_version=='2.7'\n"), actions[2]) self.assertEqual( project.StdOut(" foo>0.9;python_version!='2.7' -> " "foo>1;python_version!='2.7'\n"), actions[3]) self.assertThat(actions, matchers.HasLength(4))
def test_stdout(self): stdout = io.StringIO() root = self.useFixture(fixtures.TempDir()).path proj = {'root': root} actions = [project.StdOut(u'fred\n')] project.write(proj, actions, stdout, True) self.expectThat(stdout.getvalue(), matchers.Equals('fred\n'))
def test_single_global_multiple_in_project(self): global_content = textwrap.dedent("""\ foo>1 """) project_content = textwrap.dedent("""\ foo<2;python_version=='2.7' foo>1;python_version!='2.7' """) 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('foo', '', '>1', "", '')]), reqs) self.assertEqual(project.StdOut( " foo<2;python_version=='2.7' -> foo>1\n"), actions[2]) self.assertEqual(project.StdOut( " foo>1;python_version!='2.7' -> \n"), actions[3]) self.assertThat(actions, matchers.HasLength(4))
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])
def _sync_requirements_file(source_reqs, dest_sequence, dest_label, softupdate, hacking, non_std_reqs): actions = [] dest_reqs = requirement.to_dict(dest_sequence) changes = [] output_requirements = [] processed_packages = set() for req, req_line in dest_sequence: # Skip the instructions header if req_line in requirement._REQS_HEADER: continue elif req is None: # Unparsable lines. output_requirements.append( requirement.Requirement('', '', '', '', req_line.rstrip())) continue elif not req.package: # Comment-only lines output_requirements.append(req) continue elif req.package.lower() in processed_packages: continue processed_packages.add(req.package.lower()) # Special cases: # projects need to align hacking version on their own time if req.package == "hacking" and not hacking: output_requirements.append(req) continue reference = source_reqs.get(req.package.lower()) if reference: actual = dest_reqs.get(req.package.lower()) for req, ref in six.moves.zip_longest(actual, reference): if not req: # More in globals changes.append(Change(ref[0].package, '', ref[1])) elif not ref: # less in globals changes.append(Change(req[0].package, req[1], '')) elif req[0] != ref[0]: # 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: # under softupdate we pass through anything unknown packages, # this is intended for ecosystem projects that want to stay in # sync with existing requirements, but also add their own above # and beyond. output_requirements.append(req) else: # What do we do if we find something unexpected? # # In the default cause we should die horribly, because # the point of global requirements was a single lever # to control all the pip installs in the gate. # # However, we do have other projects using # devstack jobs that might have legitimate reasons to # override. For those we support NON_STANDARD_REQS=1 # environment variable to turn this into a warning only. # However this drops the unknown requirement. actions.append( project.Error("'%s' is not in global-requirements.txt" % req.package)) # always print out what we did if we did a thing if changes: actions.append( project.StdOut("Version change for: %s\n" % ", ".join([x.name for x in changes]))) actions.append(project.StdOut("Updated %s:\n" % dest_label)) for change in changes: actions.append(project.StdOut(" %s\n" % change)) return actions, requirement.Requirements(output_requirements)