diff options
| author | Monty Taylor <mordred@inaugust.com> | 2012-07-10 06:39:52 -0500 |
|---|---|---|
| committer | Monty Taylor <mordred@inaugust.com> | 2012-07-11 11:21:24 -0500 |
| commit | 92650ab9e9c3ed74029d06cfd8fd26e10a1ef940 (patch) | |
| tree | 97592deb435f742904831d64436afcf93fddb6df /openstack/common | |
| parent | 44beb84b48051ff374bde6088688d6759a1807eb (diff) | |
| download | oslo-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.py | 203 |
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) |
