summaryrefslogtreecommitdiffstats
path: root/openstack/common
diff options
context:
space:
mode:
authorMonty Taylor <mordred@inaugust.com>2012-07-10 06:39:52 -0500
committerMonty Taylor <mordred@inaugust.com>2012-07-11 11:21:24 -0500
commit92650ab9e9c3ed74029d06cfd8fd26e10a1ef940 (patch)
tree97592deb435f742904831d64436afcf93fddb6df /openstack/common
parent44beb84b48051ff374bde6088688d6759a1807eb (diff)
downloadoslo-92650ab9e9c3ed74029d06cfd8fd26e10a1ef940.tar.gz
oslo-92650ab9e9c3ed74029d06cfd8fd26e10a1ef940.tar.xz
oslo-92650ab9e9c3ed74029d06cfd8fd26e10a1ef940.zip
Rework the version consumer functionality.
Moved the version routines into a class for better structure. Added caching/memoization logic so that pkg_resources/git doesn't get called more than is necessary. Added periodic-based caching that will only cause the meta info refs to be checked at most once a day, to reduce network load for developers. (The information in the meta refs should really only change once a month, and this will only affect local developer workstation version reporting, so we should be fine here. Added a deferred version string class and function to allow for consuming of the version string but doing the calculation only when it is requested, based on test runs in glance. Change-Id: I6a436c8817f6904959727a76d876b807ec545ee9
Diffstat (limited to 'openstack/common')
-rw-r--r--openstack/common/version.py203
1 files changed, 123 insertions, 80 deletions
diff --git a/openstack/common/version.py b/openstack/common/version.py
index cb24096..ca350ed 100644
--- a/openstack/common/version.py
+++ b/openstack/common/version.py
@@ -18,89 +18,132 @@
Utilities for consuming the auto-generated versioninfo files.
"""
+import datetime
import pkg_resources
import os
import setup
-def _generate_version(python_package, pre_version):
- """Defer to the openstack.common.setup routines for making a
- version from git."""
- if pre_version is None:
- return setup.get_post_version(python_package)
- else:
- return setup.get_pre_version(python_package, pre_version)
-
-
-def version_string_with_vcs(package, python_package=None, pre_version=None):
- """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 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 towards
- """
- if python_package is None:
- python_package = package
- if os.path.isdir(package) and os.path.isdir(".git"):
- return _generate_version(python_package, pre_version)
- requirement = pkg_resources.Requirement.parse(python_package)
- versioninfo = "%s/versioninfo" % package
- try:
- return pkg_resources.resource_string(requirement,
- versioninfo).strip()
- except (IOError, pkg_resources.DistributionNotFound):
- return _generate_version(python_package, pre_version)
-
-
-def canonical_version_string(package, python_package=None, pre_version=None):
- """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 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 towards
- """
- vcs_string = version_string_with_vcs(package, python_package, pre_version)
- return vcs_string.split('~')[0]
-
-
-def version_string(package, python_package=None, pre_version=None):
- """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 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 towards
- """
- version = version_string_with_vcs(package, python_package, pre_version)
- version_parts = version.split('~')
- if len(version_parts) == 1:
- return version_parts[0]
- else:
- return '%s-dev' % (version_parts[0],)
+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)