Skip to content

Commit 2ee3001

Browse files
committed
LooseVersion from munki class
1 parent 8ef8ef0 commit 2ee3001

File tree

1 file changed

+118
-1
lines changed

1 file changed

+118
-1
lines changed

payload/Library/installapplications/installapplications.py

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
# https://github.com/munki/munki
2626
# Notice a pattern?
2727

28-
from distutils.version import LooseVersion
2928
from Foundation import NSLog
3029
from SystemConfiguration import SCDynamicStoreCopyConsoleUser
3130
import hashlib
@@ -48,6 +47,121 @@
4847
g_dry_run = False
4948

5049

50+
def _cmp(x, y):
51+
"""
52+
Replacement for built-in function cmp that was removed in Python 3
53+
54+
Compare the two objects x and y and return an integer according to
55+
the outcome. The return value is negative if x < y, zero if x == y
56+
and strictly positive if x > y.
57+
"""
58+
return (x > y) - (x < y)
59+
60+
61+
class LooseVersion():
62+
'''Class based on distutils.version.LooseVersion to compare things like
63+
"10.6" and "10.6.0" as equal'''
64+
65+
component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE)
66+
67+
def parse(self, vstring):
68+
"""parse function from distutils.version.LooseVersion"""
69+
# I've given up on thinking I can reconstruct the version string
70+
# from the parsed tuple -- so I just store the string here for
71+
# use by __str__
72+
self.vstring = vstring
73+
components = [x for x in self.component_re.split(vstring) if x and x != '.']
74+
for i, obj in enumerate(components):
75+
try:
76+
components[i] = int(obj)
77+
except ValueError:
78+
pass
79+
80+
self.version = components
81+
82+
def __str__(self):
83+
"""__str__ function from distutils.version.LooseVersion"""
84+
return self.vstring
85+
86+
def __repr__(self):
87+
"""__repr__ function adapted from distutils.version.LooseVersion"""
88+
return "MunkiLooseVersion ('%s')" % str(self)
89+
90+
def __init__(self, vstring=None):
91+
"""init method"""
92+
if vstring is None:
93+
# treat None like an empty string
94+
self.parse('')
95+
if vstring is not None:
96+
try:
97+
if isinstance(vstring, unicode):
98+
# unicode string! Why? Oh well...
99+
# convert to string so version.LooseVersion doesn't choke
100+
vstring = vstring.encode('UTF-8')
101+
except NameError:
102+
# python 3
103+
pass
104+
self.parse(str(vstring))
105+
106+
def _pad(self, version_list, max_length):
107+
"""Pad a version list by adding extra 0 components to the end
108+
if needed"""
109+
# copy the version_list so we don't modify it
110+
cmp_list = list(version_list)
111+
while len(cmp_list) < max_length:
112+
cmp_list.append(0)
113+
return cmp_list
114+
115+
def _compare(self, other):
116+
"""Compare MunkiLooseVersions"""
117+
if not isinstance(other, LooseVersion):
118+
other = LooseVersion(other)
119+
120+
max_length = max(len(self.version), len(other.version))
121+
self_cmp_version = self._pad(self.version, max_length)
122+
other_cmp_version = self._pad(other.version, max_length)
123+
cmp_result = 0
124+
for index, value in enumerate(self_cmp_version):
125+
try:
126+
cmp_result = _cmp(value, other_cmp_version[index])
127+
except TypeError:
128+
# integer is less than character/string
129+
if isinstance(value, int):
130+
return -1
131+
return 1
132+
if cmp_result:
133+
return cmp_result
134+
return cmp_result
135+
136+
def __hash__(self):
137+
"""Hash method"""
138+
return hash(self.version)
139+
140+
def __eq__(self, other):
141+
"""Equals comparison"""
142+
return self._compare(other) == 0
143+
144+
def __ne__(self, other):
145+
"""Not-equals comparison"""
146+
return self._compare(other) != 0
147+
148+
def __lt__(self, other):
149+
"""Less than comparison"""
150+
return self._compare(other) < 0
151+
152+
def __le__(self, other):
153+
"""Less than or equals comparison"""
154+
return self._compare(other) <= 0
155+
156+
def __gt__(self, other):
157+
"""Greater than comparison"""
158+
return self._compare(other) > 0
159+
160+
def __ge__(self, other):
161+
"""Greater than or equals comparison"""
162+
return self._compare(other) >= 0
163+
164+
51165
def iaslog(text):
52166
try:
53167
NSLog("[InstallApplications] %s" % text)
@@ -163,6 +277,7 @@ def launchctl(*arg):
163277
output, err = run.communicate()
164278
return output
165279

280+
166281
def process_request_options(options):
167282
"""
168283
Checks ia folder for a file that starts with middleware.
@@ -182,6 +297,7 @@ def process_request_options(options):
182297
options = middleware.process_request_options(options)
183298
return options
184299

300+
185301
def downloadfile(options):
186302
# Process options if middleware exists
187303
options = process_request_options(options)
@@ -443,6 +559,7 @@ def write_item_total_runtime(stage, item_name, item_start_time):
443559
with open(ias_item_runtimes_plist, 'wb') as ias_runtimes_file:
444560
plistlib.dump(ias_item_runtimes_dict, ias_runtimes_file)
445561

562+
446563
def main():
447564
# Options
448565
usage = "%prog [options]"

0 commit comments

Comments
 (0)