Change version number handling to eliminate padding/truncating version numbers to five positions (ala 1.0.0.0.0).

git-svn-id: http://munki.googlecode.com/svn/trunk@1016 a4e17f2e-e282-11dd-95e1-755cbddbdd66
This commit is contained in:
Greg Neagle
2011-01-31 21:38:47 +00:00
parent 7390b94f46
commit 69705bb33e
5 changed files with 119 additions and 53 deletions
+14 -10
View File
@@ -37,7 +37,7 @@ import os
import re
import optparse
from optparse import OptionValueError
from distutils import version
#from distutils import version
import subprocess
from munkilib import munkicommon
@@ -157,10 +157,12 @@ def getCatalogInfoFromDmg(dmgpath, options):
cataloginfo = {}
cataloginfo['name'] = iteminfo.get('CFBundleName',
os.path.splitext(item)[0])
#cataloginfo['version'] = \
# munkicommon.padVersionString(
# iteminfo.get('CFBundleShortVersionString', "0")
# ,5)
cataloginfo['version'] = \
munkicommon.padVersionString(
iteminfo.get('CFBundleShortVersionString', "0")
,5)
iteminfo.get('CFBundleShortVersionString', "0")
cataloginfo['installs'] = [iteminfo]
if options.appdmg:
cataloginfo['installer_type'] = "appdmg"
@@ -530,15 +532,17 @@ def main():
thisminosversion = iteminfodict.pop('minosversion')
if not minosversion:
minosversion = thisminosversion
elif version.LooseVersion(thisminosversion) < \
version.LooseVersion(minosversion):
elif (munkicommon.MunkiLooseVersion(thisminosversion) <
munkicommon.MunkiLooseVersion(minosversion)):
minosversion = thisminosversion
if 'CFBundleShortVersionString' in iteminfodict:
#thisitemversion = \
# munkicommon.padVersionString(
# iteminfodict['CFBundleShortVersionString'],5)
thisitemversion = \
munkicommon.padVersionString(
iteminfodict['CFBundleShortVersionString'],5)
if version.LooseVersion(thisitemversion) > \
version.LooseVersion(maxfileversion):
iteminfodict['CFBundleShortVersionString']
if (munkicommon.MunkiLooseVersion(thisitemversion) >
munkicommon.MunkiLooseVersion(maxfileversion)):
maxfileversion = thisitemversion
installs.append(iteminfodict)
else:
+4 -3
View File
@@ -28,7 +28,7 @@ import os
import optparse
import subprocess
import time
from distutils import version
#from distutils import version
from munkilib import munkicommon
from munkilib import FoundationPlist
@@ -271,7 +271,7 @@ def makeCatalogDB():
munkicommon.display_warning('Bad pkginfo: %s' % item)
# normalize the version number
vers = munkicommon.padVersionString(vers, 5)
#vers = munkicommon.padVersionString(vers, 5)
# add to hash table
if 'installer_item_hash' in item:
@@ -324,7 +324,8 @@ def findMatchingPkginfo(pkginfo):
def compare_version_keys(a, b):
"""Internal comparison function for use in sorting"""
return cmp(version.LooseVersion(b), version.LooseVersion(a))
return cmp(munkicommon.MunkiLooseVersion(b),
munkicommon.MunkiLooseVersion(a))
try:
db = makeCatalogDB()
+3 -2
View File
@@ -132,8 +132,9 @@ def getPayloadInfo(dirpath):
if propname == 'ProductName':
payloadinfo['display_name'] = propvalue
if propname == 'ProductVersion':
payloadinfo['version'] = \
munkicommon.padVersionString(propvalue,5)
#payloadinfo['version'] = \
#munkicommon.padVersionString(propvalue,5)
payloadinfo['version'] = propvalue
installmetadata = \
payload_info[0].getElementsByTagName(
+47 -14
View File
@@ -36,6 +36,7 @@ import time
import urllib2
import warnings
from distutils import version
from types import StringType
from xml.dom import minidom
from Foundation import NSDate, NSMetadataQuery, NSPredicate, NSRunLoop
@@ -753,6 +754,30 @@ def getInstallerPkgInfo(filename):
installerinfo['RestartAction'] = restartAction
return installerinfo
class MunkiLooseVersion (version.LooseVersion):
'''Subclass version.LooseVersion to compare things like
"10.6" and "10.6.0" as equal'''
def pad(self, version_list, max_length):
"""Pad a version list by adding extra 0
components to the end if needed"""
# copy the version_list so we don't modify it
cmp_list = list(version_list)
while len(cmp_list) < max_length :
cmp_list.append(0)
return (cmp_list)
def __cmp__ (self, other):
if isinstance(other, StringType):
other = MunkiLooseVersion(other)
max_length = max(len(self.version), len(other.version))
self_cmp_version = self.pad(self.version, max_length)
other_cmp_version = self.pad(other.version, max_length)
return cmp(self_cmp_version, other_cmp_version)
def padVersionString(versString, tupleCount):
@@ -811,7 +836,8 @@ def getExtendedVersion(bundlepath):
plist = FoundationPlist.readPlist(infoPlist)
versionstring = getVersionString(plist)
if versionstring:
return padVersionString(versionstring, 5)
#return padVersionString(versionstring, 5)
return versionstring
# no version number in Info.plist. Maybe old-style package?
infopath = os.path.join(bundlepath, 'Contents', 'Resources',
@@ -829,8 +855,9 @@ def getExtendedVersion(bundlepath):
if len(parts) == 2:
label = parts[0]
if label == 'Version':
return padVersionString(parts[1], 5)
#return padVersionString(parts[1], 5)
return parts[1]
# didn't find a version number, so return 0...
return '0.0.0.0.0'
@@ -848,8 +875,10 @@ def parsePkgRefs(filename):
pkginfo = {}
pkginfo['packageid'] = \
ref.attributes['id'].value.encode('UTF-8')
pkginfo['version'] = padVersionString(
ref.attributes['version'].value.encode('UTF-8'), 5)
#pkginfo['version'] = padVersionString(
# ref.attributes['version'].value.encode('UTF-8'), 5)
pkginfo['version'] = \
ref.attributes['version'].value.encode('UTF-8')
if 'installKBytes' in keys:
pkginfo['installed_size'] = int(
ref.attributes['installKBytes'].value.encode('UTF-8'))
@@ -865,9 +894,11 @@ def parsePkgRefs(filename):
pkginfo = {}
pkginfo['packageid'] = \
ref.attributes['identifier'].value.encode('UTF-8')
#pkginfo['version'] = \
# padVersionString(
# ref.attributes['version'].value.encode('UTF-8'),5)
pkginfo['version'] = \
padVersionString(
ref.attributes['version'].value.encode('UTF-8'),5)
ref.attributes['version'].value.encode('UTF-8')
payloads = ref.getElementsByTagName('payload')
if payloads:
keys = payloads[0].attributes.keys()
@@ -973,8 +1004,9 @@ def getOnePackageInfo(pkgpath):
if len(parts) == 2:
label = parts[0]
if label == 'Version':
pkginfo['version'] = \
padVersionString(parts[1], 5)
#pkginfo['version'] = \
# padVersionString(parts[1], 5)
pkginfo['version'] = parts[1]
if label == 'Title':
pkginfo['name'] = parts[1]
break
@@ -1109,7 +1141,8 @@ def getInstalledPackageVersion(pkgid):
if pkgid == foundbundleid:
display_debug2('\tThis machine has %s, version %s' %
(pkgid, foundvers))
return padVersionString(foundvers, 5)
#return padVersionString(foundvers, 5)
return foundvers
# If we got to this point, we haven't found the pkgid yet.
# Check /Library/Receipts
@@ -1125,8 +1158,8 @@ def getInstalledPackageVersion(pkgid):
foundbundleid = infoitem['packageid']
foundvers = infoitem['version']
if pkgid == foundbundleid:
if version.LooseVersion(foundvers) > \
version.LooseVersion(highestversion):
if (MunkiLooseVersion(foundvers) >
MunkiLooseVersion(highestversion)):
highestversion = foundvers
if highestversion != '0':
@@ -1206,8 +1239,8 @@ def getPackageMetaData(pkgitem):
highestpkgversion = '0.0'
installedsize = 0
for infoitem in receiptinfo:
if version.LooseVersion(infoitem['version']) > \
version.LooseVersion(highestpkgversion):
if (MunkiLooseVersion(infoitem['version']) >
MunkiLooseVersion(highestpkgversion)):
highestpkgversion = infoitem['version']
if 'installed_size' in infoitem:
# note this is in KBytes
+51 -24
View File
@@ -31,7 +31,7 @@ import time
import urllib2
import urlparse
import xattr
from distutils import version
#from distutils import version
from OpenSSL.crypto import load_certificate, FILETYPE_PEM
#our libs
@@ -57,7 +57,8 @@ def makeCatalogDB(catalogitems):
munkicommon.display_warning('Bad pkginfo: %s' % item)
# normalize the version number
vers = munkicommon.padVersionString(vers, 5)
#vers = munkicommon.padVersionString(vers, 5)
vers = trimVersionString(vers)
# build indexes for items by name and version
if not name in name_table:
@@ -181,8 +182,8 @@ def getInstalledPackages():
# installed, since presumably
# the newer package replaced the older one
storedversion = INSTALLEDPKGS[pkgid]
if version.LooseVersion(thisversion) > \
version.LooseVersion(storedversion):
if (munkicommon.MunkiLooseVersion(thisversion) >
munkicommon.MunkiLooseVersion(storedversion)):
INSTALLEDPKGS[pkgid] = thisversion
@@ -276,11 +277,13 @@ def compareVersions(thisvers, thatvers):
1 if thisvers is the same as thatvers
2 if thisvers is newer than thatvers
"""
thisvers = munkicommon.padVersionString(thisvers, 5)
thatvers = munkicommon.padVersionString(thatvers, 5)
if version.LooseVersion(thisvers) < version.LooseVersion(thatvers):
#thisvers = munkicommon.padVersionString(thisvers, 5)
#thatvers = munkicommon.padVersionString(thatvers, 5)
if (munkicommon.MunkiLooseVersion(thisvers) <
munkicommon.MunkiLooseVersion(thatvers)):
return -1
elif version.LooseVersion(thisvers) == version.LooseVersion(thatvers):
elif (munkicommon.MunkiLooseVersion(thisvers) ==
munkicommon.MunkiLooseVersion(thatvers)):
return 1
else:
return 2
@@ -755,8 +758,8 @@ def getAllItemsWithName(name, cataloglist):
"""
def compare_item_versions(a, b):
"""Internal comparison function for use with sorting"""
return cmp(version.LooseVersion(b['version']),
version.LooseVersion(a['version']))
return cmp(munkicommon.MunkiLooseVersion(b['version']),
munkicommon.MunkiLooseVersion(a['version']))
itemlist = []
# we'll throw away any included version info
@@ -785,6 +788,24 @@ def getAllItemsWithName(name, cataloglist):
# sort so latest version is first
itemlist.sort(compare_item_versions)
return itemlist
def trimVersionString(version_string):
"""Trims all lone trailing zeros in the version string after major/minor.
Examples:
10.0.0.0 -> 10.0
10.0.0.1 -> 10.0.0.1
10.0.0-abc1 -> 10.0.0-abc1
10.0.0-abc1.0 -> 10.0.0-abc1
"""
if version_string == None or version_string == '':
return ''
version_parts = version_string.split('.')
# strip off all trailing 0's in the version, while over 2 parts.
while len(version_parts) > 2 and version_parts[-1] == '0':
del(version_parts[-1])
return '.'.join(version_parts)
def getItemDetail(name, cataloglist, vers=''):
@@ -797,7 +818,8 @@ def getItemDetail(name, cataloglist, vers=''):
"""
def compare_version_keys(a, b):
"""Internal comparison function for use in sorting"""
return cmp(version.LooseVersion(b), version.LooseVersion(a))
return cmp(munkicommon.MunkiLooseVersion(b),
munkicommon.MunkiLooseVersion(a))
(name, includedversion) = nameAndVersion(name)
if vers == '':
@@ -805,7 +827,9 @@ def getItemDetail(name, cataloglist, vers=''):
vers = includedversion
if vers:
# make sure version is in 1.0.0.0.0 format
vers = munkicommon.padVersionString(vers, 5)
#vers = munkicommon.padVersionString(vers, 5)
# normalize the version string
vers = trimVersionString(vers)
else:
vers = 'latest'
@@ -840,17 +864,18 @@ def getItemDetail(name, cataloglist, vers=''):
# we have an item whose name and version matches the request.
# now check to see if it meets os and cpu requirements
if 'minimum_os_version' in item:
min_os_vers = \
munkicommon.padVersionString(
item['minimum_os_version'],3)
#min_os_vers = \
# munkicommon.padVersionString(
# item['minimum_os_version'],3)
min_os_vers = item['minimum_os_version']
munkicommon.display_debug1(
'Considering item %s, ' % item['name'] +
'version %s ' % item['version'] +
'with minimum os version required %s' % min_os_vers)
munkicommon.display_debug1('Our OS version is %s' %
MACHINE['os_vers'])
if version.LooseVersion(MACHINE['os_vers']) < \
version.LooseVersion(min_os_vers):
if (munkicommon.MunkiLooseVersion(MACHINE['os_vers']) <
munkicommon.MunkiLooseVersion(min_os_vers)):
# skip this one, go to the next
reason = (('Rejected item %s, version %s '
'with minimum os version required %s. '
@@ -862,17 +887,18 @@ def getItemDetail(name, cataloglist, vers=''):
continue
if 'maximum_os_version' in item:
max_os_vers = \
munkicommon.padVersionString(
item['maximum_os_version'],3)
#max_os_vers = \
# munkicommon.padVersionString(
# item['maximum_os_version'],3)
max_os_vers = item['maximum_os_version']
munkicommon.display_debug1(
'Considering item %s, ' % item['name'] +
'version %s ' % item['version'] +
'with maximum os version supported %s' % max_os_vers)
munkicommon.display_debug1('Our OS version is %s' %
MACHINE['os_vers'])
if version.LooseVersion(MACHINE['os_vers']) > \
version.LooseVersion(max_os_vers):
if (munkicommon.MunkiLooseVersion(MACHINE['os_vers']) >
munkicommon.MunkiLooseVersion(max_os_vers)):
# skip this one, go to the next
reason = (('Rejected item %s, version %s '
'with maximum os version required %s. '
@@ -2459,8 +2485,9 @@ def getMachineFacts():
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, unused_err) = proc.communicate()
# format version string like '10.5.8', so that '10.6' becomes '10.6.0'
MACHINE['os_vers'] = munkicommon.padVersionString(
str(output).rstrip('\n'),3)
#MACHINE['os_vers'] = munkicommon.padVersionString(
# str(output).rstrip('\n'),3)
MACHINE['os_vers'] = str(output).rstrip('\n')
def check(client_id='', localmanifestpath=None):