diff options
| author | Monty Taylor <mordred@inaugust.com> | 2012-06-25 11:31:49 -0500 |
|---|---|---|
| committer | Monty Taylor <mordred@inaugust.com> | 2012-06-25 11:31:49 -0500 |
| commit | 99586e05d7f70e0adb2eddaff7f079ec04b464fd (patch) | |
| tree | 0428e2b41fb1947faea74a635cbfe3b40d52f736 /openstackclient | |
| parent | 01dd4540c5d444274b02f71184a9779012c6c5e6 (diff) | |
| download | python-openstackclient-99586e05d7f70e0adb2eddaff7f079ec04b464fd.tar.gz | |
Add post-tag versioning.
Change-Id: I98e5f7aa788b1ab1a866b21e0a17a63b8d5efae3
Diffstat (limited to 'openstackclient')
| -rw-r--r-- | openstackclient/openstack/common/setup.py | 228 |
1 files changed, 206 insertions, 22 deletions
diff --git a/openstackclient/openstack/common/setup.py b/openstackclient/openstack/common/setup.py index 60c731a9..e9cd3400 100644 --- a/openstackclient/openstack/common/setup.py +++ b/openstackclient/openstack/common/setup.py @@ -19,9 +19,13 @@ Utilities with minimum-depends for use in setup.py """ +import datetime import os import re import subprocess +import sys + +from setuptools.command import sdist def parse_mailmap(mailmap='.mailmap'): @@ -58,11 +62,25 @@ def parse_requirements(requirements_files=['requirements.txt', 'tools/pip-requires']): requirements = [] for line in get_reqs_from_files(requirements_files): + # For the requirements list, we need to inject only the portion + # after egg= so that distutils knows the package it's looking for + # such as: + # -e git://github.com/openstack/nova/master#egg=nova if re.match(r'\s*-e\s+', line): requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1', line)) + # such as: + # http://github.com/openstack/nova/zipball/master#egg=nova + elif re.match(r'\s*https?:', line): + requirements.append(re.sub(r'\s*https?:.*#egg=(.*)$', r'\1', + line)) + # -f lines are for index locations, and don't get used here elif re.match(r'\s*-f\s+', line): pass + # argparse is part of the standard library starting with 2.7 + # adding it to the requirements list screws distro installs + elif line == 'argparse' and sys.version_info >= (2, 7): + pass else: requirements.append(line) @@ -72,11 +90,18 @@ def parse_requirements(requirements_files=['requirements.txt', def parse_dependency_links(requirements_files=['requirements.txt', 'tools/pip-requires']): dependency_links = [] + # dependency_links inject alternate locations to find packages listed + # in requirements for line in get_reqs_from_files(requirements_files): + # skip comments and blank lines if re.match(r'(\s*#)|(\s*$)', line): continue + # lines with -e or -f need the whole line, minus the flag if re.match(r'\s*-[ef]\s+', line): dependency_links.append(re.sub(r'\s*-[ef]\s+', '', line)) + # lines that are only urls can go in unmolested + elif re.match(r'\s*https?:', line): + dependency_links.append(line) return dependency_links @@ -93,28 +118,54 @@ def write_requirements(): def _run_shell_command(cmd): output = subprocess.Popen(["/bin/sh", "-c", cmd], stdout=subprocess.PIPE) - return output.communicate()[0].strip() + out = output.communicate() + if len(out) == 0: + return None + if len(out[0].strip()) == 0: + return None + return out[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 _get_git_next_version_suffix(branch_name): + datestamp = datetime.datetime.now().strftime('%Y%m%d') + if branch_name == 'milestone-proposed': + revno_prefix = "r" + else: + revno_prefix = "" + _run_shell_command("git fetch origin +refs/meta/*:refs/remotes/meta/*") + milestone_cmd = "git show meta/openstack/release:%s" % branch_name + milestonever = _run_shell_command(milestone_cmd) + if not milestonever: + milestonever = "" + post_version = _get_git_post_version() + revno = post_version.split(".")[-1] + return "%s~%s.%s%s" % (milestonever, datestamp, revno_prefix, revno) + + +def _get_git_current_tag(): + return _run_shell_command("git tag --contains HEAD") + + +def _get_git_tag_info(): + return _run_shell_command("git describe --tags") + + +def _get_git_post_version(): + current_tag = _get_git_current_tag() + if current_tag is not None: + return current_tag + else: + tag_info = _get_git_tag_info() + if tag_info is None: + base_version = "0.0" + cmd = "git --no-pager log --oneline" + out = _run_shell_command(cmd) + revno = len(out.split("\n")) + else: + tag_infos = tag_info.split("-") + base_version = "-".join(tag_infos[:-2]) + revno = tag_infos[-2] + return "%s.%s" % (base_version, revno) def write_git_changelog(): @@ -134,8 +185,8 @@ def generate_authors(): new_authors = 'AUTHORS' 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 + 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(new_authors, 'w') as new_authors_fh: @@ -143,3 +194,136 @@ def generate_authors(): if os.path.exists(old_authors): with open(old_authors, "r") as old_authors_fh: new_authors_fh.write('\n' + old_authors_fh.read()) + +_rst_template = """%(heading)s +%(underline)s + +.. automodule:: %(module)s + :members: + :undoc-members: + :show-inheritance: +""" + + +def write_versioninfo(project, version): + """Write a simple file containing the version of the package.""" + open(os.path.join(project, 'versioninfo'), 'w').write("%s\n" % version) + + +def get_cmdclass(): + """Return dict of commands to run from setup.py.""" + + cmdclass = dict() + + def _find_modules(arg, dirname, files): + for filename in files: + if filename.endswith('.py') and filename != '__init__.py': + arg["%s.%s" % (dirname.replace('/', '.'), + filename[:-3])] = True + + class LocalSDist(sdist.sdist): + """Builds the ChangeLog and Authors files from VC first.""" + + def run(self): + write_git_changelog() + generate_authors() + # sdist.sdist is an old style class, can't use super() + sdist.sdist.run(self) + + cmdclass['sdist'] = LocalSDist + + # If Sphinx is installed on the box running setup.py, + # enable setup.py to build the documentation, otherwise, + # just ignore it + try: + from sphinx.setup_command import BuildDoc + + class LocalBuildDoc(BuildDoc): + def generate_autoindex(self): + print "**Autodocumenting from %s" % os.path.abspath(os.curdir) + modules = {} + option_dict = self.distribution.get_option_dict('build_sphinx') + source_dir = os.path.join(option_dict['source_dir'][1], 'api') + if not os.path.exists(source_dir): + os.makedirs(source_dir) + for pkg in self.distribution.packages: + if '.' not in pkg: + os.path.walk(pkg, _find_modules, modules) + module_list = modules.keys() + module_list.sort() + autoindex_filename = os.path.join(source_dir, 'autoindex.rst') + with open(autoindex_filename, 'w') as autoindex: + autoindex.write(""".. toctree:: + :maxdepth: 1 + +""") + for module in module_list: + output_filename = os.path.join(source_dir, + "%s.rst" % module) + heading = "The :mod:`%s` Module" % module + underline = "=" * len(heading) + values = dict(module=module, heading=heading, + underline=underline) + + print "Generating %s" % output_filename + with open(output_filename, 'w') as output_file: + output_file.write(_rst_template % values) + autoindex.write(" %s.rst\n" % module) + + def run(self): + if not os.getenv('SPHINX_DEBUG'): + self.generate_autoindex() + + for builder in ['html', 'man']: + self.builder = builder + self.finalize_options() + self.project = self.distribution.get_name() + self.version = self.distribution.get_version() + self.release = self.distribution.get_version() + BuildDoc.run(self) + cmdclass['build_sphinx'] = LocalBuildDoc + except ImportError: + pass + + return cmdclass + + +def get_git_branchname(): + for branch in _run_shell_command("git branch --color=never").split("\n"): + if branch.startswith('*'): + _branch_name = branch.split()[1].strip() + if _branch_name == "(no": + _branch_name = "no-branch" + return _branch_name + + +def get_pre_version(projectname, base_version): + """Return a version which is based""" + if os.path.isdir('.git'): + current_tag = _get_git_current_tag() + if current_tag is not None: + version = current_tag + else: + branch_name = os.getenv('BRANCHNAME', + os.getenv('GERRIT_REFNAME', + get_git_branchname())) + version_suffix = _get_git_next_version_suffix(branch_name) + version = "%s~%s" % (base_version, version_suffix) + write_versioninfo(projectname, version) + return version.split('~')[0] + else: + with open(os.path.join(projectname, 'versioninfo'), 'r') as vinfo: + full_version = vinfo.read().strip() + return full_version.split('~')[0] + + +def get_post_version(projectname): + """Return a version which is equal to the tag that's on the current + revision if there is one, or tag plus number of additional revisions + if the current revision has no tag.""" + + if os.path.isdir('.git'): + version = _get_git_post_version() + write_versioninfo(projectname, version) + return version + return open(os.path.join(projectname, 'versioninfo'), 'r').read().strip() |
