| # 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 os |
| |
| 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) |