2525# https://github.com/munki/munki
2626# Notice a pattern?
2727
28- from distutils .version import LooseVersion
2928from Foundation import NSLog
3029from SystemConfiguration import SCDynamicStoreCopyConsoleUser
3130import hashlib
4847g_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+
51165def 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+
166281def 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+
185301def 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+
446563def main ():
447564 # Options
448565 usage = "%prog [options]"
0 commit comments