diff --git a/.gitignore b/.gitignore index eeccc0fb..2c05c8e2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ build dist python_openstackclient.egg-info +.tox/ +ChangeLog diff --git a/.gitreview b/.gitreview new file mode 100644 index 00000000..784c1900 --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=review.openstack.org +port=29418 +project=openstack/python-openstackclient.git diff --git a/openstackclient/openstack/common/setup.py b/openstackclient/openstack/common/setup.py new file mode 100644 index 00000000..43761027 --- /dev/null +++ b/openstackclient/openstack/common/setup.py @@ -0,0 +1,140 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Utilities with minimum-depends for use in setup.py +""" + +import os +import re +import subprocess + + +def parse_mailmap(mailmap='.mailmap'): + mapping = {} + if os.path.exists(mailmap): + fp = open(mailmap, 'r') + for l in fp: + l = l.strip() + if not l.startswith('#') and ' ' in l: + canonical_email, alias = l.split(' ') + mapping[alias] = canonical_email + return mapping + + +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 +def get_reqs_from_files(requirements_files): + reqs_in = [] + for requirements_file in requirements_files: + if os.path.exists(requirements_file): + return open(requirements_file, 'r').read().split('\n') + return [] + + +def parse_requirements(requirements_files=['requirements.txt', + 'tools/pip-requires']): + requirements = [] + for line in get_reqs_from_files(requirements_files): + if re.match(r'\s*-e\s+', line): + requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1', + line)) + elif re.match(r'\s*-f\s+', line): + pass + else: + requirements.append(line) + + return requirements + + +def parse_dependency_links(requirements_files=['requirements.txt', + 'tools/pip-requires']): + dependency_links = [] + for line in get_reqs_from_files(requirements_files): + if re.match(r'(\s*#)|(\s*$)', line): + continue + if re.match(r'\s*-[ef]\s+', line): + dependency_links.append(re.sub(r'\s*-[ef]\s+', '', line)) + return dependency_links + + +def write_requirements(): + venv = os.environ.get('VIRTUAL_ENV', None) + if venv is not None: + with open("requirements.txt", "w") as req_file: + output = subprocess.Popen(["pip", "-E", venv, "freeze", "-l"], + stdout=subprocess.PIPE) + requirements = output.communicate()[0].strip() + req_file.write(requirements) + + +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_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. :) +version_info = { + 'branch_nick': '%s', + 'revision_id': '%s', + 'revno': %s +} +""" % (branch_nick, revid, revno)) + + +def write_git_changelog(): + """Write a changelog based on the git changelog""" + if os.path.isdir('.git'): + 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(canonicalize_emails(changelog, mailmap)) + + +def generate_authors(): + """Create AUTHORS file using git commits""" + jenkins_email = 'jenkins@review.openstack.org' + if os.path.isdir('.git'): + # don't include jenkins email address in AUTHORS file + git_log_cmd = "git log --format='%aN <%aE>' | sort -u | " \ + "grep -v " + jenkins_email + changelog = _run_shell_command(git_log_cmd) + mailmap = parse_mailmap() + with open("AUTHORS", "w") as authors_file: + authors_file.write(canonicalize_emails(changelog, mailmap)) diff --git a/openstackclient/shell.py b/openstackclient/shell.py index 3e8c6dca..50df0d15 100644 --- a/openstackclient/shell.py +++ b/openstackclient/shell.py @@ -95,17 +95,20 @@ class OpenStackShell(App): parser.add_argument('--os-identity-api-version', metavar='', default=env('OS_IDENTITY_API_VERSION', default='2.0'), - help='Identity API version, default=2.0 (Env: OS_IDENTITY_API_VERSION)') + help='Identity API version, default=2.0 '\ + '(Env: OS_IDENTITY_API_VERSION)') parser.add_argument('--os-compute-api-version', metavar='', default=env('OS_COMPUTE_API_VERSION', default='2'), - help='Compute API version, default=2 (Env: OS_COMPUTE_API_VERSION)') + help='Compute API version, default=2 '\ + '(Env: OS_COMPUTE_API_VERSION)') parser.add_argument('--os-image-api-version', metavar='', default=env('OS_IMAGE_API_VERSION', default='1.0'), - help='Image API version, default=1.0 (Env: OS_IMAGE_API_VERSION)') + help='Image API version, default=1.0 '\ + '(Env: OS_IMAGE_API_VERSION)') parser.add_argument('--os-token', metavar='', default=env('OS_TOKEN'), @@ -130,7 +133,10 @@ class OpenStackShell(App): } if self.options.debug: - print "API: Identity=%s Compute=%s Image=%s" % (self.api_version['identity'], self.api_version['compute'], self.api_version['image']) + print "API: Identity=%s Compute=%s Image=%s" % ( + self.api_version['identity'], + self.api_version['compute'], + self.api_version['image']) print "cmd: %s" % cmd # do checking of os_username, etc here @@ -169,7 +175,8 @@ class OpenStackShell(App): auth_url=kwargs.get('auth_url'), ) token = self.auth_client.auth_token - endpoint = self.auth_client.service_catalog.url_for(service_type=cmd.api) + endpoint = self.auth_client.service_catalog.url_for( + service_type=cmd.api) if self.options.debug: print "api: %s" % cmd.api diff --git a/setup.cfg b/setup.cfg index d63913d3..2388434f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -3,6 +3,8 @@ cover-package = openstackclient cover-html = true cover-erase = true cover-inclusive = true +verbosity=2 +detailed-errors=1 [build_sphinx] source-dir = docs/ diff --git a/setup.py b/setup.py index 93e8f015..4df5cded 100644 --- a/setup.py +++ b/setup.py @@ -1,36 +1,30 @@ import os -import sys -from setuptools import setup, find_packages + +import setuptools + +from openstackclient.openstack.common.setup import parse_requirements +from openstackclient.openstack.common.setup import parse_dependency_links +from openstackclient.openstack.common.setup import write_git_changelog + + +requires = parse_requirements() +dependency_links = parse_dependency_links() +write_git_changelog() def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() -requirements = [ - 'cliff', - 'distribute', - 'httplib2', - 'prettytable', - "python-keystoneclient >= 2012.1", - "python-novaclient >= 2012.1", -] - -if sys.version_info < (2, 6): - requirements.append('simplejson') -if sys.version_info < (2, 7): - requirements.append("argparse") - -setup( - name = "python-openstackclient", - version = "2012.0", - description = "OpenStack command-line client", - long_description = read('README.rst'), +setuptools.setup( + name="python-openstackclient", + version="2012.2", + description="OpenStack command-line client", + long_description=read('README.rst'), + url='https://github.com/openstack/python-openstackclient', license="Apache License, Version 2.0", - author = "Dean Troyer", - author_email = "dtroyer@gmail.com", - packages=find_packages(exclude=['tests', 'tests.*']), - url = "https://github.com/dtroyer/python-openstackclient", - install_requires=requirements, + author='OpenStack Client Contributors', + author_email='openstackclient@example.com', + packages=setuptools.find_packages(exclude=['tests', 'tests.*']), classifiers=[ 'Development Status :: 2 - Pre-Alpha', 'Environment :: Console', @@ -39,18 +33,16 @@ setup( 'License :: OSI Approved :: Apache Software License', 'Operating System :: OS Independent', 'Programming Language :: Python', - ], - - tests_require = ["nose", "mock", "mox"], - test_suite = "nose.collector", - - entry_points = { - 'console_scripts': ['stack = openstackclient.shell:main'], + ], + install_requires=requires, + dependency_links=dependency_links, + test_suite="nose.collector", + entry_points={ + 'console_scripts': ['stack=openstackclient.shell:main'], 'openstack.cli': [ - 'list_server = openstackclient.compute.v2.server:List_Server', - 'show_server = openstackclient.compute.v2.server:Show_Server', - 'list_service = openstackclient.identity.v2_0.service:List_Service', + 'list_server=openstackclient.compute.v2.server:List_Server', + 'show_server=openstackclient.compute.v2.server:Show_Server', + 'list_service=openstackclient.identity.v2_0.service:List_Service', ] } ) - diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..624754bb --- /dev/null +++ b/tox.ini @@ -0,0 +1,46 @@ +[tox] +envlist = py26,py27,pep8 + +[testenv] +setenv = VIRTUAL_ENV={envdir} + NOSE_WITH_OPENSTACK=1 + NOSE_OPENSTACK_COLOR=1 + NOSE_OPENSTACK_RED=0.05 + NOSE_OPENSTACK_YELLOW=0.025 + NOSE_OPENSTACK_SHOW_ELAPSED=1 +deps = -r{toxinidir}/tools/pip-requires + -r{toxinidir}/tools/test-requires +commands = nosetests + +[testenv:pep8] +deps = pep8 +commands = pep8 --repeat --show-source openstackclient setup.py + +[testenv:venv] +commands = {posargs} + +[testenv:cover] +commands = nosetests --cover-erase --cover-package=openstackclient --with-xcoverage + +[tox:jenkins] +downloadcache = ~/cache/pip + +[testenv:jenkins26] +basepython = python2.6 +setenv = NOSE_WITH_XUNIT=1 +deps = file://{toxinidir}/.cache.bundle + +[testenv:jenkins27] +basepython = python2.7 +setenv = NOSE_WITH_XUNIT=1 +deps = file://{toxinidir}/.cache.bundle + +[testenv:jenkinscover] +deps = file://{toxinidir}/.cache.bundle +setenv = NOSE_WITH_XUNIT=1 +commands = nosetests --cover-erase --cover-package=openstackclient --with-xcoverage + +[testenv:jenkinsvenv] +deps = file://{toxinidir}/.cache.bundle +setenv = NOSE_WITH_XUNIT=1 +commands = {posargs}