Changes to support installation of Adobe Acrobat Pro 9 updates.

git-svn-id: http://munki.googlecode.com/svn/trunk@415 a4e17f2e-e282-11dd-95e1-755cbddbdd66
This commit is contained in:
Greg Neagle
2009-12-24 20:27:33 +00:00
parent 1fd7e22375
commit 6125f77293
4 changed files with 269 additions and 43 deletions

View File

@@ -98,47 +98,11 @@ def getCatalogInfoFromDmg(dmgpath, pkgname='', appname=''):
cataloginfo = munkicommon.getPackageMetaData(itempath)
# get out of fsitem loop
break
if not cataloginfo:
# ADOBE STUFF
# no Apple installer items found.
# Look for AdobeUberInstaller items
pkgroot = os.path.join(mountpoints[0], pkgname)
adobeinstallxml = os.path.join(pkgroot, "AdobeUberInstaller.xml")
if os.path.exists(adobeinstallxml):
# this is a CS4 Enterprise Deployment package
cataloginfo = adobeutils.getAdobePackageInfo(pkgroot)
if cataloginfo:
# add some more data
cataloginfo['name'] = \
cataloginfo['display_name'].replace(" ",'')
cataloginfo['uninstallable'] = True
cataloginfo['uninstall_method'] = "AdobeUberUninstaller"
cataloginfo['installer_type'] = "AdobeUberInstaller"
if pkgname:
cataloginfo['package_path'] = pkgname
if not cataloginfo:
# ADOBE STUFF
# maybe this is an Adobe update DMG or CS3 installer
# look for Adobe Setup.app
setuppath = adobeutils.findSetupApp(mountpoints[0])
if setuppath:
cataloginfo = adobeutils.getAdobeSetupInfo(mountpoints[0])
if cataloginfo:
# add some more data
cataloginfo['name'] = \
cataloginfo['display_name'].replace(" ",'')
cataloginfo['installer_type'] = "AdobeSetup"
if cataloginfo.get('AdobeSetupType') == "ProductInstall":
cataloginfo['uninstallable'] = True
cataloginfo['uninstall_method'] = "AdobeSetup"
else:
cataloginfo['description'] = "Adobe updater"
cataloginfo['uninstallable'] = False
cataloginfo['update_for'] = ["PleaseEditMe-1.0.0.0.0"]
if not cataloginfo:
cataloginfo = adobeutils.getAdobeCatalogInfo(mountpoints[0],
pkgname)
if not cataloginfo:
# maybe this is an appdmg
# look for an app at the top level of the dmg

View File

