1- #!/usr/bin/python
2- 31import argparse
42import string
53import os
@@ -8,155 +6,12 @@ import tempfile
86import shutil
97import stat
108
11- # includes FoundationPlist since some apps store their Info.plist
12- # as binary PropertyLists
13- 14- # FoundationPlist:
15- 16- # Copyright 2009-2014 Greg Neagle.
17- #
18- # Licensed under the Apache License, Version 2.0 (the "License");
19- # you may not use this file except in compliance with the License.
20- # You may obtain a copy of the License at
21- #
22- # http://www.apache.org/licenses/LICENSE-2.0
23- #
24- # Unless required by applicable law or agreed to in writing, software
25- # distributed under the License is distributed on an "AS IS" BASIS,
26- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
27- # See the License for the specific language governing permissions and
28- # limitations under the License.
29- """FoundationPlist.py -- a tool to generate and parse MacOSX .plist files.
30-
31- This is intended as a drop-in replacement for Python's included plistlib,
32- with a few caveats:
33- - readPlist() and writePlist() operate only on a filepath,
34- not a file object.
35- - there is no support for the deprecated functions:
36- readPlistFromResource()
37- writePlistToResource()
38- - there is no support for the deprecated Plist class.
39-
40- The Property List (.plist) file format is a simple XML pickle supporting
41- basic object types, like dictionaries, lists, numbers and strings.
42- Usually the top level object is a dictionary.
43-
44- To write out a plist file, use the writePlist(rootObject, filepath)
45- function. 'rootObject' is the top level object, 'filepath' is a
46- filename.
47-
48- To parse a plist from a file, use the readPlist(filepath) function,
49- with a file name. It returns the top level object (again, usually a
50- dictionary).
51-
52- To work with plist data in strings, you can use readPlistFromString()
53- and writePlistToString().
54- """
55- 56- from Foundation import NSData , \
57- NSPropertyListSerialization , \
58- NSPropertyListMutableContainersAndLeaves , \
59- NSPropertyListXMLFormat_v1_0
60- 61- 62- class FoundationPlistException (Exception ):
63- '''Base error for this module'''
64- pass
65- 66- 67- class NSPropertyListSerializationException (FoundationPlistException ):
68- '''Read error for this module'''
69- pass
70- 71- 72- class NSPropertyListWriteException (FoundationPlistException ):
73- '''Write error for this module'''
74- pass
75- 76- 77- # private functions
78- def _dataToPlist (data ):
79- '''low-level function that parses a data object into a propertyList object'''
80- darwin_vers = int (os .uname ()[2 ].split ('.' )[0 ])
81- if darwin_vers > 10 :
82- (plistObject , plistFormat , error ) = (
83- NSPropertyListSerialization .propertyListWithData_options_format_error_ (
84- data , NSPropertyListMutableContainersAndLeaves , None , None ))
85- else :
86- # 10.5 doesn't support propertyListWithData:options:format:error:
87- # 10.6's PyObjC wrapper for propertyListWithData:options:format:error:
88- # is broken
89- # so use the older NSPropertyListSerialization function
90- (plistObject , plistFormat , error ) = (
91- NSPropertyListSerialization .propertyListFromData_mutabilityOption_format_errorDescription_ (
92- data , NSPropertyListMutableContainersAndLeaves , None , None ))
93- if plistObject is None :
94- if error is None :
95- error = "Plist data is invalid and could not be deserialized."
96- raise NSPropertyListSerializationException (error )
97- else :
98- return plistObject
99- 100- 101- def _plistToData (plistObject ):
102- '''low-level function that creates NSData from a plist object'''
103- darwin_vers = int (os .uname ()[2 ].split ('.' )[0 ])
104- if darwin_vers > 10 :
105- (data , error ) = (
106- NSPropertyListSerialization .dataWithPropertyList_format_options_error_ (
107- plistObject , NSPropertyListXMLFormat_v1_0 , 0 , None ))
108- else :
109- # use the older NSPropertyListSerialization function on 10.6 and 10.5
110- (data , error ) = (
111- NSPropertyListSerialization .dataFromPropertyList_format_errorDescription_ (
112- plistObject , NSPropertyListXMLFormat_v1_0 , None ))
113- if data is None :
114- if error is None :
115- error = "Property list invalid for format."
116- raise NSPropertyListSerializationException (error )
117- return data
118- 119- 120- # public functions
121- def readPlist (filepath ):
122- '''Read a .plist file from filepath. Return the unpacked root object
123- (which is usually a dictionary).'''
124- try :
125- data = NSData .dataWithContentsOfFile_ (filepath )
126- except NSPropertyListSerializationException , error :
127- # insert filepath info into error message
128- errmsg = (u'%s in %s' % (error , filepath ))
129- raise NSPropertyListSerializationException (errmsg )
130- return _dataToPlist (data )
131- 132- 133- def readPlistFromString (aString ):
134- '''Read a plist data from a string. Return the root object.'''
135- data = buffer (aString )
136- return _dataToPlist (data )
137- 138- 139- def writePlist (plistObject , filepath ):
140- '''Write 'plistObject' as a plist to filepath.'''
141- plistData = _plistToData (plistObject )
142- if plistData .writeToFile_atomically_ (filepath , True ):
143- return
144- else :
145- raise NSPropertyListWriteException (
146- u"Failed to write plist data to %s" % filepath )
147- 148- 149- def writePlistToString (plistObject ):
150- '''Create a plist-formatted string from plistObject.'''
151- return str (_plistToData (plistObject ))
152- 153- 1549#
15510# quickpkg
15611#
15712
15813
159- quickpkg_version = '0.9 '
14+ quickpkg_version = '1 '
16015supported_extensions = ['dmg', 'app', 'zip', 'xip']
16116
16217
@@ -165,7 +20,7 @@ supported_extensions = ['dmg', 'app', 'zip', 'xip']
16520
16621def logger(log, v=0):
16722 if args.verbosity >= v:
168- print log
23+ print( log)
16924
17025
17126def cmdexec(command, stdin=''):
@@ -211,7 +66,7 @@ def dmg_has_sla(dmgpath):
21166 imageinfo_cmd = ['/usr/bin/hdiutil', 'imageinfo', dmgpath, '-plist']
21267 result = cmdexec(imageinfo_cmd)
21368 if result["return_code"] != 0:
214- print "error getting imageinfo! %s, %s" % (result ["return_code" ], result ["stderr" ])
69+ print( "error getting imageinfo! %s, %s" % (result["return_code"], result["stderr"]) )
21570 return False
21671 result_plist = result["stdout"]
21772 imageinfo_dict = readPlistFromString(result_plist)
@@ -230,18 +85,18 @@ def attachdmg(dmgpath):
23085 (theplist, alltext) = getFirstPlist(info_result["stdout"])
23186 info_dict = readPlistFromString(theplist)
23287 volpaths = []
233- if "images" in info_dict .keys ():
88+ if "images" in list( info_dict.keys() ):
23489 for y in info_dict["images"]:
235- if "image-path" in y .keys ():
90+ if "image-path" in list( y.keys() ):
23691 if y["image-path"] == dmgpath and os.path.samefile(y["image-path"], dmgpath):
23792 for x in y.get("system-entities"):
238- if "mount-point" in x .keys ():
93+ if "mount-point" in list( x.keys() ):
23994 volpaths.append(x["mount-point"])
24095 dmg_was_mounted = True
24196 return volpaths
24297 else:
243- print "error getting hdiutil info"
244- print "(%d, %s)" % (info_result ["returncode" ], info_result ["stderr" ])
98+ print( "error getting hdiutil info")
99+ print( "(%d, %s)" % (info_result["returncode"], info_result["stderr"]) )
245100 cleanup_and_exit(1)
246101
247102 attachcmd = ["/usr/bin/hdiutil",
@@ -253,7 +108,7 @@ def attachdmg(dmgpath):
253108 "-nobrowse"]
254109 if dmg_has_sla(dmgpath):
255110 stdin = "Y\n"
256- print "NOTE: Disk image %s has a license agreement!" % dmgpath
111+ print( "NOTE: Disk image %s has a license agreement!" % dmgpath)
257112 else:
258113 stdin = ''
259114 result = cmdexec(attachcmd, stdin)
@@ -269,8 +124,8 @@ def attachdmg(dmgpath):
269124 # return the paths to mounted volume
270125 return volpaths
271126 else:
272- print "error mounting disk image"
273- print "(%d, %s)" % (result ["returncode" ], result ["stderr" ])
127+ print( "error mounting disk image")
128+ print( "(%d, %s)" % (result["returncode"], result["stderr"]) )
274129 cleanup_and_exit(1)
275130
276131
@@ -291,15 +146,15 @@ def finditemswithextension(dirpath, item_extension):
291146 if item_extension == 'app':
292147 foundapps.append(os.path.join(dirpath, x))
293148 else:
294- print "path %s does not exist" % dirpath
149+ print( "path %s does not exist" % dirpath)
295150 cleanup_and_exit(1)
296151 return foundapps
297152
298153
299154def appNameAndVersion(app_path):
300155 info_path = os.path.join(app_path, "Contents/Info.plist")
301156 if not os.path.exists(info_path):
302- print "Application at path %s does not have Info.plist" % app_path
157+ print( "Application at path %s does not have Info.plist" % app_path)
303158 # TODO: cleanup volumes here
304159 cleanup_and_exit(1)
305160 info_plist = readPlist(info_path)
@@ -391,7 +246,7 @@ if __name__ == "__main__":
391246
392247 # is extension supported
393248 if item_extension not in supported_extensions:
394- print ".%s is not a supported extension!" % item_extension
249+ print( ".%s is not a supported extension!" % item_extension)
395250 exit(1)
396251
397252 foundapps = []
@@ -400,7 +255,7 @@ if __name__ == "__main__":
400255 # if item is an app, just pass it on
401256 if item_extension == 'app':
402257 if not os.path.exists(item_path):
403- print "This does not seem to be an Application!"
258+ print( "This does not seem to be an Application!")
404259 exit(1)
405260 foundapps.append(item_path)
406261 copy_app = True
@@ -421,11 +276,11 @@ if __name__ == "__main__":
421276 moreapps = finditemswithextension(x, 'app')
422277 foundapps.extend(moreapps)
423278 if len(foundapps) == 0:
424- print "Could not find an application!"
279+ print( "Could not find an application!")
425280 cleanup_and_exit(1)
426281 elif len(foundapps) > 1:
427- print "Found too many Applications! Can't decide!"
428- print foundapps
282+ print( "Found too many Applications! Can't decide!")
283+ print( foundapps)
429284 cleanup_and_exit(1)
430285
431286 # if item is zip, unzip to tmp location and find useful contents
@@ -434,16 +289,16 @@ if __name__ == "__main__":
434289 unzip_cmd = ["/usr/bin/unzip", "-d", unarchive_path, item_path]
435290 result = cmdexec(unzip_cmd)
436291 if result["return_code"] != 0:
437- print "An error occured while unzipping:"
438- print "%d, %s" % (result ["return_code" ], result ["stderr" ])
292+ print( "An error occured while unzipping:")
293+ print( "%d, %s" % (result["return_code"], result["stderr"]) )
439294 cleanup_and_exit(1)
440295 foundapps = finditemswithextension(unarchive_path, 'app')
441296 if len(foundapps) == 0:
442- print "Could not find an application!"
297+ print( "Could not find an application!")
443298 cleanup_and_exit(1)
444299 elif len(foundapps) > 1:
445- print "Found too many Applications! Can't decide!"
446- print foundapps
300+ print( "Found too many Applications! Can't decide!")
301+ print( foundapps)
447302 cleanup_and_exit(1)
448303
449304 # if item is xip, extract to tmp location and find useful contents
@@ -456,16 +311,16 @@ if __name__ == "__main__":
456311 result = cmdexec(xip_cmd)
457312 os.chdir(cwd)
458313 if result["return_code"] != 0:
459- print "An error occured while expanding xip archive:"
460- print "%d, %s" % (result ["return_code" ], result ["stderr" ])
314+ print( "An error occured while expanding xip archive:")
315+ print( "%d, %s" % (result["return_code"], result["stderr"]) )
461316 cleanup_and_exit(1)
462317 foundapps = finditemswithextension(unarchive_path, 'app')
463318 if len(foundapps) == 0:
464- print "Could not find an application!"
319+ print( "Could not find an application!")
465320 cleanup_and_exit(1)
466321 elif len(foundapps) > 1:
467- print "Found too many Applications! Can't decide!"
468- print foundapps
322+ print( "Found too many Applications! Can't decide!")
323+ print( foundapps)
469324 cleanup_and_exit(1)
470325
471326 logger("Found application: %s" % foundapps[0], 1)
@@ -497,16 +352,16 @@ if __name__ == "__main__":
497352
498353 logger(result["stdout"], 1)
499354 if result["return_code"] != 0:
500- print "Error Code: %d " % result ["return_code" ]
501- print result ["stderr" ]
355+ print( "Error Code: %d " % result["return_code"])
356+ print( result["stderr"])
502357 cleanup_and_exit(1)
503358
504359 if not args.relocatable:
505360 # read and change component plist
506361 components = readPlist(component_plist)
507362 # component plist is an array of components
508363 for bundle in components:
509- if "BundleIsRelocatable" in bundle .keys ():
364+ if "BundleIsRelocatable" in list( bundle.keys() ):
510365 bundle["BundleIsRelocatable"] = False
511366 writePlist(components, component_plist)
512367
@@ -534,7 +389,7 @@ if __name__ == "__main__":
534389 pkg_path]
535390
536391 if args.scripts and not os.path.exists(args.scripts):
537- print "scripts folder %s does not exist!" % args .scripts
392+ print( "scripts folder %s does not exist!" % args.scripts)
538393 cleanup_and_exit(1)
539394
540395 if args.postinstall or args.preinstall:
@@ -547,11 +402,11 @@ if __name__ == "__main__":
547402 shutil.copytree(args.scripts, tmp_scripts_path)
548403 if args.postinstall:
549404 if not os.path.exists(args.postinstall):
550- print "postinstall file %s does not exist!" % args .postinstall
405+ print( "postinstall file %s does not exist!" % args.postinstall)
551406 cleanup_and_exit(1)
552407 postinstall_path = os.path.join(tmp_scripts_path, "postinstall")
553408 if os.path.exists(postinstall_path):
554- print "postinstall script already exists in %s" % args .scripts
409+ print( "postinstall script already exists in %s" % args.scripts)
555410 cleanup_and_exit(1)
556411 logger("copying %s to %s" % (args.postinstall, postinstall_path), 1)
557412 shutil.copy2(args.postinstall, postinstall_path)
@@ -560,11 +415,11 @@ if __name__ == "__main__":
560415 stat.S_IROTH | stat.S_IXOTH)
561416 if args.preinstall:
562417 if not os.path.exists(args.preinstall):
563- print "preinstall file %s does not exist!" % args .preinstall
418+ print( "preinstall file %s does not exist!" % args.preinstall)
564419 cleanup_and_exit(1)
565420 preinstall_path = os.path.join(tmp_scripts_path, "preinstall")
566421 if os.path.exists(preinstall_path):
567- print "preinstall script already exists in %s" % args .scripts
422+ print( "preinstall script already exists in %s" % args.scripts)
568423 cleanup_and_exit(1)
569424 logger("copying %s to %s" % (args.preinstall, preinstall_path), 1)
570425 shutil.copy2(args.preinstall, preinstall_path)
@@ -593,9 +448,9 @@ if __name__ == "__main__":
593448
594449 logger(result["stdout"], 1)
595450 if result["return_code"] != 0:
596- print "Error Code: %d " % result ["return_code" ]
597- print result ["stderr" ]
451+ print( "Error Code: %d " % result["return_code"])
452+ print( result["stderr"])
598453 else:
599- print pkg_path
454+ print( pkg_path)
600455
601456 cleanup_and_exit(0)
0 commit comments