<pre style='margin:0'>
Renee Otten (reneeotten) pushed a commit to branch master
in repository upt-macports.
</pre>
<p><a href="https://github.com/macports/upt-macports/commit/19d7b79391e09cc91d7b374eaa363a65cda926da">https://github.com/macports/upt-macports/commit/19d7b79391e09cc91d7b374eaa363a65cda926da</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'> new 19d7b79 Implement the "update" feature.
</span>19d7b79 is described below
<span style='display:block; white-space:pre;color:#808000;'>commit 19d7b79391e09cc91d7b374eaa363a65cda926da
</span>Author: Cyril Roelandt <tipecaml@gmail.com>
AuthorDate: Sun Jan 26 22:28:40 2020 +0100
<span style='display:block; white-space:pre;color:#404040;'> Implement the "update" feature.
</span>---
upt_macports/portfile_updater.py | 275 ++++++++++++++++++
upt_macports/tests/test_macports_backend.py | 15 +
upt_macports/tests/test_portfile_updater.py | 433 ++++++++++++++++++++++++++++
upt_macports/upt_macports.py | 33 +++
4 files changed, 756 insertions(+)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/upt_macports/portfile_updater.py b/upt_macports/portfile_updater.py
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..ac99438
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/upt_macports/portfile_updater.py
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,275 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Copyright 2021 Cyril Roelandt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Licensed under the 3-clause BSD license. See the LICENSE file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+import logging
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+import re
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+import upt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+class PortfileUpdater:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def __init__(self, portfile_fp, pdiff, pkg_class):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.portfile_fp = portfile_fp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.pdiff = pdiff
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.logger = logging.getLogger('upt')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.macports_pkg = pkg_class()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def update(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_portfile_content = self._update_portfile_content()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.portfile_fp.seek(0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.portfile_fp.write(new_portfile_content)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.portfile_fp.truncate()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _update_portfile_content(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content = self.portfile_fp.read()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content = self._update_version(content,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.pdiff.old_version,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.pdiff.new_version)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content = self._update_revision(content)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ archive_format = self.macports_pkg.archive_format
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_archive = self.pdiff.new.get_archive(archive_format)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content = self._update_checksums(content, new_archive)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ except upt.ArchiveUnavailable:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.logger.info('We could not get archives for this package. '
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'The checksums/size will be wrong.')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content = self._update_dependencies(content, self.pdiff,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.macports_pkg.jinja2_reqformat)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return content
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @staticmethod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _update_checksums(content, new_archive):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Update the checksums block.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Return CONTENT after replacing the checksums (and size) with updated
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ checksums (and size) for NEW_ARCHIVE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ In the process, completely removes md5 checksum, which are no longer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ required in MacPorts.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ m = re.search(r"[^\n]*checksums.*?[^\\]\n", content, re.DOTALL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if not m: # This Portfile had no checksums, let's not change anything
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return content
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_archive_block = m.group(0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ m = re.match(r'(\s*)checksums(\s+)[^\s]+',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_archive_block.split('\n')[0])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ space_before = m.group(1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ space_after = m.group(2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ indent = ' ' * len(space_before + 'checksums' + space_after)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_archive_block = f'{space_before}checksums{space_after}'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_archive_block += f'rmd160 {new_archive.rmd160} \\\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_archive_block += f'{indent}sha256 {new_archive.sha256} \\\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_archive_block += f'{indent}size {new_archive.size}\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return content.replace(old_archive_block, new_archive_block)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @staticmethod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _update_version(content, old_version, new_version):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Update the version of the package being updated.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Return CONTENT after replacing the OLD_VERSION with the NEW_VERSION.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ This works for the "version" keyword, and a variety of "*.setup"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ keywords.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ keywords = '|'.join([
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'version', 'github.setup', 'bitbucket.setup',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'ruby.setup', 'perl5.setup',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return re.sub(fr'({keywords})(.*){old_version}',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fr'\g<1>\g<2>{new_version}',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content, count=1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @staticmethod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _update_revision(content):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Update the first revision entry in the Portfile.'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return re.sub(r'revision(\s+)\d+', r'revision\g<1>0', content,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ count=1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _update_dependencies(self, content, pdiff, reqformat_fn):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for phase in ['build', 'lib', 'test']:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content = self._update_dependency_phase(content, pdiff,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ reqformat_fn, phase)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return content
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @staticmethod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _get_current_dependencies(content, phase):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Return a list of the current dependencies for a given phase.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Extract all dependencies for PHASE from CONTENT. PHASE must be one of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'build', 'lib', 'test'. The dependencies are returned just like they
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ are written in the Portfile, for instance:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ['port:py${python.version}-six', 'port:py${python.version}-xlrd']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mmm = re.search(fr"[^\n]*depends_{phase}-append.*?[^\\]\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content, re.DOTALL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deps = []
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if mmm:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_depends_block = mmm.group(0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for line in old_depends_block.split('\n'):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ m = re.match(fr'(\s*)depends_{phase}-append(\s+)(.*)', line)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if m:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ line = m.group(3)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if line.endswith('\\'):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ line = line[:-1]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ line = line.strip()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deps.extend(line.split())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_depends_block = ''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return old_depends_block, deps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @staticmethod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _remove_deleted_dependencies(current_deps, deleted_dependencies):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Remove DELETED_DEPENDENCIES from CURRENT_DEPS.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CURRENT_DEPS and DELETED_DEPENDENCIES must be lists of dependencies as
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ specified in a Portfile.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Example:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ current_deps = ['port:py${python.version}-six',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'port:py${python.version}-xlrd']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deleted_dependencies = ['port:py${python.version}-xlrd']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ This method will return ['port:py${python.version}-six']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # We could have used operations on sets here, but since sets are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # unordered, the dependencies would have been "shuffled", which would
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # have caused the diff between the old and the new Portfiles to be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # bigger and harder to read that they needed to be.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for deleted_dependency in deleted_dependencies:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ current_deps.remove(deleted_dependency)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ except ValueError:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # This particular requirement is no longer marked as needed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # upstream. Maybe it was never included in the Makefile, which
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # means that trying to remove it may raise this exception.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pass
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return current_deps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @staticmethod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _add_new_dependencies(current_deps, new_dependencies):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Add NEW_DEPENDENCIES to CURRENT_DEPS.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CURRENT_DEPS and NEW_DEPENDENCIES must be lists of dependencies as
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ specified in a Portfile.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Example:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ current_deps = ['port:py${python.version}-six']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_dependencies = ['port:py${python.version}-xlrd']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ This method will return = ['port:py${python.version}-six',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'port:py${python.version}-xlrd']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # We could have used operations on sets here, but since sets are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # unordered, the dependencies would have been "shuffled", which would
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # have caused the diff between the old and the new Portfiles to be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # bigger and harder to read that they needed to be.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Some of the new requirements may already be in the Portfile. This
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # happens when upstream failed to properly specify metadata in the old
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # version and fixed everything in the new one:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Old upstream metadata: "required: []" (even though 'foo' is needed)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # New upstream metadata: "required: ['foo']"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # In this case, upt will consider that 'foo' is a new requirement.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Since it was already required in the old version (even though that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # was not specified in the metadata), the dependency on 'foo' will
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # already be specified in the Portfile. We need to make sure that we do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # not duplicate this dependency, hence the if condition in the loop.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for new_dependency in new_dependencies:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if new_dependency not in current_deps:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ current_deps.append(new_dependency)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return current_deps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _update_dependency_phase(self, content, pdiff, reqformat_fn, phase):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ phases = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'build': 'build',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'lib': 'run',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'test': 'test',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Let's extract the dependencies currently specified in the Portfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # for this phase.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_depends_block, deps = self._get_current_dependencies(content,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ phase)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Start by removing the deleted dependencies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deleted_dependencies = [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ f'port:{reqformat_fn(deleted_dependency)}'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for deleted_dependency in pdiff.deleted_requirements(phases[phase])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deps = self._remove_deleted_dependencies(deps, deleted_dependencies)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Next, add the new dependencies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_dependencies = [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ f'port:{reqformat_fn(new_dependency)}'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for new_dependency in pdiff.new_requirements(phases[phase])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deps = self._add_new_dependencies(deps, new_dependencies)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Finally, format the new depends block properly.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_depends_block = self._format_like(deps, old_depends_block, phase)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if old_depends_block:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content = content.replace(old_depends_block, new_depends_block)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # This phase had no dependencies, let's add it at the bottom of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Portfile and let the maintainer move it wherever they want.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if new_depends_block:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content += '# TODO: Move this\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ content += new_depends_block
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return content
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @staticmethod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def _format_like(deps, old_depends_block, phase):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Format a block of dependencies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ Return a string representing a dependency block for PHASE, containing
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dependencies specified in DEPS, so that it uses the same
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ indentation/spacing as OLD_DEPENDS_BLOCK.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if not deps: # No dependencies -> No block in the Portfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Read
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_depends_block_lines = old_depends_block.split('\n')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ block_name = f'depends_{phase}-append'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ m = re.match(fr'(\s*)depends_{phase}-append(\s+)(.*)',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_depends_block_lines[0])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if m:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ first_line_indent = m.group(1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ space = m.group(2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if m.group(3) == '\\':
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # When the first line does not contain a dependency, like this:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # depends_lib-append \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # we use this "hack": this allows us to not handle a "special"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # case" when crafting the new depends block.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deps.insert(0, '')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # This phase was not included in the original Portfile, we will
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # build it "from scratch".
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ first_line_indent = ''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ space = ' '
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ next_lines_indent = ''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if len(old_depends_block_lines) > 1:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ m = re.match(r'(\s+)', old_depends_block_lines[1])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if m:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ next_lines_indent = m.group(1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if next_lines_indent == '':
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ next_lines_indent = first_line_indent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ next_lines_indent += ' ' * len(block_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ next_lines_indent += space
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Craft the new block
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_depends = f'{first_line_indent}{block_name}'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if not deps[0]:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_depends += ' ' * (len(space) - 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_depends += space
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_depends += ' \\\n'.join([
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dep if i == 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else f'{next_lines_indent}{dep}'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for i, dep in enumerate(deps)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_depends += '\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return new_depends
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/upt_macports/tests/test_macports_backend.py b/upt_macports/tests/test_macports_backend.py
</span><span style='display:block; white-space:pre;color:#808080;'>index da7ac14..527fdff 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/upt_macports/tests/test_macports_backend.py
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/upt_macports/tests/test_macports_backend.py
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -7,6 +7,21 @@ from upt_macports.upt_macports import MacPortsBackend
</span> class TestMacPortsBackend(unittest.TestCase):
def setUp(self):
self.macports_backend = MacPortsBackend()
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.macports_backend.frontend = 'pypi'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @mock.patch('upt_macports.upt_macports.MacPortsBackend.package_versions',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return_value=['1.2'])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_current_version(self, m_package_versions):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ version = self.macports_backend.current_version(mock.Mock(), 'foo')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(version, '1.2')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @mock.patch('upt_macports.upt_macports.MacPortsBackend.package_versions',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return_value=[])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @mock.patch('upt.Backend.current_version', return_value='1.2')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_current_version_fallback(self, m_current_version,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ m_package_versions):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ version = self.macports_backend.current_version(mock.Mock(), 'foo')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(version, '1.2')
</span>
def test_unhandled_frontend(self):
upt_pkg = upt.Package('foo', '42')
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/upt_macports/tests/test_portfile_updater.py b/upt_macports/tests/test_portfile_updater.py
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..c730c18
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/upt_macports/tests/test_portfile_updater.py
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,433 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Copyright 2021 Cyril Roelandt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Licensed under the 3-clause BSD license. See the LICENSE file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+import io
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+import unittest
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+from unittest import mock
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+import upt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+from upt_macports.portfile_updater import PortfileUpdater
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+from upt_macports.upt_macports import MacPortsPythonPackage
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+class TestPortfileUpdater(unittest.TestCase):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def setUp(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ handle = io.StringIO('')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.updater = PortfileUpdater(handle, mock.Mock(),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ MacPortsPythonPackage)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_version(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ test_cases = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'version 1.2.3': 'version 4.5.6',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ' version 1.2.3': ' version 4.5.6',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'github.setup auth pkg 1.2.3': 'github.setup auth pkg 4.5.6',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'bitbucket.setup auth pkg 1.2.3': 'bitbucket.setup auth pkg 4.5.6',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'perl5.setup foo 1.2.3': 'perl5.setup foo 4.5.6',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'ruby.setup foo 1.2.3 gem': 'ruby.setup foo 4.5.6 gem',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'platforms darwin': 'platforms darwin',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for before, after in test_cases.items():
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._update_version(before, '1.2.3', '4.5.6')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, after)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_revision(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ test_cases = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'revision 1\n': 'revision 0\n',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'revision 0\n': 'revision 0\n',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'revision 1\nrevision 2\n': 'revision 0\nrevision 2\n',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'foo\n': 'foo\n',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for before, after in test_cases.items():
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(self.updater._update_revision(before), after)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_checksums(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # No checksum in the Portfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfile = 'version 1.2\nrevision 0\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._update_checksums(portfile, mock.Mock())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, portfile)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Build upt.Archive objects
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldrmd = '91bf89c0493ad2caa8ed29372972e2e887f84bb8'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldsha = '2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a' # noqa
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newrmd = '770c41f726e57b64e2c27266e6b0cf8b7bf895ab'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newsha = '2f52bbb095baa858b3273d851de5cc25a4470351bdfe675b2d5b997e3145c2c4' # noqa
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldsize = 42
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newsize = 1337
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new = upt.Archive('url', size=newsize, rmd160=newrmd, sha256=newsha)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # A single hash in the Portfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfile = f'checksums rmd160 {oldrmd} \n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = f'checksums rmd160 {newrmd} \\\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected += f' sha256 {newsha} \\\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected += f' size {newsize}\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._update_checksums(portfile, new)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # A more common case
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfile = f'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ checksums md5 abcdef \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rmd160 {oldrmd} \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sha256 {oldsha} \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size {oldsize}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = f'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ checksums rmd160 {newrmd} \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sha256 {newsha} \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size {newsize}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._update_checksums(portfile, new)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_get_current_dependencies(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfile = '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_lib-append libdep1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_test-append testdep1 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ testdep2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # lib phase
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ block, deps = self.updater._get_current_dependencies(portfile, 'lib')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(block, 'depends_lib-append libdep1\n')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertListEqual(deps, ['libdep1'])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # test phase
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ block, deps = self.updater._get_current_dependencies(portfile, 'test')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = ''' depends_test-append testdep1 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ testdep2\n'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(block, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertListEqual(deps, ['testdep1', 'testdep2'])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # build phase
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ block, deps = self.updater._get_current_dependencies(portfile, 'build')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(block, '')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(deps, [])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_get_current_dependencies_corner_cases(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfile = '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_build-append port:foo port:bar
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_lib-append \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:baz
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # build phase
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ block, deps = self.updater._get_current_dependencies(portfile, 'build')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(block, 'depends_build-append port:foo port:bar\n')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(deps, ['port:foo', 'port:bar'])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # lib phase
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ block, deps = self.updater._get_current_dependencies(portfile, 'lib')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(block, 'depends_lib-append \\\n port:baz\n')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertListEqual(deps, ['port:baz'])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_remove_deleted_dependencies(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ current = ['foo', 'bar']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deleted = ['bar', 'baz']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = ['foo']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._remove_deleted_dependencies(current, deleted)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertListEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_add_new_dependencies(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ current = ['foo', 'bar']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ added = ['bar', 'baz']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = ['foo', 'bar', 'baz']
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._add_new_dependencies(current, added)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertListEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_format_like(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # No deps
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(self.updater._format_like([], mock.Mock(), 'lib'), '')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # The block did not exist in the old Portfile and must be added
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = 'depends_lib-append port:foo\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._format_like(['port:foo'], '', 'lib')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # No dependency on the first line
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old = 'depends_lib-append \\\nport:foo\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = '''depends_lib-append \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:bar\n'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._format_like(['port:bar'], old, 'lib')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # There are spaces before the block
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ deps = [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'port:foo', 'port:bar', 'port:baz'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_depends_block = ''' depends_lib-append port:foo \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:bar
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = ''' depends_lib-append port:foo \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:bar \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:baz
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._format_like(deps, old_depends_block, 'lib')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # The original depends block is a single line
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_depends_block = 'depends_test-append port:foo\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = '''depends_test-append port:foo \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:bar \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:baz
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._format_like(deps, old_depends_block, 'test')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_dependencies(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_portfile = '''version 1.2.3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_build-append \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:build-foo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append port:lib-foo \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:lib-bar
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+platforms darwin
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected = '''version 1.2.3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_build-append \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:build-foo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append port:lib-foo \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:lib-baz
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+platforms darwin
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# TODO: Move this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_test-append port:test-foo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def reqformat(req):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return f'port:{req}'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg = upt.Package('somepkg', '1.2.3')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.requirements = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'build': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('build-foo')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'run': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('lib-foo'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('lib-bar'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg = upt.Package('somepkg', '4.5.6')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.requirements = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'build': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('build-foo')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'run': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('lib-foo'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('lib-baz'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'test': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('test-foo'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pdiff = upt.PackageDiff(oldpkg, newpkg)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = self.updater._update_dependencies(old_portfile, pdiff,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ lambda x: x)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_portfile_content_beautifulsoup(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_portfile = '''\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+version 4.6.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+checksums rmd160 6452de577ef676636fb0be79eba9224cafd5622d \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size 160846
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {${name} ne ${subport}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append port:py${python.version}-setuptools
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected_portfile = '''\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+version 4.9.1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+checksums rmd160 b72ed53263f07c843ce34513a9d62128051e2fc3 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sha256 73cc4d115b96f79c7d77c1c7f7a0a8d4c57860d1041df407dd1aae7f07a77fd7 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size 374759
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {${name} ne ${subport}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append port:py${python.version}-setuptools \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-soupsieve
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+''' # noqa
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg = upt.Package('beautifulsoup4', '4.6.0')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.frontend = 'pypi'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.requirements = {}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.archives = [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.Archive('url',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rmd160='6452de577ef676636fb0be79eba9224cafd5622d',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sha256='808b6ac932dccb0a4126558f7dfdcf41710dd44a4ef497a0bb59a77f9f078e89', # noqa
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size=160846)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg = upt.Package('beautifulsoup4', '4.9.1')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.frontend = 'pypi'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.requirements = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'run': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('soupsieve'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.archives = [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.Archive('url',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ rmd160='b72ed53263f07c843ce34513a9d62128051e2fc3',
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sha256='73cc4d115b96f79c7d77c1c7f7a0a8d4c57860d1041df407dd1aae7f07a77fd7', # noqa
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size=374759)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pdiff = upt.PackageDiff(oldpkg, newpkg)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater = PortfileUpdater(io.StringIO(old_portfile),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pdiff,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ MacPortsPythonPackage)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = updater._update_portfile_content()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected_portfile)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_portfile_content_sunpy(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # Upgrading sunpy from 0.3.1 to 1.1.3 has us:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # 1) Reset the revision (from 1 to 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # 2) Parse a big block of runtime dependencies
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_portfile = '''\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+version 0.3.1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+revision 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {${name} ne ${subport}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_build-append port:py${python.version}-numpy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append port:py${python.version}-scipy \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-matplotlib \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-astropy \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pyqt4 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-suds \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pandas \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-beautifulsoup4 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-configobj \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-setuptools \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-py
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected_portfile = '''\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+version 1.1.3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+revision 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {${name} ne ${subport}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_build-append port:py${python.version}-numpy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append port:py${python.version}-scipy \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-matplotlib \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-astropy \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pyqt4 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-suds \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pandas \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-beautifulsoup4 \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-configobj \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-setuptools \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-py \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-numpy \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-parfive
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# TODO: Move this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_test-append port:py${python.version}-hypothesis \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pytest \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pytest-doctestplus \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pytest-astropy \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pytest-cov \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pytest-mock \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-tox \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-tox-conda
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg = upt.Package('sunpy', '0.3.1')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.frontend = 'pypi'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.requirements = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg = upt.Package('beautifulsoup4', '1.1.3')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.frontend = 'pypi'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.requirements = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'run': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('numpy'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('parfive'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'test': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('hypothesis'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest-doctestplus'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest-astropy'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest-cov'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest-mock'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('tox'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('tox-conda'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pdiff = upt.PackageDiff(oldpkg, newpkg)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater = PortfileUpdater(io.StringIO(old_portfile),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pdiff,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ MacPortsPythonPackage)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = updater._update_portfile_content()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected_portfile)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_portfile_content_gwosc(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # What is interesting about updating gwosc from 0.3.3 to 0.5.3 is:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # 1) depends_lib-append must be removed completely
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # 2) depends_test-append must be added
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_portfile = '''\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+version 0.3.3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {${name} ne ${subport}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_build-append port:py${python.version}-setuptools
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_lib-append port:py${python.version}-six
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ livecheck.type none
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ expected_portfile = '''\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+version 0.5.3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+if {${name} ne ${subport}} {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ depends_build-append port:py${python.version}-setuptools
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ livecheck.type none
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# TODO: Move this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+depends_test-append port:py${python.version}-pytest \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pytest-cov \\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ port:py${python.version}-pytest-socket
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+'''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg = upt.Package('gwosc', '0.3.3')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.frontend = 'pypi'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ oldpkg.requirements = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'run': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('six'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg = upt.Package('gwosc', '0.5.3')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.frontend = 'pypi'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ newpkg.requirements = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'run': [],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 'test': [
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest-cov'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ upt.PackageRequirement('pytest-socket'),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pdiff = upt.PackageDiff(oldpkg, newpkg)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater = PortfileUpdater(io.StringIO(old_portfile),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pdiff,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ MacPortsPythonPackage)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ out = updater._update_portfile_content()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(out, expected_portfile)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_portfile = 'line1\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_portfile = 'line2\nline3\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater = PortfileUpdater(io.StringIO(old_portfile), None, mock.Mock())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater._update_portfile_content = lambda: new_portfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater.update()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater.portfile_fp.seek(0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(updater.portfile_fp.read(), new_portfile)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def test_update_shorter_portfile(self):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ old_portfile = 'line1\nline2\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ new_portfile = 'line3\n'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater = PortfileUpdater(io.StringIO(old_portfile), None, mock.Mock())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater._update_portfile_content = lambda: new_portfile
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater.update()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ updater.portfile_fp.seek(0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.assertEqual(updater.portfile_fp.read(), new_portfile)
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/upt_macports/upt_macports.py b/upt_macports/upt_macports.py
</span><span style='display:block; white-space:pre;color:#808080;'>index 8b62caf..bb09465 100755
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/upt_macports/upt_macports.py
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/upt_macports/upt_macports.py
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -9,6 +9,8 @@ import subprocess
</span> import sys
from packaging.specifiers import SpecifierSet
<span style='display:block; white-space:pre;background:#e0ffe0;'>+from upt_macports.portfile_updater import PortfileUpdater
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span>
class MacPortsPackage(object):
def __init__(self):
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -328,3 +330,34 @@ class MacPortsBackend(upt.Backend):
</span> self.standardize_CPAN_version(dep.version) for dep in s])
return super().needs_requirement(req, phase)
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def current_version(self, frontend, pkgname, output=None):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''Return the current version of PKGNAME, packaged using FRONTEND.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ PKGNAME is the name of the package in the upstream package archive, not
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+the port name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ '''
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.frontend = frontend.name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ try:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return self.package_versions(pkgname)[0]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ except: # noqa
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ self.logger.error(f'Could not get current version for {pkgname}')
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return super().current_version(frontend, pkgname, output=output)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ def update_package(self, pdiff, output=None):
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pkg_class = self.pkg_classes[self.frontend]
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ macports_pkg = pkg_class()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # TODO: This is basically the same code as the one found in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # MacPortsPackage._create_output_directories(). It would be nice not to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # repeat ourselves.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if output is None:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ pkgname = pdiff.new.name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ folder_name = macports_pkg._normalized_macports_folder(pkgname)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ output_dir = os.path.join(macports_pkg.category, folder_name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfile_path = f'{output_dir}/Portfile'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ else:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ portfile_path = output
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ with open(portfile_path, 'r+') as f:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ PortfileUpdater(f, pdiff, pkg_class).update()
</span></pre><pre style='margin:0'>
</pre>