mirror of
https://github.com/munki/munki.git
synced 2026-01-06 06:29:56 -06:00
Support for installing AAMEE/CCP packages that include updates.
This commit is contained in:
@@ -67,6 +67,39 @@ def convertDateStringToNSDate(datetime_string):
|
||||
return None
|
||||
iso_date_string = time.strftime(ISOFormat, dt)
|
||||
return NSDate.dateWithString_(iso_date_string)
|
||||
|
||||
|
||||
def getCatalogInfoFromPath(pkgpath, options):
|
||||
"""Gets package metadata for the package at pathname.
|
||||
Returns cataloginfo"""
|
||||
cataloginfo = {}
|
||||
if os.path.exists(pkgpath):
|
||||
cataloginfo = munkicommon.getPackageMetaData(pkgpath)
|
||||
if options.installer_choices_xml:
|
||||
installer_choices_xml = munkicommon.getChoiceChangesXML(pkgpath)
|
||||
if installer_choices_xml:
|
||||
cataloginfo['installer_choices_xml'] = installer_choices_xml
|
||||
|
||||
if cataloginfo:
|
||||
# we found a package, but let's see if it's an Adobe CS5 install
|
||||
# (AAMEE) package
|
||||
if 'receipts' in cataloginfo:
|
||||
try:
|
||||
pkgid = cataloginfo['receipts'][0].get('packageid')
|
||||
except IndexError:
|
||||
pkgid = ""
|
||||
if pkgid.startswith("com.adobe.Enterprise.install"):
|
||||
# we have an Adobe CS5 install package, process
|
||||
# as Adobe install
|
||||
#adobepkgname = cataloginfo['receipts'][0].get('filename')
|
||||
cataloginfo = adobeutils.getAdobeCatalogInfo(pkgpath)
|
||||
#mountpoints[0], adobepkgname)
|
||||
|
||||
else:
|
||||
# maybe an Adobe installer/updater/patcher?
|
||||
cataloginfo = adobeutils.getAdobeCatalogInfo(pkgpath,
|
||||
options.pkgname or '')
|
||||
return cataloginfo
|
||||
|
||||
|
||||
def getCatalogInfoFromDmg(dmgpath, options):
|
||||
@@ -85,49 +118,23 @@ def getCatalogInfoFromDmg(dmgpath, options):
|
||||
|
||||
if options.pkgname:
|
||||
pkgpath = os.path.join(mountpoints[0], options.pkgname)
|
||||
if os.path.exists(pkgpath):
|
||||
cataloginfo = munkicommon.getPackageMetaData(pkgpath)
|
||||
if options.installer_choices_xml:
|
||||
installer_choices_xml = munkicommon.getChoiceChangesXML(pkgpath)
|
||||
if installer_choices_xml:
|
||||
cataloginfo['installer_choices_xml'] = installer_choices_xml
|
||||
if cataloginfo:
|
||||
cataloginfo['package_path'] = options.pkgname
|
||||
cataloginfo = getCatalogInfoFromPath(pkgpath, options)
|
||||
if cataloginfo:
|
||||
cataloginfo['package_path'] = options.pkgname
|
||||
elif not options.item:
|
||||
# search for first package at root
|
||||
for fsitem in munkicommon.listdir(mountpoints[0]):
|
||||
itempath = os.path.join(mountpoints[0], fsitem)
|
||||
if munkicommon.hasValidInstallerItemExt(itempath):
|
||||
cataloginfo = munkicommon.getPackageMetaData(itempath)
|
||||
if options.installer_choices_xml:
|
||||
installer_choices_xml = munkicommon.getChoiceChangesXML(
|
||||
itempath)
|
||||
if installer_choices_xml:
|
||||
cataloginfo['installer_choices_xml'] = \
|
||||
installer_choices_xml
|
||||
cataloginfo = getCatalogInfoFromPath(itempath, options)
|
||||
# get out of fsitem loop
|
||||
break
|
||||
|
||||
if cataloginfo:
|
||||
# we found a package, but let's see if it's an Adobe CS5 install
|
||||
# (AAMEE) package
|
||||
if 'receipts' in cataloginfo:
|
||||
try:
|
||||
pkgid = cataloginfo['receipts'][0].get('packageid')
|
||||
except IndexError:
|
||||
pkgid = ""
|
||||
if pkgid.startswith("com.adobe.Enterprise.install"):
|
||||
# we have an Adobe CS5 install package, process
|
||||
# as Adobe install
|
||||
adobepkgname = cataloginfo['receipts'][0].get('filename')
|
||||
cataloginfo = adobeutils.getAdobeCatalogInfo(
|
||||
mountpoints[0], adobepkgname)
|
||||
|
||||
else:
|
||||
# maybe an Adobe installer/updater/patcher?
|
||||
cataloginfo = adobeutils.getAdobeCatalogInfo(mountpoints[0],
|
||||
options.pkgname or '')
|
||||
|
||||
if not cataloginfo:
|
||||
# look for one of the many possible Adobe installer/updaters
|
||||
cataloginfo = adobeutils.getAdobeCatalogInfo(mountpoints[0],
|
||||
options.pkgname or '')
|
||||
|
||||
if not cataloginfo:
|
||||
# maybe this is a drag-n-drop dmg
|
||||
# look for given item or an app at the top level of the dmg
|
||||
@@ -731,12 +738,7 @@ def main():
|
||||
exit(-1)
|
||||
|
||||
elif munkicommon.hasValidPackageExt(item):
|
||||
catinfo = munkicommon.getPackageMetaData(item)
|
||||
if options.installer_choices_xml:
|
||||
installer_choices_xml = munkicommon.getChoiceChangesXML(
|
||||
item)
|
||||
if installer_choices_xml:
|
||||
catinfo['installer_choices_xml'] = installer_choices_xml
|
||||
catinfo = getCatalogInfoFromPath(item, options)
|
||||
if not catinfo:
|
||||
print >> sys.stderr, (
|
||||
"%s doesn't appear to be a valid installer item!" %
|
||||
|
||||
@@ -23,6 +23,7 @@ using the CS3/CS4/CS5 Deployment Toolkits.
|
||||
|
||||
#import sys
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from xml.dom import minidom
|
||||
@@ -33,6 +34,92 @@ import munkicommon
|
||||
import munkistatus
|
||||
import utils
|
||||
|
||||
|
||||
class AdobeInstallProgressMonitor(object):
|
||||
"""A class to monitor installs/removals of Adobe products.
|
||||
Finds the currently active installation log and scrapes data out of it.
|
||||
Installations that install a product and updates may actually create
|
||||
multiple logs."""
|
||||
|
||||
def __init__(self, kind='CS5', operation='install'):
|
||||
'''Provide some hints as to what type of installer is running and
|
||||
whether we are installing or removing'''
|
||||
self.kind = kind
|
||||
self.operation = operation
|
||||
self.payload_count = {}
|
||||
|
||||
def get_current_log(self):
|
||||
'''Returns the current Adobe install log'''
|
||||
|
||||
logpath = '/Library/Logs/Adobe/Installers'
|
||||
# find the most recently-modified log file
|
||||
proc = subprocess.Popen(['/bin/ls', '-t1', logpath],
|
||||
bufsize=-1, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(output, unused_err) = proc.communicate()
|
||||
if output:
|
||||
firstitem = str(output).splitlines()[0]
|
||||
if firstitem.endswith(".log"):
|
||||
# return path of most recently modified log file
|
||||
return os.path.join(logpath, firstitem)
|
||||
|
||||
return None
|
||||
|
||||
def info(self):
|
||||
'''Returns the number of completed Adobe payloads,
|
||||
and the AdobeCode of the most recently completed payload.'''
|
||||
last_adobecode = ""
|
||||
|
||||
logfile = self.get_current_log()
|
||||
if logfile:
|
||||
if self.kind in ['CS6', 'CS5']:
|
||||
regex = r'END TIMER :: \[Payload Operation :\{'
|
||||
elif self.kind in ['CS3', 'CS4']:
|
||||
if self.operation == 'install':
|
||||
regex = r'Closed PCD cache session payload with ID'
|
||||
else:
|
||||
regex = r'Closed CAPS session for removal of payload'
|
||||
else:
|
||||
if self.operation == 'install':
|
||||
regex = r'Completing installation for payload at '
|
||||
else:
|
||||
regex = r'Physical payload uninstall result '
|
||||
|
||||
cmd = ['/usr/bin/grep', '-E', regex, logfile]
|
||||
proc = subprocess.Popen(cmd, bufsize=-1,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(output, unused_err) = proc.communicate()
|
||||
if output:
|
||||
lines = str(output).splitlines()
|
||||
completed_payloads = len(lines)
|
||||
|
||||
if (not logfile in self.payload_count
|
||||
or completed_payloads > self.payload_count[logfile]):
|
||||
# record number of completed payloads
|
||||
self.payload_count[logfile] = completed_payloads
|
||||
|
||||
# now try to get the AdobeCode of the most recently
|
||||
# completed payload.
|
||||
# this isn't 100% accurate, but it's mostly for show
|
||||
# anyway...
|
||||
regex = re.compile(r'[^{]*(\{[A-Fa-f0-9-]+\})')
|
||||
lines.reverse()
|
||||
for line in lines:
|
||||
m = regex.match(line)
|
||||
try:
|
||||
last_adobecode = m.group(1)
|
||||
break
|
||||
except (IndexError, AttributeError):
|
||||
pass
|
||||
|
||||
total_completed_payloads = 0
|
||||
for key in self.payload_count.keys():
|
||||
total_completed_payloads += self.payload_count[key]
|
||||
|
||||
return (total_completed_payloads, last_adobecode)
|
||||
|
||||
|
||||
# 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 (or not).
|
||||
@@ -49,7 +136,7 @@ def mountAdobeDmg(dmgpath):
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(pliststr, err) = proc.communicate()
|
||||
if err:
|
||||
munkicommon.display_error("Error %s mounting %s." % (err, dmgname))
|
||||
munkicommon.display_error('Error %s mounting %s.' % (err, dmgname))
|
||||
if pliststr:
|
||||
plist = FoundationPlist.readPlistFromString(pliststr)
|
||||
for entity in plist['system-entities']:
|
||||
@@ -62,13 +149,13 @@ def mountAdobeDmg(dmgpath):
|
||||
def getCS5uninstallXML(optionXMLfile):
|
||||
'''Gets the uninstall deployment data from a CS5 installer'''
|
||||
dom = minidom.parse(optionXMLfile)
|
||||
DeploymentInfo = dom.getElementsByTagName("DeploymentInfo")
|
||||
DeploymentInfo = dom.getElementsByTagName('DeploymentInfo')
|
||||
if DeploymentInfo:
|
||||
DeploymentUninstall = DeploymentInfo[0].getElementsByTagName(
|
||||
"DeploymentUninstall")
|
||||
'DeploymentUninstall')
|
||||
if DeploymentUninstall:
|
||||
deploymentData = DeploymentUninstall[0].getElementsByTagName(
|
||||
"Deployment")
|
||||
'Deployment')
|
||||
if deploymentData:
|
||||
Deployment = deploymentData[0]
|
||||
return Deployment.toxml('UTF-8')
|
||||
@@ -82,22 +169,22 @@ def getCS5mediaSignature(dirpath):
|
||||
payloads_dir = ""
|
||||
# look for a payloads folder
|
||||
for (path, unused_dirs, unused_files) in os.walk(dirpath):
|
||||
if path.endswith("/payloads"):
|
||||
if path.endswith('/payloads'):
|
||||
payloads_dir = path
|
||||
|
||||
# return empty-handed if we didn't find a payloads folder
|
||||
if not payloads_dir:
|
||||
return ""
|
||||
return ''
|
||||
|
||||
# now look for setup.xml
|
||||
setupxml = os.path.join(payloads_dir, "Setup.xml")
|
||||
setupxml = os.path.join(payloads_dir, 'Setup.xml')
|
||||
if os.path.exists(setupxml) and os.path.isfile(setupxml):
|
||||
# parse the XML
|
||||
dom = minidom.parse(setupxml)
|
||||
setupElements = dom.getElementsByTagName("Setup")
|
||||
setupElements = dom.getElementsByTagName('Setup')
|
||||
if setupElements:
|
||||
mediaSignatureElements = \
|
||||
setupElements[0].getElementsByTagName("mediaSignature")
|
||||
setupElements[0].getElementsByTagName('mediaSignature')
|
||||
if mediaSignatureElements:
|
||||
element = mediaSignatureElements[0]
|
||||
elementvalue = ''
|
||||
@@ -117,7 +204,7 @@ def getPayloadInfo(dirpath):
|
||||
if item.endswith('.proxy.xml'):
|
||||
xmlpath = os.path.join(dirpath, item)
|
||||
dom = minidom.parse(xmlpath)
|
||||
payload_info = dom.getElementsByTagName("PayloadInfo")
|
||||
payload_info = dom.getElementsByTagName('PayloadInfo')
|
||||
if payload_info:
|
||||
installer_properties = \
|
||||
payload_info[0].getElementsByTagName(
|
||||
@@ -125,7 +212,7 @@ def getPayloadInfo(dirpath):
|
||||
if installer_properties:
|
||||
properties = \
|
||||
installer_properties[0].getElementsByTagName(
|
||||
"Property")
|
||||
'Property')
|
||||
for prop in properties:
|
||||
if 'name' in prop.attributes.keys():
|
||||
propname = \
|
||||
@@ -142,10 +229,10 @@ def getPayloadInfo(dirpath):
|
||||
|
||||
installmetadata = \
|
||||
payload_info[0].getElementsByTagName(
|
||||
"InstallDestinationMetadata")
|
||||
'InstallDestinationMetadata')
|
||||
if installmetadata:
|
||||
totalsizes = \
|
||||
installmetadata[0].getElementsByTagName("TotalSize")
|
||||
installmetadata[0].getElementsByTagName('TotalSize')
|
||||
if totalsizes:
|
||||
installsize = ''
|
||||
for node in totalsizes[0].childNodes:
|
||||
@@ -163,15 +250,15 @@ def getAdobeSetupInfo(installroot):
|
||||
info = {}
|
||||
payloads = []
|
||||
|
||||
# look for a payloads folder
|
||||
# look for all the payloads folders
|
||||
for (path, unused_dirs, unused_files) in os.walk(installroot):
|
||||
if path.endswith("/payloads"):
|
||||
if path.endswith('/payloads'):
|
||||
driverfolder = ''
|
||||
mediaSignature = ''
|
||||
setupxml = os.path.join(path, "setup.xml")
|
||||
setupxml = os.path.join(path, 'setup.xml')
|
||||
if os.path.exists(setupxml):
|
||||
dom = minidom.parse(setupxml)
|
||||
drivers = dom.getElementsByTagName("Driver")
|
||||
drivers = dom.getElementsByTagName('Driver')
|
||||
if drivers:
|
||||
driver = drivers[0]
|
||||
if 'folder' in driver.attributes.keys():
|
||||
@@ -179,11 +266,11 @@ def getAdobeSetupInfo(installroot):
|
||||
driver.attributes['folder'].value.encode('UTF-8')
|
||||
if driverfolder == '':
|
||||
# look for mediaSignature (CS5 AAMEE install)
|
||||
setupElements = dom.getElementsByTagName("Setup")
|
||||
setupElements = dom.getElementsByTagName('Setup')
|
||||
if setupElements:
|
||||
mediaSignatureElements = \
|
||||
setupElements[0].getElementsByTagName(
|
||||
"mediaSignature")
|
||||
'mediaSignature')
|
||||
if mediaSignatureElements:
|
||||
element = mediaSignatureElements[0]
|
||||
for node in element.childNodes:
|
||||
@@ -199,11 +286,7 @@ def getAdobeSetupInfo(installroot):
|
||||
payloadinfo['AdobeCode'] == mediaSignature):
|
||||
info['display_name'] = payloadinfo['display_name']
|
||||
info['version'] = payloadinfo['version']
|
||||
info['AdobeSetupType'] = "ProductInstall"
|
||||
|
||||
# we found a payloads directory,
|
||||
# so no need to keep walking the installroot
|
||||
break
|
||||
info['AdobeSetupType'] = 'ProductInstall'
|
||||
|
||||
if not payloads:
|
||||
# look for an extensions folder; almost certainly this is an Updater
|
||||
@@ -286,92 +369,16 @@ def getAdobePackageInfo(installroot):
|
||||
return info
|
||||
|
||||
|
||||
def getAdobeInstallLog():
|
||||
'''Returns the current Adobe install log'''
|
||||
|
||||
logpath = "/Library/Logs/Adobe/Installers"
|
||||
# find the most recently-modified log file
|
||||
proc = subprocess.Popen(['/bin/ls', '-t1', logpath],
|
||||
bufsize=1, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(output, unused_err) = proc.communicate()
|
||||
if output:
|
||||
firstitem = str(output).splitlines()[0]
|
||||
if firstitem.endswith(".log"):
|
||||
# get the last line of the most recently modified log
|
||||
return os.path.join(logpath, firstitem)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def getAdobeInstallProgressInfo(previous_completedpayloads,
|
||||
previous_payloadname):
|
||||
'''Returns the number of completed Adobe payloads,
|
||||
and the name of the most recentlly completed payload.'''
|
||||
|
||||
completedpayloads = previous_completedpayloads
|
||||
lastpayloadname = previous_payloadname
|
||||
|
||||
logfile = getAdobeInstallLog()
|
||||
if logfile:
|
||||
# get number of completed payloads
|
||||
regex = "(Completing installation for payload at )"
|
||||
regex += "|"
|
||||
regex += "(Physical payload uninstall result)"
|
||||
cmd = ['/usr/bin/grep', '-c', "-E", regex, logfile]
|
||||
proc = subprocess.Popen(cmd, bufsize=1,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(output, unused_err) = proc.communicate()
|
||||
if output:
|
||||
try:
|
||||
completedpayloads = int(str(output).rstrip("\n"))
|
||||
except (ValueError, TypeError):
|
||||
completedpayloads = previous_completedpayloads
|
||||
|
||||
if completedpayloads > previous_completedpayloads:
|
||||
# now try to get the name of the most recently completed payload
|
||||
# this isn't 100% accurate, but it's mostly for show anyway...
|
||||
regex = " for payload \{.*\} "
|
||||
cmd = ['/usr/bin/grep', "-E", regex, logfile]
|
||||
proc = subprocess.Popen(cmd, bufsize=1,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
(output, unused_err) = proc.communicate()
|
||||
if output:
|
||||
# start with the last line of the output
|
||||
# and work backwards until we find a name
|
||||
lines = str(output).splitlines()
|
||||
lines.reverse()
|
||||
for line in lines:
|
||||
parts = line.split("}", 1)
|
||||
if len(parts) == 2:
|
||||
if parts[1]:
|
||||
name = parts[1].lstrip()
|
||||
if not name.startswith("returned :"):
|
||||
lastpayloadname = name
|
||||
break
|
||||
|
||||
return (completedpayloads, lastpayloadname)
|
||||
|
||||
|
||||
def countPayloads(dirpath):
|
||||
'''Attempts to count the payloads in the Adobe installation item'''
|
||||
for item in munkicommon.listdir(dirpath):
|
||||
itempath = os.path.join(dirpath, item)
|
||||
if os.path.isdir(itempath):
|
||||
if item == "payloads":
|
||||
count = 0
|
||||
for subitem in munkicommon.listdir(itempath):
|
||||
subitempath = os.path.join(itempath, subitem)
|
||||
if os.path.isdir(subitempath):
|
||||
count = count + 1
|
||||
return count
|
||||
else:
|
||||
payloadcount = countPayloads(itempath)
|
||||
if payloadcount:
|
||||
return payloadcount
|
||||
return 0
|
||||
count = 0
|
||||
for (path, unused_dirs, unused_files) in os.walk(dirpath):
|
||||
if path.endswith("/payloads"):
|
||||
for subitem in munkicommon.listdir(path):
|
||||
subitempath = os.path.join(path, subitem)
|
||||
if os.path.isdir(subitempath):
|
||||
count = count + 1
|
||||
return count
|
||||
|
||||
|
||||
def getPercent(current, maximum):
|
||||
@@ -464,9 +471,16 @@ def killStupidProcesses():
|
||||
return
|
||||
|
||||
|
||||
def runAdobeInstallTool(cmd, number_of_payloads=0, killAdobeAIR=False):
|
||||
def runAdobeInstallTool(
|
||||
cmd, number_of_payloads=0, killAdobeAIR=False, payloads=None,
|
||||
kind="CS5", operation="install"):
|
||||
'''An abstraction of the tasks for running Adobe Setup,
|
||||
AdobeUberInstaller, AdobeUberUninstaller, AdobeDeploymentManager, etc'''
|
||||
|
||||
# initialize an AdobeInstallProgressMonitor object.
|
||||
progress_monitor = AdobeInstallProgressMonitor(
|
||||
kind=kind, operation=operation)
|
||||
|
||||
if munkicommon.munkistatusoutput and not number_of_payloads:
|
||||
# indeterminate progress bar
|
||||
munkistatus.percent(-1)
|
||||
@@ -479,12 +493,16 @@ def runAdobeInstallTool(cmd, number_of_payloads=0, killAdobeAIR=False):
|
||||
payloadname = ""
|
||||
while (proc.poll() == None):
|
||||
time.sleep(1)
|
||||
(payload_completed_count, payloadname) = \
|
||||
getAdobeInstallProgressInfo(old_payload_completed_count,
|
||||
payloadname)
|
||||
(payload_completed_count, adobe_code) = progress_monitor.info()
|
||||
if payload_completed_count > old_payload_completed_count:
|
||||
old_payload_completed_count = payload_completed_count
|
||||
if payloadname:
|
||||
if adobe_code and payloads:
|
||||
matched_payloads = [payload for payload in payloads
|
||||
if payload.get('AdobeCode') == adobe_code]
|
||||
if matched_payloads:
|
||||
payloadname = matched_payloads[0].get('display_name')
|
||||
else:
|
||||
payloadname = adobe_code
|
||||
payloadinfo = " - " + payloadname
|
||||
else:
|
||||
payloadinfo = ""
|
||||
@@ -537,7 +555,7 @@ def runAdobeInstallTool(cmd, number_of_payloads=0, killAdobeAIR=False):
|
||||
return retcode
|
||||
|
||||
|
||||
def runAdobeSetup(dmgpath, uninstalling=False):
|
||||
def runAdobeSetup(dmgpath, uninstalling=False, payloads=None):
|
||||
'''Runs the Adobe setup tool in silent mode from
|
||||
an Adobe update DMG or an Adobe CS3 install DMG'''
|
||||
munkicommon.display_status_minor(
|
||||
@@ -551,6 +569,7 @@ def runAdobeSetup(dmgpath, uninstalling=False):
|
||||
installxml = os.path.join(mountpoints[0], "install.xml")
|
||||
uninstallxml = os.path.join(mountpoints[0], "uninstall.xml")
|
||||
if uninstalling:
|
||||
operation = 'uninstall'
|
||||
if os.path.exists(uninstallxml):
|
||||
deploymentfile = uninstallxml
|
||||
else:
|
||||
@@ -563,6 +582,7 @@ def runAdobeSetup(dmgpath, uninstalling=False):
|
||||
os.path.basename(dmgpath))
|
||||
return -1
|
||||
else:
|
||||
operation = 'install'
|
||||
if os.path.exists(installxml):
|
||||
deploymentfile = installxml
|
||||
|
||||
@@ -575,7 +595,9 @@ def runAdobeSetup(dmgpath, uninstalling=False):
|
||||
if deploymentfile:
|
||||
adobe_setup.append('--deploymentFile=%s' % deploymentfile)
|
||||
|
||||
retcode = runAdobeInstallTool(adobe_setup, number_of_payloads)
|
||||
retcode = runAdobeInstallTool(
|
||||
adobe_setup, number_of_payloads, payloads=payloads,
|
||||
kind='CS3', operation=operation)
|
||||
|
||||
else:
|
||||
munkicommon.display_error(
|
||||
@@ -603,7 +625,7 @@ def writefile(stringdata, path):
|
||||
return ""
|
||||
|
||||
|
||||
def doAdobeCS5Uninstall(adobeInstallInfo):
|
||||
def doAdobeCS5Uninstall(adobeInstallInfo, payloads=None):
|
||||
'''Runs the locally-installed Adobe CS5 tools to remove CS5 products.
|
||||
We need the uninstallxml and the CS5 Setup.app.'''
|
||||
uninstallxml = adobeInstallInfo.get('uninstallxml')
|
||||
@@ -626,10 +648,11 @@ def doAdobeCS5Uninstall(adobeInstallInfo):
|
||||
'--skipProcessCheck=1',
|
||||
'--deploymentFile=%s' % deploymentFile ]
|
||||
munkicommon.display_status_minor('Running Adobe Uninstall')
|
||||
return runAdobeInstallTool(uninstall_cmd, payloadcount)
|
||||
return runAdobeInstallTool(uninstall_cmd, payloadcount, payloads=payloads,
|
||||
kind='CS5', operation='uninstall')
|
||||
|
||||
|
||||
def runAdobeCS5AAMEEInstall(dmgpath):
|
||||
def runAdobeCS5AAMEEInstall(dmgpath, payloads=None):
|
||||
'''Installs a CS5 product using an AAMEE-generated package on a
|
||||
disk image.'''
|
||||
munkicommon.display_status_minor(
|
||||
@@ -643,13 +666,16 @@ def runAdobeCS5AAMEEInstall(dmgpath):
|
||||
if deploymentmanager:
|
||||
# big hack to convince the Adobe tools to install off a mounted
|
||||
# disk image.
|
||||
# For some reason, the Adobe install tools refuse to install when
|
||||
# the payloads are on a "removable" disk, which includes mounted disk
|
||||
# images.
|
||||
#
|
||||
# For some reason, some versions of the Adobe install tools refuse to
|
||||
# install when the payloads are on a "removable" disk,
|
||||
# which includes mounted disk images.
|
||||
#
|
||||
# we create a temporary directory on the local disk and then symlink
|
||||
# some resources from the mounted disk image to the temporary
|
||||
# directory. When we pass this temporary directory to the Adobe
|
||||
# installation tools, they are now happy.
|
||||
|
||||
basepath = os.path.dirname(deploymentmanager)
|
||||
number_of_payloads = countPayloads(basepath)
|
||||
tmpdir = tempfile.mkdtemp(prefix='munki-', dir='/tmp')
|
||||
@@ -657,14 +683,17 @@ def runAdobeCS5AAMEEInstall(dmgpath):
|
||||
# make our symlinks
|
||||
os.symlink(os.path.join(basepath,"ASU"), os.path.join(tmpdir, "ASU"))
|
||||
os.symlink(os.path.join(basepath,"ProvisioningTool"),
|
||||
os.path.join(tmpdir, "ProvisioningTool"))
|
||||
os.path.join(tmpdir, "ProvisioningTool"))
|
||||
|
||||
realsetupdir = os.path.join(basepath,"Setup")
|
||||
tmpsetupdir = os.path.join(tmpdir, "Setup")
|
||||
os.mkdir(tmpsetupdir)
|
||||
for item in munkicommon.listdir(realsetupdir):
|
||||
os.symlink(os.path.join(realsetupdir, item),
|
||||
os.path.join(tmpsetupdir, item))
|
||||
for dir_name in ['Patches', 'Setup']:
|
||||
realdir = os.path.join(basepath, dir_name)
|
||||
if os.path.isdir(realdir):
|
||||
tmpsubdir = os.path.join(tmpdir, dir_name)
|
||||
os.mkdir(tmpsubdir)
|
||||
for item in munkicommon.listdir(realdir):
|
||||
os.symlink(
|
||||
os.path.join(realdir, item),
|
||||
os.path.join(tmpsubdir, item))
|
||||
|
||||
optionXMLfile = os.path.join(basepath, "optionXML.xml")
|
||||
if (not munkicommon.getconsoleuser() or
|
||||
@@ -677,12 +706,13 @@ def runAdobeCS5AAMEEInstall(dmgpath):
|
||||
cmd = []
|
||||
|
||||
cmd.extend([deploymentmanager, '--optXMLPath=%s' % optionXMLfile,
|
||||
'--setupBasePath=%s' % tmpdir, '--installDirPath=/',
|
||||
'--mode=install'])
|
||||
'--setupBasePath=%s' % basepath, '--installDirPath=/',
|
||||
'--mode=install'])
|
||||
|
||||
munkicommon.display_status_minor('Starting Adobe installer...')
|
||||
retcode = runAdobeInstallTool(cmd, number_of_payloads,
|
||||
killAdobeAIR=True)
|
||||
retcode = runAdobeInstallTool(
|
||||
cmd, number_of_payloads, killAdobeAIR=True, payloads=payloads,
|
||||
kind='CS5', operation='install')
|
||||
# now clean up our symlink hackfest
|
||||
unused_result = subprocess.call(["/bin/rm", "-rf", tmpdir])
|
||||
else:
|
||||
@@ -695,7 +725,7 @@ def runAdobeCS5AAMEEInstall(dmgpath):
|
||||
return retcode
|
||||
|
||||
|
||||
def runAdobeCS5PatchInstaller(dmgpath, copylocal=False):
|
||||
def runAdobeCS5PatchInstaller(dmgpath, copylocal=False, payloads=None):
|
||||
'''Runs the AdobePatchInstaller for CS5.
|
||||
Optionally can copy the DMG contents to the local disk
|
||||
to work around issues with the patcher.'''
|
||||
@@ -730,7 +760,8 @@ def runAdobeCS5PatchInstaller(dmgpath, copylocal=False):
|
||||
'--mode=silent',
|
||||
'--skipProcessCheck=1' ]
|
||||
retcode = runAdobeInstallTool(install_cmd,
|
||||
number_of_payloads)
|
||||
number_of_payloads, payloads=payloads,
|
||||
kind='CS5', operation='install')
|
||||
else:
|
||||
munkicommon.display_error(
|
||||
"%s doesn't appear to contain AdobePatchInstaller.app." %
|
||||
@@ -747,7 +778,7 @@ def runAdobeCS5PatchInstaller(dmgpath, copylocal=False):
|
||||
return -1
|
||||
|
||||
|
||||
def runAdobeUberTool(dmgpath, pkgname='', uninstalling=False):
|
||||
def runAdobeUberTool(dmgpath, pkgname='', uninstalling=False, payloads=None):
|
||||
'''Runs either AdobeUberInstaller or AdobeUberUninstaller
|
||||
from a disk image and provides progress feedback.
|
||||
pkgname is the name of a directory at the top level of the dmg
|
||||
@@ -769,8 +800,10 @@ def runAdobeUberTool(dmgpath, pkgname='', uninstalling=False):
|
||||
info = getAdobePackageInfo(installroot)
|
||||
packagename = info['display_name']
|
||||
action = "Installing"
|
||||
operation = "install"
|
||||
if uninstalling:
|
||||
action = "Uninstalling"
|
||||
operation = "uninstall"
|
||||
munkicommon.display_status_major('%s %s' % (action, packagename))
|
||||
if munkicommon.munkistatusoutput:
|
||||
munkistatus.detail('Starting %s' % os.path.basename(ubertool))
|
||||
@@ -780,7 +813,8 @@ def runAdobeUberTool(dmgpath, pkgname='', uninstalling=False):
|
||||
number_of_payloads = countPayloads(installroot)
|
||||
|
||||
retcode = runAdobeInstallTool(
|
||||
[ubertool], number_of_payloads, killAdobeAIR=True)
|
||||
[ubertool], number_of_payloads, killAdobeAIR=True,
|
||||
payloads=payloads, kind='CS4', operation=operation)
|
||||
|
||||
else:
|
||||
munkicommon.display_error("No %s found" % ubertool)
|
||||
@@ -793,23 +827,6 @@ def runAdobeUberTool(dmgpath, pkgname='', uninstalling=False):
|
||||
return -1
|
||||
|
||||
|
||||
#lastpatchlogline = ''
|
||||
#def getAcrobatPatchLogInfo(logpath):
|
||||
# '''Gets info from the Adobe Acrobat patch log'''
|
||||
# global lastpatchlogline
|
||||
# if os.path.exists(logpath):
|
||||
# proc = subprocess.Popen(['/usr/bin/tail', '-1', logpath],
|
||||
# bufsize=1, stdout=subprocess.PIPE,
|
||||
# stderr=subprocess.PIPE)
|
||||
# (output, err) = proc.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. If found, returns the path to the bundled
|
||||
@@ -913,23 +930,12 @@ def updateAcrobatPro(dmgpath):
|
||||
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)
|
||||
|
||||
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
while (proc.poll() == None):
|
||||
time.sleep(1)
|
||||
#loginfo = getAcrobatPatchLogInfo(logfile_path)
|
||||
#if loginfo:
|
||||
# print loginfo
|
||||
|
||||
# run of patch tool completed
|
||||
retcode = proc.poll()
|
||||
@@ -1186,6 +1192,7 @@ def adobeSetupError(errorcode):
|
||||
def doAdobeRemoval(item):
|
||||
'''Wrapper for all the Adobe removal methods'''
|
||||
uninstallmethod = item['uninstall_method']
|
||||
payloads = item.get("payloads")
|
||||
itempath = ""
|
||||
if "uninstaller_item" in item:
|
||||
managedinstallbase = munkicommon.pref('ManagedInstallDir')
|
||||
@@ -1199,18 +1206,19 @@ def doAdobeRemoval(item):
|
||||
|
||||
if uninstallmethod == "AdobeSetup":
|
||||
# CS3 uninstall
|
||||
retcode = runAdobeSetup(itempath, uninstalling=True)
|
||||
retcode = runAdobeSetup(itempath, uninstalling=True, payloads=payloads)
|
||||
|
||||
elif uninstallmethod == "AdobeUberUninstaller":
|
||||
# CS4 uninstall
|
||||
pkgname = item.get("adobe_package_name") or \
|
||||
item.get("package_path","")
|
||||
retcode = runAdobeUberTool(itempath, pkgname, uninstalling=True)
|
||||
retcode = runAdobeUberTool(
|
||||
itempath, pkgname, uninstalling=True, payloads=payloads)
|
||||
|
||||
elif uninstallmethod == "AdobeCS5AAMEEPackage":
|
||||
# CS5 uninstall. Sheesh. Three releases, three methods.
|
||||
adobeInstallInfo = item.get('adobe_install_info')
|
||||
retcode = doAdobeCS5Uninstall(adobeInstallInfo)
|
||||
retcode = doAdobeCS5Uninstall(adobeInstallInfo, payloads=payloads)
|
||||
|
||||
if retcode:
|
||||
munkicommon.display_error("Uninstall of %s failed." % item['name'])
|
||||
@@ -1228,24 +1236,25 @@ def doAdobeInstall(item):
|
||||
'Cache',
|
||||
item["installer_item"])
|
||||
installer_type = item.get("installer_type","")
|
||||
payloads = item.get("payloads")
|
||||
if installer_type == "AdobeSetup":
|
||||
# Adobe CS3/CS4 updater or Adobe CS3 installer
|
||||
retcode = runAdobeSetup(itempath)
|
||||
retcode = runAdobeSetup(itempath, payloads=payloads)
|
||||
elif installer_type == "AdobeUberInstaller":
|
||||
# Adobe CS4 installer
|
||||
pkgname = item.get("adobe_package_name") or \
|
||||
item.get("package_path","")
|
||||
retcode = runAdobeUberTool(itempath, pkgname)
|
||||
retcode = runAdobeUberTool(itempath, pkgname, payloads=payloads)
|
||||
elif installer_type == "AdobeAcrobatUpdater":
|
||||
# Acrobat Pro 9 updater
|
||||
retcode = updateAcrobatPro(itempath)
|
||||
elif installer_type == "AdobeCS5AAMEEPackage":
|
||||
# Adobe CS5 AAMEE package
|
||||
retcode = runAdobeCS5AAMEEInstall(itempath)
|
||||
retcode = runAdobeCS5AAMEEInstall(itempath, payloads=payloads)
|
||||
elif installer_type == "AdobeCS5PatchInstaller":
|
||||
# Adobe CS5 updater
|
||||
retcode = runAdobeCS5PatchInstaller(itempath,
|
||||
copylocal=item.get("copy_local"))
|
||||
copylocal=item.get("copy_local"), payloads=payloads)
|
||||
return retcode
|
||||
|
||||
|
||||
|
||||
@@ -1765,6 +1765,7 @@ def processInstall(manifestitem, cataloglist, installinfo):
|
||||
'installs',
|
||||
'requires',
|
||||
'update_for',
|
||||
'payloads',
|
||||
'preinstall_script',
|
||||
'postinstall_script',
|
||||
'items_to_copy', # used w/ copy_from_dmg
|
||||
@@ -2211,6 +2212,7 @@ def processRemoval(manifestitem, cataloglist, installinfo):
|
||||
'installs',
|
||||
'requires',
|
||||
'update_for',
|
||||
'payloads',
|
||||
'preuninstall_script',
|
||||
'postuninstall_script',
|
||||
'apple_item']
|
||||
|
||||
Reference in New Issue
Block a user