Monty Taylor | da3bada | 2012-11-22 09:38:22 -0800 | [diff] [blame^] | 1 | # vim: tabstop=4 shiftwidth=4 softtabstop=4 |
| 2 | |
| 3 | # Copyright 2012 OpenStack LLC |
| 4 | # |
| 5 | # Licensed under the Apache License, Version 2.0 (the "License"); you may |
| 6 | # not use this file except in compliance with the License. You may obtain |
| 7 | # a copy of the License at |
| 8 | # |
| 9 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | # |
| 11 | # Unless required by applicable law or agreed to in writing, software |
| 12 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 13 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 14 | # License for the specific language governing permissions and limitations |
| 15 | # under the License. |
| 16 | |
| 17 | """ |
| 18 | Utilities for consuming the auto-generated versioninfo files. |
| 19 | """ |
| 20 | |
| 21 | import datetime |
| 22 | import pkg_resources |
| 23 | import os |
| 24 | |
| 25 | import setup |
| 26 | |
| 27 | |
| 28 | class _deferred_version_string(object): |
| 29 | """Internal helper class which provides delayed version calculation.""" |
| 30 | def __init__(self, version_info, prefix): |
| 31 | self.version_info = version_info |
| 32 | self.prefix = prefix |
| 33 | |
| 34 | def __str__(self): |
| 35 | return "%s%s" % (self.prefix, self.version_info.version_string()) |
| 36 | |
| 37 | def __repr__(self): |
| 38 | return "%s%s" % (self.prefix, self.version_info.version_string()) |
| 39 | |
| 40 | |
| 41 | class VersionInfo(object): |
| 42 | |
| 43 | def __init__(self, package, python_package=None, pre_version=None): |
| 44 | """Object that understands versioning for a package |
| 45 | :param package: name of the top level python namespace. For glance, |
| 46 | this would be "glance" for python-glanceclient, it |
| 47 | would be "glanceclient" |
| 48 | :param python_package: optional name of the project name. For |
| 49 | glance this can be left unset. For |
| 50 | python-glanceclient, this would be |
| 51 | "python-glanceclient" |
| 52 | :param pre_version: optional version that the project is working to |
| 53 | """ |
| 54 | self.package = package |
| 55 | if python_package is None: |
| 56 | self.python_package = package |
| 57 | else: |
| 58 | self.python_package = python_package |
| 59 | self.pre_version = pre_version |
| 60 | self.version = None |
| 61 | |
| 62 | def _generate_version(self): |
| 63 | """Defer to the openstack.common.setup routines for making a |
| 64 | version from git.""" |
| 65 | if self.pre_version is None: |
| 66 | return setup.get_post_version(self.python_package) |
| 67 | else: |
| 68 | return setup.get_pre_version(self.python_package, self.pre_version) |
| 69 | |
| 70 | def _newer_version(self, pending_version): |
| 71 | """Check to see if we're working with a stale version or not. |
| 72 | We expect a version string that either looks like: |
| 73 | 2012.2~f3~20120708.10.4426392 |
| 74 | which is an unreleased version of a pre-version, or: |
| 75 | 0.1.1.4.gcc9e28a |
| 76 | which is an unreleased version of a post-version, or: |
| 77 | 0.1.1 |
| 78 | Which is a release and which should match tag. |
| 79 | For now, if we have a date-embedded version, check to see if it's |
| 80 | old, and if so re-generate. Otherwise, just deal with it. |
| 81 | """ |
| 82 | try: |
| 83 | version_date = int(self.version.split("~")[-1].split('.')[0]) |
| 84 | if version_date < int(datetime.date.today().strftime('%Y%m%d')): |
| 85 | return self._generate_version() |
| 86 | else: |
| 87 | return pending_version |
| 88 | except Exception: |
| 89 | return pending_version |
| 90 | |
| 91 | def version_string_with_vcs(self, always=False): |
| 92 | """Return the full version of the package including suffixes indicating |
| 93 | VCS status. |
| 94 | |
| 95 | For instance, if we are working towards the 2012.2 release, |
| 96 | canonical_version_string should return 2012.2 if this is a final |
| 97 | release, or else something like 2012.2~f1~20120705.20 if it's not. |
| 98 | |
| 99 | :param always: if true, skip all version caching |
| 100 | """ |
| 101 | if always: |
| 102 | self.version = self._generate_version() |
| 103 | |
| 104 | if self.version is None: |
| 105 | |
| 106 | requirement = pkg_resources.Requirement.parse(self.python_package) |
| 107 | versioninfo = "%s/versioninfo" % self.package |
| 108 | try: |
| 109 | raw_version = pkg_resources.resource_string(requirement, |
| 110 | versioninfo) |
| 111 | self.version = self._newer_version(raw_version.strip()) |
| 112 | except (IOError, pkg_resources.DistributionNotFound): |
| 113 | self.version = self._generate_version() |
| 114 | |
| 115 | return self.version |
| 116 | |
| 117 | def canonical_version_string(self, always=False): |
| 118 | """Return the simple version of the package excluding any suffixes. |
| 119 | |
| 120 | For instance, if we are working towards the 2012.2 release, |
| 121 | canonical_version_string should return 2012.2 in all cases. |
| 122 | |
| 123 | :param always: if true, skip all version caching |
| 124 | """ |
| 125 | return self.version_string_with_vcs(always).split('~')[0] |
| 126 | |
| 127 | def version_string(self, always=False): |
| 128 | """Return the base version of the package. |
| 129 | |
| 130 | For instance, if we are working towards the 2012.2 release, |
| 131 | version_string should return 2012.2 if this is a final release, or |
| 132 | 2012.2-dev if it is not. |
| 133 | |
| 134 | :param always: if true, skip all version caching |
| 135 | """ |
| 136 | version_parts = self.version_string_with_vcs(always).split('~') |
| 137 | if len(version_parts) == 1: |
| 138 | return version_parts[0] |
| 139 | else: |
| 140 | return '%s-dev' % (version_parts[0],) |
| 141 | |
| 142 | def deferred_version_string(self, prefix=""): |
| 143 | """Generate an object which will expand in a string context to |
| 144 | the results of version_string(). We do this so that don't |
| 145 | call into pkg_resources every time we start up a program when |
| 146 | passing version information into the CONF constructor, but |
| 147 | rather only do the calculation when and if a version is requested |
| 148 | """ |
| 149 | return _deferred_version_string(self, prefix) |