Added support for installcheck and managedinstaller to handle Apple Software Updates.

Moved some functions from makepkginfo to munkilib so installcheck could use them.
Added checking to installcheck, managedinstaller, and removepackages.py so they warn and exit if run by a non-root user.
Added checks to installcheck and mamangedinstaller so that they exit if the other is running.


git-svn-id: http://munki.googlecode.com/svn/trunk@87 a4e17f2e-e282-11dd-95e1-755cbddbdd66
This commit is contained in:
Greg Neagle
2009-05-22 19:05:57 +00:00
parent b37a3d9884
commit 82ad48c60e
6 changed files with 311 additions and 189 deletions
+5 -119
View File
@@ -44,120 +44,6 @@ import hashlib
import munkilib
def mountdmg(dmgpath):
"""
Attempts to mount the dmg at dmgpath
and returns a list of mountpoints
"""
mountpoints = []
dmgname = os.path.basename(dmgpath)
p = subprocess.Popen(['/usr/bin/hdiutil', 'attach', dmgpath, '-mountRandom', '/tmp', '-nobrowse', '-plist'],
bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(plist, err) = p.communicate()
if err:
print >>sys.stderr, "Error %s mounting %s." % (err, dmgpath)
if plist:
pl = plistlib.readPlistFromString(plist)
for entity in pl['system-entities']:
if 'mount-point' in entity:
mountpoints.append(entity['mount-point'])
return mountpoints
def unmountdmg(mountpoint):
"""
Unmounts the dmg at mountpoint
"""
p = subprocess.Popen(['/usr/bin/hdiutil', 'detach', mountpoint],
bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, err) = p.communicate()
if err:
print >>sys.stderr, err
p = subprocess.Popen(['/usr/bin/hdiutil', 'detach', mountpoint, '-force'],
bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, err) = p.communicate()
def nameAndVersion(s):
"""
Splits a string into the name and version numbers:
'TextWrangler2.3b1' becomes ('TextWrangler', '2.3b1')
'AdobePhotoshopCS3-11.2.1' becomes ('AdobePhotoshopCS3', '11.2.1')
'MicrosoftOffice2008v12.2.1' becomes ('MicrosoftOffice2008', '12.2.1')
"""
index = 0
for char in s:
if char in "0123456789":
possibleVersion = s[index:]
if not (" " in possibleVersion or "_" in possibleVersion or "-" in possibleVersion or "v" in possibleVersion):
return (s[0:index].rstrip(" .-_v"), possibleVersion)
index += 1
# no version number found, just return original string and empty string
return (s, '')
def getCatalogInfo(pkgitem):
"""
The core function here. Queries an installer item (.pkg, .mpkg)
and gets metadata. There are a lot of valid Apple package formats
and this function may not deal with them all equally well.
Standard bundle packages are probably the best understood and documented,
so this code deals with those pretty well.
metadata items include:
installer_item_size: size of the installer item (.dmg, .pkg, etc)
installed_size: size of items that will be installed
RestartAction: will a restart be needed after installation?
name
version
description
receipts: an array of packageids that may be installed (some may be optional)
"""
installedsize = 0
installerinfo = munkilib.getInstallerPkgInfo(pkgitem)
info = munkilib.getPkgInfo(pkgitem)
highestpkgversion = "0.0"
for infoitem in info:
if version.LooseVersion(infoitem['version']) > version.LooseVersion(highestpkgversion):
highestpkgversion = infoitem['version']
if "installed_size" in infoitem:
# note this is in KBytes
installedsize += infoitem['installed_size']
name = os.path.split(pkgitem)[1]
shortname = os.path.splitext(name)[0]
metaversion = nameAndVersion(shortname)[1]
if not len(metaversion):
metaversion = highestpkgversion
elif highestpkgversion.startswith(metaversion):
#for example, highestpkgversion is 2.0.3124.0, version in filename is 2.0
metaversion = highestpkgversion
if 'installed_size' in installerinfo:
if installerinfo['installed_size'] > 0:
installedsize = installerinfo['installed_size']
cataloginfo = {}
cataloginfo['name'] = nameAndVersion(shortname)[0]
cataloginfo['version'] = metaversion
for key in ('display_name', 'RestartAction', 'description'):
if key in installerinfo:
cataloginfo[key] = installerinfo[key]
if installedsize > 0:
cataloginfo['installed_size'] = installedsize
cataloginfo['receipts'] = []
for infoitem in info:
pkginfo = {}
pkginfo['packageid'] = infoitem['id']
pkginfo['version'] = infoitem['version']
cataloginfo['receipts'].append(pkginfo)
return cataloginfo
def getCatalogInfoFromDmg(dmgpath):
"""
* Mounts a disk image
@@ -167,21 +53,21 @@ def getCatalogInfoFromDmg(dmgpath):
To-do: handle multiple installer items on a disk image
"""
cataloginfo = None
mountpoints = mountdmg(dmgpath)
mountpoints = munkilib.mountdmg(dmgpath)
for mountpoint in mountpoints:
for fsitem in os.listdir(mountpoint):
itempath = os.path.join(mountpoint, fsitem)
if itempath.endswith('.pkg') or itempath.endswith('.mpkg'):
cataloginfo = getCatalogInfo(itempath)
cataloginfo = munkilib.getPackageMetaData(itempath)
# get out of fsitem loop
break
if cataloginfo:
# get out of moutpoint loop
# get out of mountpoint loop
break
#unmount all the mountpoints from the dmg
for mountpoint in mountpoints:
unmountdmg(mountpoint)
munkilib.unmountdmg(mountpoint)
return cataloginfo
@@ -301,7 +187,7 @@ def main():
if item.endswith('.dmg'):
catinfo = getCatalogInfoFromDmg(item)
elif item.endswith('.pkg') or item.endswith('.mpkg'):
catinfo = getCatalogInfo(item)
catinfo = munkilib.getPackageMetaData(item)
else:
print >>sys.stderr, "%s is not an installer package!" % item
exit(-1)