diff options
-rw-r--r-- | pbr/core.py | 120 | ||||
-rw-r--r-- | pbr/packaging.py | 172 | ||||
-rw-r--r-- | pbr/testr_command.py | 2 | ||||
-rw-r--r-- | setup.cfg | 2 | ||||
-rw-r--r-- | tools/integration.sh | 28 |
5 files changed, 187 insertions, 137 deletions
diff --git a/pbr/core.py b/pbr/core.py index f622ad0..0f4b94a 100644 --- a/pbr/core.py +++ b/pbr/core.py @@ -40,6 +40,7 @@ from distutils import core from distutils import errors +import logging import os import sys import warnings @@ -49,7 +50,17 @@ from setuptools import dist from pbr import util -core.Distribution = dist._get_unpatched(core.Distribution) +_saved_core_distribution = core.Distribution + + +def _monkeypatch_distribution(): + core.Distribution = dist._get_unpatched(core.Distribution) + + +def _restore_distribution_monkeypatch(): + core.Distribution = _saved_core_distribution + + if sys.version_info[0] == 3: string_type = str integer_types = (int,) @@ -76,52 +87,63 @@ def pbr(dist, attr, value): not work well with distributions that do use a `Distribution` subclass. """ - if not value: - return - if isinstance(value, string_type): - path = os.path.abspath(value) - else: - path = os.path.abspath('setup.cfg') - if not os.path.exists(path): - raise errors.DistutilsFileError( - 'The setup.cfg file %s does not exist.' % path) - - # Converts the setup.cfg file to setup() arguments try: - attrs = util.cfg_to_args(path) - except Exception: - e = sys.exc_info()[1] - raise errors.DistutilsSetupError( - 'Error parsing %s: %s: %s' % (path, e.__class__.__name__, e)) - - # Repeat some of the Distribution initialization code with the newly - # provided attrs - if attrs: - # Skips 'options' and 'licence' support which are rarely used; may add - # back in later if demanded - for key, val in attrs.items(): - if hasattr(dist.metadata, 'set_' + key): - getattr(dist.metadata, 'set_' + key)(val) - elif hasattr(dist.metadata, key): - setattr(dist.metadata, key, val) - elif hasattr(dist, key): - setattr(dist, key, val) - else: - msg = 'Unknown distribution option: %s' % repr(key) - warnings.warn(msg) - - # Re-finalize the underlying Distribution - core.Distribution.finalize_options(dist) - - # This bit comes out of distribute/setuptools - if isinstance(dist.metadata.version, integer_types + (float,)): - # Some people apparently take "version number" too literally :) - dist.metadata.version = str(dist.metadata.version) - - # This bit of hackery is necessary so that the Distribution will ignore - # normally unsupport command options (namely pre-hooks and post-hooks). - # dist.command_options is normally a dict mapping command names to dicts of - # their options. Now it will be a defaultdict that returns IgnoreDicts for - # the each command's options so we can pass through the unsupported options - ignore = ['pre_hook.*', 'post_hook.*'] - dist.command_options = util.DefaultGetDict(lambda: util.IgnoreDict(ignore)) + _monkeypatch_distribution() + if not value: + return + if isinstance(value, string_type): + path = os.path.abspath(value) + else: + path = os.path.abspath('setup.cfg') + if not os.path.exists(path): + raise errors.DistutilsFileError( + 'The setup.cfg file %s does not exist.' % path) + + # Converts the setup.cfg file to setup() arguments + try: + attrs = util.cfg_to_args(path) + except Exception: + e = sys.exc_info()[1] + # NB: This will output to the console if no explicit logging has + # been setup - but thats fine, this is a fatal distutils error, so + # being pretty isn't the #1 goal.. being diagnosable is. + logging.exception('Error parsing') + raise errors.DistutilsSetupError( + 'Error parsing %s: %s: %s' % (path, e.__class__.__name__, e)) + + # Repeat some of the Distribution initialization code with the newly + # provided attrs + if attrs: + # Skips 'options' and 'licence' support which are rarely used; may + # add back in later if demanded + for key, val in attrs.items(): + if hasattr(dist.metadata, 'set_' + key): + getattr(dist.metadata, 'set_' + key)(val) + elif hasattr(dist.metadata, key): + setattr(dist.metadata, key, val) + elif hasattr(dist, key): + setattr(dist, key, val) + else: + msg = 'Unknown distribution option: %s' % repr(key) + warnings.warn(msg) + + # Re-finalize the underlying Distribution + core.Distribution.finalize_options(dist) + + # This bit comes out of distribute/setuptools + if isinstance(dist.metadata.version, integer_types + (float,)): + # Some people apparently take "version number" too literally :) + dist.metadata.version = str(dist.metadata.version) + + # This bit of hackery is necessary so that the Distribution will ignore + # normally unsupport command options (namely pre-hooks and post-hooks). + # dist.command_options is normally a dict mapping command names to + # dicts of their options. Now it will be a defaultdict that returns + # IgnoreDicts for the each command's options so we can pass through the + # unsupported options + ignore = ['pre_hook.*', 'post_hook.*'] + dist.command_options = util.DefaultGetDict( + lambda: util.IgnoreDict(ignore) + ) + finally: + _restore_distribution_monkeypatch() diff --git a/pbr/packaging.py b/pbr/packaging.py index a998ceb..dc256a0 100644 --- a/pbr/packaging.py +++ b/pbr/packaging.py @@ -253,95 +253,101 @@ def write_git_changelog(git_dir=None, dest_dir=os.path.curdir, """Write a changelog based on the git changelog.""" should_skip = get_boolean_option(option_dict, 'skip_changelog', 'SKIP_WRITE_GIT_CHANGELOG') - if not should_skip: - new_changelog = os.path.join(dest_dir, 'ChangeLog') - # If there's already a ChangeLog and it's not writable, just use it - if (os.path.exists(new_changelog) - and not os.access(new_changelog, os.W_OK)): - return - log.info('[pbr] Writing ChangeLog') - if git_dir is None: - git_dir = _get_git_directory() - if git_dir: - log_cmd = ['log', '--oneline', '--decorate'] - changelog = _run_git_command(log_cmd, git_dir) - first_line = True - with io.open(new_changelog, "w", - encoding="utf-8") as changelog_file: - changelog_file.write("CHANGES\n=======\n\n") - for line in changelog.split('\n'): - line_parts = line.split() - if len(line_parts) < 2: - continue - # Tags are in a list contained in ()'s. If a commit - # subject that is tagged happens to have ()'s in it - # this will fail - if line_parts[1].startswith('(') and ')' in line: - msg = line.split(')')[1].strip() - else: - msg = " ".join(line_parts[1:]) - - if "tag:" in line: - tags = [ - tag.split(",")[0] - for tag in line.split(")")[0].split("tag: ")[1:]] - tag = _get_highest_tag(tags) - - underline = len(tag) * '-' - if not first_line: - changelog_file.write('\n') - changelog_file.write( - ("%(tag)s\n%(underline)s\n\n" % - dict(tag=tag, - underline=underline))) - - if not msg.startswith("Merge "): - if msg.endswith("."): - msg = msg[:-1] - changelog_file.write( - ("* %(msg)s\n" % dict(msg=msg))) - first_line = False + if should_skip: + return + + new_changelog = os.path.join(dest_dir, 'ChangeLog') + # If there's already a ChangeLog and it's not writable, just use it + if (os.path.exists(new_changelog) + and not os.access(new_changelog, os.W_OK)): + return + log.info('[pbr] Writing ChangeLog') + if git_dir is None: + git_dir = _get_git_directory() + if not git_dir: + return + + log_cmd = ['log', '--oneline', '--decorate'] + changelog = _run_git_command(log_cmd, git_dir) + first_line = True + with io.open(new_changelog, "w", + encoding="utf-8") as changelog_file: + changelog_file.write("CHANGES\n=======\n\n") + for line in changelog.split('\n'): + line_parts = line.split() + if len(line_parts) < 2: + continue + # Tags are in a list contained in ()'s. If a commit + # subject that is tagged happens to have ()'s in it + # this will fail + if line_parts[1].startswith('(') and ')' in line: + msg = line.split(')')[1].strip() + else: + msg = " ".join(line_parts[1:]) + + if "tag:" in line: + tags = [ + tag.split(",")[0] + for tag in line.split(")")[0].split("tag: ")[1:]] + tag = _get_highest_tag(tags) + + underline = len(tag) * '-' + if not first_line: + changelog_file.write('\n') + changelog_file.write( + ("%(tag)s\n%(underline)s\n\n" % + dict(tag=tag, + underline=underline))) + + if not msg.startswith("Merge "): + if msg.endswith("."): + msg = msg[:-1] + changelog_file.write( + ("* %(msg)s\n" % dict(msg=msg))) + first_line = False def generate_authors(git_dir=None, dest_dir='.', option_dict=dict()): """Create AUTHORS file using git commits.""" should_skip = get_boolean_option(option_dict, 'skip_authors', 'SKIP_GENERATE_AUTHORS') - if not should_skip: - old_authors = os.path.join(dest_dir, 'AUTHORS.in') - new_authors = os.path.join(dest_dir, 'AUTHORS') - # If there's already an AUTHORS file and it's not writable, just use it - if (os.path.exists(new_authors) - and not os.access(new_authors, os.W_OK)): - return - log.info('[pbr] Generating AUTHORS') - ignore_emails = '(jenkins@review|infra@lists|jenkins@openstack)' - if git_dir is None: - git_dir = _get_git_directory() - if git_dir: - authors = [] - - # don't include jenkins email address in AUTHORS file - git_log_cmd = ['log', '--format=%aN <%aE>'] - authors += _run_git_command(git_log_cmd, git_dir).split('\n') - authors = [a for a in authors if not re.search(ignore_emails, a)] - - # get all co-authors from commit messages - co_authors_out = _run_git_command('log', git_dir) - co_authors = re.findall('Co-authored-by:.+', co_authors_out, - re.MULTILINE) - co_authors = [signed.split(":", 1)[1].strip() - for signed in co_authors if signed] - - authors += co_authors - authors = sorted(set(authors)) - - with open(new_authors, 'wb') as new_authors_fh: - if os.path.exists(old_authors): - with open(old_authors, "rb") as old_authors_fh: - new_authors_fh.write(old_authors_fh.read()) - new_authors_fh.write(('\n'.join(authors) + '\n') - .encode('utf-8')) + if should_skip: + return + + old_authors = os.path.join(dest_dir, 'AUTHORS.in') + new_authors = os.path.join(dest_dir, 'AUTHORS') + # If there's already an AUTHORS file and it's not writable, just use it + if (os.path.exists(new_authors) + and not os.access(new_authors, os.W_OK)): + return + log.info('[pbr] Generating AUTHORS') + ignore_emails = '(jenkins@review|infra@lists|jenkins@openstack)' + if git_dir is None: + git_dir = _get_git_directory() + if git_dir: + authors = [] + + # don't include jenkins email address in AUTHORS file + git_log_cmd = ['log', '--format=%aN <%aE>'] + authors += _run_git_command(git_log_cmd, git_dir).split('\n') + authors = [a for a in authors if not re.search(ignore_emails, a)] + + # get all co-authors from commit messages + co_authors_out = _run_git_command('log', git_dir) + co_authors = re.findall('Co-authored-by:.+', co_authors_out, + re.MULTILINE) + co_authors = [signed.split(":", 1)[1].strip() + for signed in co_authors if signed] + + authors += co_authors + authors = sorted(set(authors)) + + with open(new_authors, 'wb') as new_authors_fh: + if os.path.exists(old_authors): + with open(old_authors, "rb") as old_authors_fh: + new_authors_fh.write(old_authors_fh.read()) + new_authors_fh.write(('\n'.join(authors) + '\n') + .encode('utf-8')) def _find_git_files(dirname='', git_dir=None): diff --git a/pbr/testr_command.py b/pbr/testr_command.py index bf36b27..34b02ed 100644 --- a/pbr/testr_command.py +++ b/pbr/testr_command.py @@ -125,7 +125,7 @@ class Testr(cmd.Command): # Use this as coverage package name if self.coverage_package_name: package = self.coverage_package_name - options = "--source %s --parallel-mode" % self.coverage_package_name + options = "--source %s --parallel-mode" % package os.environ['PYTHON'] = ("coverage run %s" % options) logger.debug("os.environ['PYTHON'] = %r", os.environ['PYTHON']) @@ -36,6 +36,8 @@ warnerrors = True [entry_points] distutils.setup_keywords = pbr = pbr.core:pbr +distutils.commands = + testr = pbr.testr_command:Testr [build_sphinx] all_files = 1 diff --git a/tools/integration.sh b/tools/integration.sh index b6021f3..8c2db5e 100644 --- a/tools/integration.sh +++ b/tools/integration.sh @@ -43,7 +43,14 @@ BASE=${BASE:-/opt/stack} REPODIR=${REPODIR:-$BASE/new} # TODO: Figure out how to get this on to the box properly -sudo apt-get install -y --force-yes libxml2-dev libxslt-dev libmysqlclient-dev libpq-dev libnspr4-dev pkg-config libsqlite3-dev libzmq-dev libffi-dev libldap2-dev libsasl2-dev +sudo apt-get install -y --force-yes libxml2-dev libxslt-dev libmysqlclient-dev libpq-dev libnspr4-dev pkg-config libsqlite3-dev libzmq-dev libffi-dev libldap2-dev libsasl2-dev ccache + +# FOR numpy / pyyaml +sudo apt-get build-dep -y --force-yes python-numpy +sudo apt-get build-dep -y --force-yes python-yaml + +# And use ccache explitly +export PATH=/usr/lib/ccache:$PATH tmpdir=$(mktemp -d) @@ -93,7 +100,7 @@ if [ ! -d /etc/apache2/sites-enabled/ ] ; then exit 1 fi -sudo rm /etc/apache2/sites-enabled/* +sudo rm -f /etc/apache2/sites-enabled/* cat <<EOF > $tmpdir/pypi.conf <VirtualHost *:80> ServerAdmin webmaster@localhost @@ -101,8 +108,21 @@ cat <<EOF > $tmpdir/pypi.conf Options Indexes FollowSymLinks </VirtualHost> EOF -sudo mv $tmpdir/pypi.conf /etc/apache2/sites-available/pypi -sudo chown root:root /etc/apache2/sites-available/pypi + +# NOTE(dhellmann): This logic is copied from apache_site_config_for +# devstack/lib/apache with non-Ubuntu OSes left out because we don't +# run this integration test anywhere else for now. +apache_version=$(/usr/sbin/apache2ctl -v | awk '/Server version/ {print $3}' | cut -f2 -d/) +if [[ "$apache_version" =~ ^2\.2\. ]] +then + # Ubuntu 12.04 - Apache 2.2 + apache_conf=/etc/apache2/sites-available/pypi +else + # Ubuntu 14.04 - Apache 2.4 + apache_conf=/etc/apache2/sites-available/pypi.conf +fi +sudo mv $tmpdir/pypi.conf $apache_conf +sudo chown root:root $apache_conf sudo a2ensite pypi sudo service apache2 reload |