@@ -33,7 +33,7 @@ import munkistatus
# dmg helper
# we need this instead of the one in munkicommon because the Adobe stuff
# needs the dmgs mounted under /Volumes. We can merge this later.
# needs the dmgs mounted under /Volumes. We can merge this later (or not).
def mountAdobeDmg(dmgpath):
"""
Attempts to mount the dmg at dmgpath
@@ -417,7 +417,263 @@ def runAdobeUberTool(dmgpath, pkgname='', uninstalling=False):
else:
munkicommon.display_error("No mountable filesystems on %s" % dmgpath)
return -1
# appdict is a global so we don't call system_profiler more than once per session
appdict = {}
def getAppData():
"""
Queries system_profiler and returns a dict
of app info items
"""
global appdict
if appdict == {}:
munkicommon.display_debug1(
"Getting info on currently installed applications...")
cmd = ['/usr/sbin/system_profiler', '-XML', 'SPApplicationsDataType']
p = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(plist, err) = p.communicate()
if p.returncode == 0:
pl = FoundationPlist.readPlistFromString(plist)
# top level is an array instead of a dict, so get dict
spdict = pl[0]
if '_items' in spdict:
appdict = spdict['_items']
return appdict
lastpatchlogline = ''
def getAcrobatPatchLogInfo(logpath):
global lastpatchlogline
if os.path.exists(logpath):
p = subprocess.Popen(['/usr/bin/tail', '-1', logpath],
bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, err) = p.communicate()
logline = output.rstrip('\n')
# is it different than the last time we checked?
if logline != lastpatchlogline:
lastpatchlogline = logline
return logline
return ''
def findAcrobatPatchApp(dirpath):
'''Attempts to find an AcrobatPro patching application
in dirpath'''
for (path, dirs, files) in os.walk(dirpath):
if path.endswith(".app"):
# look for Adobe's patching script
patch_script_path = os.path.join(path, "Contents", "Resources",
"ApplyOperation.py")
if os.path.exists(patch_script_path):
return path
return ''
def updateAcrobatPro(dmgpath):
"""Uses the scripts and Resources inside the Acrobat Patch application
bundle to silently update Acrobat Pro and related apps
Why oh why does this use a different mechanism than the other Adobe
apps?"""
if munkicommon.munkistatusoutput:
munkistatus.percent(-1)
#first mount the dmg
munkicommon.display_status("Mounting disk image %s" %
os.path.basename(dmgpath))
mountpoints = mountAdobeDmg(dmgpath)
if mountpoints:
installroot = mountpoints[0]
pathToAcrobatPatchApp = findAcrobatPatchApp(installroot)
else:
munkicommon.display_error("No mountable filesystems on %s" % dmgpath)
return -1
if not pathToAcrobatPatchApp:
munkicommon.display_error("No Acrobat Patch app at %s" %
pathToAcrobatPatchApp)
munkicommon.unmountdmg(installroot)
return -1
# some values needed by the patching script
resourcesDir = os.path.join(pathToAcrobatPatchApp,
"Contents", "Resources")
ApplyOperation = os.path.join(resourcesDir, "ApplyOperation.py")
callingScriptPath = os.path.join(resourcesDir, "InstallUpdates.sh")
appList = []
appListFile = os.path.join(resourcesDir, "app_list.txt")
if os.path.exists(appListFile):
f = open(appListFile, mode='r', buffering=1)
if f:
for line in f.readlines():
appList.append(line)
f.close()
if not appList:
munkicommon.display_error("Did not find a list of apps to update.")
munkicommon.unmountdmg(installroot)
return -1
payloadNum = -1
for line in appList:
payloadNum = payloadNum + 1
if munkicommon.munkistatusoutput:
munkistatus.percent(getPercent(payloadNum+1, len(appList)+1))
(appname, status) = line.split("\t")
munkicommon.display_status("Searching for %s" % appname)
candidates = [item for item in getAppData()
if item.get("path","").endswith("/" + appname) and
not item.get("path","").startswith("/Volumes")]
# hope there's only one!
if len(candidates) == 0:
if status == "optional":
continue
else:
munkicommon.display_error("Cannot patch %s because it "
"was not found on the startup "
"disk." % appname)
munkicommon.unmountdmg(installroot)
return -1
if len(candidates) > 1:
munkicommon.display_error("Cannot patch %s because we found "
"more than one copy on the "
"startup disk." % appname)
munkicommon.unmountdmg(installroot)
return -1
munkicommon.display_status("Updating %s" % appname)
apppath = os.path.dirname(candidates[0]["path"])
cmd = [ApplyOperation, apppath, appname, resourcesDir,
callingScriptPath, str(payloadNum)]
# figure out the log file path
patchappname = os.path.basename(pathToAcrobatPatchApp)
logfile_name = patchappname.split('.')[0] + str(payloadNum) + '.log'
homePath = os.path.expanduser("~")
logfile_dir = os.path.join(homePath, "Library", "Logs",
"Adobe", "Acrobat")
logfile_path = os.path.join(logfile_dir, logfile_name)
p = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
while (p.poll() == None):
time.sleep(1)
#loginfo = getAcrobatPatchLogInfo(logfile_path)
#if loginfo:
# print loginfo
# run of patch tool completed
retcode = p.poll()
if retcode != 0:
munkicommon.display_error("Error patching %s: %s" %
(appname, retcode))
break
else:
munkicommon.display_status("Patching %s complete." % appname)
munkicommon.display_status("Done.")
if munkicommon.munkistatusoutput:
munkistatus.percent(100)
munkicommon.unmountdmg(installroot)
return retcode
def getBundleInfo(path):
"""
Returns Info.plist data if available
for bundle at path
"""
infopath = os.path.join(path, "Contents", "Info.plist")
if not os.path.exists(infopath):
infopath = os.path.join(path, "Resources", "Info.plist")
if os.path.exists(infopath):
try:
pl = FoundationPlist.readPlist(infopath)
return pl
except FoundationPlist.NSPropertyListSerializationException:
pass
return None
def getAdobeCatalogInfo(mountpoint, pkgname):
'''Used by makepkginfo to build pkginfo data for Adobe
installers/updaters'''
# Look for AdobeUberInstaller items (CS4 install)
pkgroot = os.path.join(mountpoint, pkgname)
adobeinstallxml = os.path.join(pkgroot, "AdobeUberInstaller.xml")
if os.path.exists(adobeinstallxml):
# this is a CS4 Enterprise Deployment package
cataloginfo = getAdobePackageInfo(pkgroot)
if cataloginfo:
# add some more data
cataloginfo['name'] = \
cataloginfo['display_name'].replace(" ",'')
cataloginfo['uninstallable'] = True
cataloginfo['uninstall_method'] = "AdobeUberUninstaller"
cataloginfo['installer_type'] = "AdobeUberInstaller"
if pkgname:
cataloginfo['package_path'] = pkgname
return cataloginfo
# maybe this is an Adobe update DMG or CS3 installer
# look for Adobe Setup.app
setuppath = findSetupApp(mountpoint)
if setuppath:
cataloginfo = getAdobeSetupInfo(mountpoint)
if cataloginfo:
# add some more data
cataloginfo['name'] = \
cataloginfo['display_name'].replace(" ",'')
cataloginfo['installer_type'] = "AdobeSetup"
if cataloginfo.get('AdobeSetupType') == "ProductInstall":
cataloginfo['uninstallable'] = True
cataloginfo['uninstall_method'] = "AdobeSetup"
else:
cataloginfo['description'] = "Adobe updater"
cataloginfo['uninstallable'] = False
cataloginfo['update_for'] = ["PleaseEditMe-1.0.0.0.0"]
return cataloginfo
# maybe this is an Adobe Acrobat 9 Pro patcher?
acrobatpatcherapp = findAcrobatPatchApp(mountpoint)
if acrobatpatcherapp:
cataloginfo = {}
cataloginfo['installer_type'] = "AdobeAcrobatUpdater"
cataloginfo['uninstallable'] = False
pl = getBundleInfo(acrobatpatcherapp)
cataloginfo['version'] = munkicommon.getVersionString(pl)
cataloginfo['name'] = "AcrobatPro9Update"
cataloginfo['display_name'] = "Adobe Acrobat Pro Update"
cataloginfo['update_for'] = ["AcrobatPro9"]
cataloginfo['RestartAction'] = 'RequireLogout'
cataloginfo['requires'] = []
cataloginfo['installs'] = \
[{'CFBundleIdentifier': 'com.adobe.Acrobat.Pro',
'CFBundleName': 'Acrobat',
'CFBundleShortVersionString': cataloginfo['version'],
'path':
'/Applications/Adobe Acrobat 9 Pro/Adobe Acrobat Pro.app',
'type': 'application'}]
return cataloginfo
# didn't find any Adobe installers/updaters we understand
return None
def adobeSetupError(errorcode):
# returns text description for numeric error code
@@ -429,7 +685,7 @@ def adobeSetupError(errorcode):
3 : "Unable to initialize ExtendScript",
4 : "User interface workflow failed",
5 : "Unable to initialize user interface workflow",
6 : "Slient workflow completed with errors",
6 : "Silent workflow completed with errors",
7 : "Unable to complete the silent workflow",
8 : "Exit and restart",
9 : "Unsupported operating system version",

View File

@@ -315,6 +315,9 @@ def installWithInfo(dirpath, installlist):
# Adobe Setup says restart needed
restartflag = True
retcode = 0
elif installer_type == "AdobeAcrobatUpdater":
# Acrobat Pro 9 updater
retcode = adobeutils.updateAcrobatPro(itempath)
elif installer_type == "appdmg":
retcode = copyAppFromDMG(itempath)
else:

View File

@@ -96,7 +96,10 @@ def display_status(msg):
if munkistatusoutput:
munkistatus.detail(msg)
elif verbose > 0:
print "%s..." % msg.encode('UTF-8')
if msg.endswith(".") or msg.endswith(u""):
print "%s" % msg.encode('UTF-8')
else:
print "%s..." % msg.encode('UTF-8')
sys.stdout.flush()