diff --git a/.gitignore b/.gitignore index 663816576..88e3a1208 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ ChangeLog *.deb dist *.egg +ceilometer/versioninfo diff --git a/ceilometer/openstack/common/setup.py b/ceilometer/openstack/common/setup.py index 83eef07a7..e6f72f034 100644 --- a/ceilometer/openstack/common/setup.py +++ b/ceilometer/openstack/common/setup.py @@ -117,8 +117,12 @@ def write_requirements(): def _run_shell_command(cmd): - output = subprocess.Popen(["/bin/sh", "-c", cmd], - stdout=subprocess.PIPE) + if os.name == 'nt': + output = subprocess.Popen(["cmd.exe", "/C", cmd], + stdout=subprocess.PIPE) + else: + output = subprocess.Popen(["/bin/sh", "-c", cmd], + stdout=subprocess.PIPE) out = output.communicate() if len(out) == 0: return None diff --git a/ceilometer/openstack/common/version.py b/ceilometer/openstack/common/version.py new file mode 100644 index 000000000..a19e42265 --- /dev/null +++ b/ceilometer/openstack/common/version.py @@ -0,0 +1,148 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack LLC +# +# 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 for consuming the auto-generated versioninfo files. +""" + +import datetime +import pkg_resources + +import setup + + +class _deferred_version_string(object): + """Internal helper class which provides delayed version calculation.""" + def __init__(self, version_info, prefix): + self.version_info = version_info + self.prefix = prefix + + def __str__(self): + return "%s%s" % (self.prefix, self.version_info.version_string()) + + def __repr__(self): + return "%s%s" % (self.prefix, self.version_info.version_string()) + + +class VersionInfo(object): + + def __init__(self, package, python_package=None, pre_version=None): + """Object that understands versioning for a package + :param package: name of the top level python namespace. For glance, + this would be "glance" for python-glanceclient, it + would be "glanceclient" + :param python_package: optional name of the project name. For + glance this can be left unset. For + python-glanceclient, this would be + "python-glanceclient" + :param pre_version: optional version that the project is working to + """ + self.package = package + if python_package is None: + self.python_package = package + else: + self.python_package = python_package + self.pre_version = pre_version + self.version = None + + def _generate_version(self): + """Defer to the openstack.common.setup routines for making a + version from git.""" + if self.pre_version is None: + return setup.get_post_version(self.python_package) + else: + return setup.get_pre_version(self.python_package, self.pre_version) + + def _newer_version(self, pending_version): + """Check to see if we're working with a stale version or not. + We expect a version string that either looks like: + 2012.2~f3~20120708.10.4426392 + which is an unreleased version of a pre-version, or: + 0.1.1.4.gcc9e28a + which is an unreleased version of a post-version, or: + 0.1.1 + Which is a release and which should match tag. + For now, if we have a date-embedded version, check to see if it's + old, and if so re-generate. Otherwise, just deal with it. + """ + try: + version_date = int(self.version.split("~")[-1].split('.')[0]) + if version_date < int(datetime.date.today().strftime('%Y%m%d')): + return self._generate_version() + else: + return pending_version + except Exception: + return pending_version + + def version_string_with_vcs(self, always=False): + """Return the full version of the package including suffixes indicating + VCS status. + + For instance, if we are working towards the 2012.2 release, + canonical_version_string should return 2012.2 if this is a final + release, or else something like 2012.2~f1~20120705.20 if it's not. + + :param always: if true, skip all version caching + """ + if always: + self.version = self._generate_version() + + if self.version is None: + + requirement = pkg_resources.Requirement.parse(self.python_package) + versioninfo = "%s/versioninfo" % self.package + try: + raw_version = pkg_resources.resource_string(requirement, + versioninfo) + self.version = self._newer_version(raw_version.strip()) + except (IOError, pkg_resources.DistributionNotFound): + self.version = self._generate_version() + + return self.version + + def canonical_version_string(self, always=False): + """Return the simple version of the package excluding any suffixes. + + For instance, if we are working towards the 2012.2 release, + canonical_version_string should return 2012.2 in all cases. + + :param always: if true, skip all version caching + """ + return self.version_string_with_vcs(always).split('~')[0] + + def version_string(self, always=False): + """Return the base version of the package. + + For instance, if we are working towards the 2012.2 release, + version_string should return 2012.2 if this is a final release, or + 2012.2-dev if it is not. + + :param always: if true, skip all version caching + """ + version_parts = self.version_string_with_vcs(always).split('~') + if len(version_parts) == 1: + return version_parts[0] + else: + return '%s-dev' % (version_parts[0],) + + def deferred_version_string(self, prefix=""): + """Generate an object which will expand in a string context to + the results of version_string(). We do this so that don't + call into pkg_resources every time we start up a program when + passing version information into the CONF constructor, but + rather only do the calculation when and if a version is requested + """ + return _deferred_version_string(self, prefix) diff --git a/ceilometer/version.py b/ceilometer/version.py new file mode 100644 index 000000000..df88c0507 --- /dev/null +++ b/ceilometer/version.py @@ -0,0 +1,26 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2012 New Dream Network, LLC (DreamHost) +# +# Author: Doug Hellmann +# +# 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. +"""Version information for ceilometer. +""" + +from ceilometer.openstack.common import version as common_version + +NEXT_VERSION = '2013.1' + +version_info = common_version.VersionInfo('ceilometer', + pre_version=NEXT_VERSION) diff --git a/doc/source/conf.py b/doc/source/conf.py index a0a028359..70131677e 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -57,9 +57,9 @@ copyright = u'2012, OpenStack, LLC' # # The short X.Y version. #version = '0.0' -version = os.popen('cd ../..; python setup.py --version', 'r').read().strip() -# The full version, including alpha/beta/rc tags. -release = version +from ceilometer.version import version_info as ceilometer_version +release = ceilometer_version.version_string_with_vcs() +version = ceilometer_version.canonical_version_string() # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/openstack-common.conf b/openstack-common.conf index a1062a61c..049da9b67 100644 --- a/openstack-common.conf +++ b/openstack-common.conf @@ -1,3 +1,3 @@ [DEFAULT] -modules=cfg,iniparser,rpc,importutils,excutils,local,jsonutils,gettextutils,timeutils,notifier,context,log,network_utils,setup,policy,service,threadgroup,eventlet_backdoor,loopingcall +modules=cfg,iniparser,rpc,importutils,excutils,local,jsonutils,gettextutils,timeutils,notifier,context,log,network_utils,setup,policy,service,threadgroup,eventlet_backdoor,loopingcall,version base=ceilometer diff --git a/setup.py b/setup.py index 71312a9bc..7626d3c72 100755 --- a/setup.py +++ b/setup.py @@ -22,12 +22,13 @@ import os import setuptools from ceilometer.openstack.common import setup as common_setup +from ceilometer.version import version_info requires = common_setup.parse_requirements(['tools/pip-requires']) depend_links = common_setup.parse_dependency_links(['tools/pip-requires']) -version = '0.2' url_base = 'http://tarballs.openstack.org/ceilometer/ceilometer-%s.tar.gz' +version_string = version_info.canonical_version_string(always=True) def directories(target_dir): @@ -38,7 +39,7 @@ def directories(target_dir): setuptools.setup( name='ceilometer', - version=version, + version=version_string, description='cloud computing metering', @@ -46,7 +47,7 @@ setuptools.setup( author_email='ceilometer@lists.launchpad.net', url='https://launchpad.net/ceilometer', - download_url=url_base % version, + download_url=url_base % version_string, classifiers=[ 'Development Status :: 3 - Alpha',