diff --git a/melange/openstack/common/config.py b/melange/openstack/common/config.py index a5fc3f09..7ae703e1 100644 --- a/melange/openstack/common/config.py +++ b/melange/openstack/common/config.py @@ -62,8 +62,8 @@ def add_common_options(parser): :param parser: optparse.OptionParser """ - help_text = "The following configuration options are common to "\ - "this app's programs." + help_text = ("The following configuration options are common to " + "this app's programs.") group = optparse.OptionGroup(parser, "Common Options", help_text) group.add_option('-v', '--verbose', default=False, dest="verbose", @@ -88,8 +88,8 @@ def add_log_options(parser): :param parser: optparse.OptionParser """ - help_text = "The following configuration options are specific to logging "\ - "functionality for this program." + help_text = ("The following configuration options are specific to " + "logging functionality for this program.") group = optparse.OptionGroup(parser, "Logging Options", help_text) group.add_option('--log-config', default=None, metavar="PATH", @@ -133,10 +133,10 @@ def setup_logging(options, conf): # If either the CLI option or the conf value # is True, we set to True - debug = options.get('debug') or \ - get_option(conf, 'debug', type='bool', default=False) - verbose = options.get('verbose') or \ - get_option(conf, 'verbose', type='bool', default=False) + debug = (options.get('debug') or + get_option(conf, 'debug', type='bool', default=False)) + verbose = (options.get('verbose') or + get_option(conf, 'verbose', type='bool', default=False)) root_logger = logging.root if debug: root_logger.setLevel(logging.DEBUG) @@ -157,8 +157,8 @@ def setup_logging(options, conf): if not logfile: logfile = conf.get('log_file') - use_syslog = options.get('use_syslog') or \ - get_option(conf, 'use_syslog', type='bool', default=False) + use_syslog = (options.get('use_syslog') or + get_option(conf, 'use_syslog', type='bool', default=False)) if use_syslog: handler = logging.handlers.SysLogHandler(address='/dev/log') @@ -289,10 +289,10 @@ def load_paste_app(app_name, options, args, config_dir=None): # We only update the conf dict for the verbose and debug # flags. Everything else must be set up in the conf file... - debug = options.get('debug') or \ - get_option(conf, 'debug', type='bool', default=False) - verbose = options.get('verbose') or \ - get_option(conf, 'verbose', type='bool', default=False) + debug = (options.get('debug') or + get_option(conf, 'debug', type='bool', default=False)) + verbose = (options.get('verbose') or + get_option(conf, 'verbose', type='bool', default=False)) conf['debug'] = debug conf['verbose'] = verbose diff --git a/melange/openstack/common/setup.py b/melange/openstack/common/setup.py index 4f822814..9eabfcca 100644 --- a/melange/openstack/common/setup.py +++ b/melange/openstack/common/setup.py @@ -36,10 +36,13 @@ def parse_mailmap(mailmap='.mailmap'): return mapping -def str_dict_replace(s, mapping): - for s1, s2 in mapping.iteritems(): - s = s.replace(s1, s2) - return s +def canonicalize_emails(changelog, mapping): + """ Takes in a string and an email alias mapping and replaces all + instances of the aliases in the string with their real email + """ + for alias, email in mapping.iteritems(): + changelog = changelog.replace(alias, email) + return changelog # Get requirements from the first file that exists @@ -87,20 +90,22 @@ def write_requirements(): req_file.write(requirements) -def run_git_command(cmd): +def _run_shell_command(cmd): output = subprocess.Popen(["/bin/sh", "-c", cmd], stdout=subprocess.PIPE) return output.communicate()[0].strip() def write_vcsversion(location): + """ Produce a vcsversion dict that mimics the old one produced by bzr + """ if os.path.isdir('.git'): branch_nick_cmd = 'git branch | grep -Ei "\* (.*)" | cut -f2 -d" "' - branch_nick = run_git_command(branch_nick_cmd) - revid_cmd = "git --no-pager log --max-count=1 --pretty=oneline" - revid = run_git_command(revid_cmd).split()[0] - revno_cmd = "git --no-pager log --oneline | wc -l" - revno = run_git_command(revno_cmd) + branch_nick = _run_shell_command(branch_nick_cmd) + revid_cmd = "git rev-parse HEAD" + revid = _run_shell_command(revid_cmd).split()[0] + revno_cmd = "git log --oneline | wc -l" + revno = _run_shell_command(revno_cmd) with open(location, 'w') as version_file: version_file.write(""" # This file is automatically generated by setup.py, So don't edit it. :) @@ -113,9 +118,10 @@ version_info = { def write_git_changelog(): + """ Write a changelog based on the git changelog """ if os.path.isdir('.git'): - git_log_gnu = 'git log --format="%ai %aN %n%n%x09* %s%d%n"' - changelog = run_git_command(git_log_gnu) + git_log_cmd = 'git log --stat' + changelog = _run_shell_command(git_log_cmd) mailmap = parse_mailmap() with open("ChangeLog", "w") as changelog_file: - changelog_file.write(str_dict_replace(changelog, mailmap)) + changelog_file.write(canonicalize_emails(changelog, mailmap)) diff --git a/melange/openstack/common/utils.py b/melange/openstack/common/utils.py index e45e1956..0585d4bd 100644 --- a/melange/openstack/common/utils.py +++ b/melange/openstack/common/utils.py @@ -25,15 +25,15 @@ import os import random import shlex import sys -import types from eventlet import greenthread from eventlet.green import subprocess +import iso8601 from melange.openstack.common import exception -TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" +TIME_FORMAT = "%Y-%m-%dT%H:%M:%S" LOG = logging.getLogger(__name__) @@ -60,9 +60,9 @@ def bool_from_string(subject): Useful for JSON-decoded stuff and config file parsing """ - if isinstance(subject, types.BooleanType): + if isinstance(subject, bool): return subject - if isinstance(subject, types.StringTypes): + if isinstance(subject, basestring): if subject.strip().lower() in ('true', 'on', '1'): return True return False @@ -120,8 +120,9 @@ def execute(*cmd, **kwargs): _returncode = obj.returncode # pylint: disable=E1101 if _returncode: LOG.debug(_('Result was %s') % _returncode) - if type(check_exit_code) == types.IntType \ - and _returncode != check_exit_code: + if (isinstance(check_exit_code, int) and + not isinstance(check_exit_code, bool) and + _returncode != check_exit_code): (stdout, stderr) = result raise exception.ProcessExecutionError( exit_code=_returncode, @@ -163,13 +164,29 @@ def import_object(import_str): def isotime(at=None): + """Stringify time in ISO 8601 format""" if not at: at = datetime.datetime.utcnow() - return at.strftime(TIME_FORMAT) + str = at.strftime(TIME_FORMAT) + tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' + str += ('Z' if tz == 'UTC' else tz) + return str def parse_isotime(timestr): - return datetime.datetime.strptime(timestr, TIME_FORMAT) + """Parse time from ISO 8601 format""" + try: + return iso8601.parse_date(timestr) + except iso8601.ParseError as e: + raise ValueError(e.message) + except TypeError as e: + raise ValueError(e.message) + + +def normalize_time(timestamp): + """Normalize time in arbitrary timezone to UTC""" + offset = timestamp.utcoffset() + return timestamp.replace(tzinfo=None) - offset if offset else timestamp def utcnow(): diff --git a/melange/openstack/common/wsgi.py b/melange/openstack/common/wsgi.py index 132d9676..b01fa74b 100644 --- a/melange/openstack/common/wsgi.py +++ b/melange/openstack/common/wsgi.py @@ -495,8 +495,8 @@ class ResponseSerializer(object): } self.body_serializers.update(body_serializers or {}) - self.headers_serializer = headers_serializer or \ - ResponseHeadersSerializer() + self.headers_serializer = (headers_serializer or + ResponseHeadersSerializer()) def serialize(self, response_data, content_type, action='default'): """Serialize a dict into a string and wrap in a wsgi.Request object. @@ -550,8 +550,8 @@ class RequestDeserializer(object): } self.body_deserializers.update(body_deserializers or {}) - self.headers_deserializer = headers_deserializer or \ - RequestHeadersDeserializer() + self.headers_deserializer = (headers_deserializer or + RequestHeadersDeserializer()) def deserialize(self, request): """Extract necessary pieces of the request. diff --git a/tools/pip-requires b/tools/pip-requires index c452b827..bc0ebb4b 100644 --- a/tools/pip-requires +++ b/tools/pip-requires @@ -13,3 +13,4 @@ webtest factory_boy httplib2 lxml +iso8601