First iteration of forced installs/uninstalls.

If pkginfo key forced_(un)install is set to <true/>, (un)installs will run immediately after downloading without any notification the user.  If further non-forced installs are remaining MSU.app will appear after all forced-installs are finished.

This needs documentation about how risky it is; should only be used for simple packages that are known to be safely installed while app is running. More features will come in the future making it safer to use on other packages.



git-svn-id: http://munki.googlecode.com/svn/trunk@814 a4e17f2e-e282-11dd-95e1-755cbddbdd66
This commit is contained in:
Justin McWilliams
2010-10-18 21:20:11 +00:00
3 changed files with 188 additions and 153 deletions
+29 -19
View File
@@ -126,16 +126,21 @@ def initMunkiDirs():
return True
def doInstallTasks():
def doInstallTasks(only_forced=False):
"""Perform our installation/removal tasks.
Args:
only_forced: Boolean. If True, only do forced installs/removals.
Returns:
Boolean. True if a restart is required, False otherwise.
"""
# first, clear the last notified date
# so we can get notified of new changes after this round
# of installs
clearLastNotifiedDate()
if not only_forced:
# first, clear the last notified date
# so we can get notified of new changes after this round
# of installs
clearLastNotifiedDate()
need_to_restart = False
# munki updates take priority over Apple Updates, because
# a munki install or (especially) removal could make a
@@ -147,7 +152,7 @@ def doInstallTasks():
if munkiUpdatesAvailable():
# install munki updates
try:
need_to_restart = installer.run()
need_to_restart = installer.run(only_forced=only_forced)
except:
munkicommon.display_error('Unexpected error in '
' munkilib.installer:')
@@ -157,8 +162,10 @@ def doInstallTasks():
# clear any Apple update info since it may no longer
# be relevant
appleupdates.clearAppleUpdateInfo()
elif munkicommon.pref('InstallAppleSoftwareUpdates'):
if not only_forced:
appleupdates.clearAppleUpdateInfo()
elif munkicommon.pref('InstallAppleSoftwareUpdates') and \
not only_forced:
# are we supposed to handle Apple Software Updates?
try:
need_to_restart = appleupdates.installAppleUpdates()
@@ -233,10 +240,15 @@ def recordUpdateCheckResult(result):
def notifyUserOfUpdates():
"""Notify the logged-in user of available updates."""
"""Notify the logged-in user of available updates.
Returns:
Boolean. True if the user was notified, False otherwise.
"""
# called when options.auto == True
# someone is logged in, and we have updates.
# if we haven't notified in a while, notify:
user_was_notified = False
lastNotifiedString = munkicommon.pref('LastNotifiedDate')
daysBetweenNotifications = munkicommon.pref('DaysBetweenNotifications')
now = NSDate.new()
@@ -270,6 +282,8 @@ def notifyUserOfUpdates():
time.sleep(0.1)
if os.path.exists(launchfile):
os.unlink(launchfile)
user_was_notified = True
return user_was_notified
def runPreOrPostFlightScript(script, runtype='custom'):
@@ -581,11 +595,6 @@ def main():
munkicommon.savereport()
exit(-1)
if options.auto:
# when --auto, munkistatusoutput is false for checking,
# but true for installing
munkicommon.munkistatusoutput = True
mustrestart = False
if options.manualcheck:
# just quit munkistatus; Managed Software Update will notify
@@ -595,18 +604,19 @@ def main():
# just install
mustrestart = doInstallTasks()
elif options.auto:
if not munkicommon.currentGUIusers():
# no GUI users
if not munkicommon.currentGUIusers(): # no GUI users
if getIdleSeconds() > 10:
if not munkicommon.pref('SuppressAutoInstall') or \
runtype == 'checkandinstallatstartup':
# no GUI users, system is idle, so install
# enable status output over login window
munkicommon.munkistatusoutput = True
mustrestart = doInstallTasks()
else:
munkicommon.log('Skipping auto install because '
'SuppressAutoInstall is true.')
else:
# there are GUI users
else: # there are GUI users
doInstallTasks(only_forced=True)
consoleuser = munkicommon.getconsoleuser()
if consoleuser == u'loginwindow':
# someone is logged in, but we're sitting at
@@ -614,11 +624,11 @@ def main():
# so do nothing
pass
elif not munkicommon.pref('SuppressUserNotification'):
# notify the current console user
notifyUserOfUpdates()
else:
munkicommon.log('Skipping user notification because '
'SuppressUserNotification is true.')
elif not options.quiet:
print ('\nRun %s --installonly to install the downloaded '
'updates.' % myname)
+155 -131
View File
@@ -6,9 +6,9 @@
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#
# http://www.apache.org/licenses/LICENSE-2.0
#
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -55,7 +55,7 @@ def removeBundleRelocationInfo(pkgpath):
"Removed Contents/Resources/TokenDefinitions.plist")
except OSError:
pass
plist = {}
infoplist = os.path.join(pkgpath, "Contents/Info.plist")
if os.path.exists(infoplist):
@@ -63,7 +63,7 @@ def removeBundleRelocationInfo(pkgpath):
plist = FoundationPlist.readPlist(infoplist)
except FoundationPlist.NSPropertyListSerializationException:
pass
if 'IFPkgPathMappings' in plist:
del plist['IFPkgPathMappings']
try:
@@ -72,26 +72,26 @@ def removeBundleRelocationInfo(pkgpath):
"Removed IFPkgPathMappings")
except FoundationPlist.NSPropertyListWriteException:
pass
def install(pkgpath, choicesXMLpath=None, suppressBundleRelocation=False):
"""
Uses the apple installer to install the package or metapackage
at pkgpath. Prints status messages to STDOUT.
Returns a tuple:
Returns a tuple:
the installer return code and restart needed as a boolean.
"""
restartneeded = False
installeroutput = []
if os.path.islink(pkgpath):
# resolve links before passing them to /usr/bin/installer
pkgpath = os.path.realpath(pkgpath)
if suppressBundleRelocation:
removeBundleRelocationInfo(pkgpath)
packagename = ''
restartaction = 'None'
pkginfo = munkicommon.getInstallerPkgInfo(pkgpath)
@@ -100,20 +100,20 @@ def install(pkgpath, choicesXMLpath=None, suppressBundleRelocation=False):
restartaction = pkginfo.get('RestartAction','None')
if not packagename:
packagename = os.path.basename(pkgpath)
if munkicommon.munkistatusoutput:
munkistatus.message("Installing %s..." % packagename)
munkistatus.detail("")
# clear indeterminate progress bar
# clear indeterminate progress bar
munkistatus.percent(0)
munkicommon.log("Installing %s from %s" % (packagename,
os.path.basename(pkgpath)))
cmd = ['/usr/sbin/installer', '-query', 'RestartAction', '-pkg', pkgpath]
if choicesXMLpath:
cmd.extend(['-applyChoiceChangesXML', choicesXMLpath])
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, unused_err) = proc.communicate()
restartaction = str(output).decode('UTF-8').rstrip("\n")
@@ -122,19 +122,19 @@ def install(pkgpath, choicesXMLpath=None, suppressBundleRelocation=False):
munkicommon.display_status("%s requires a restart after installation."
% packagename)
restartneeded = True
# get the OS version; we need it later when processing installer's output,
# which varies depending on OS version.
# get the OS version; we need it later when processing installer's output,
# which varies depending on OS version.
osvers = int(os.uname()[2].split('.')[0])
cmd = ['/usr/sbin/installer', '-verboseR', '-pkg', pkgpath,
cmd = ['/usr/sbin/installer', '-verboseR', '-pkg', pkgpath,
'-target', '/']
if choicesXMLpath:
cmd.extend(['-applyChoiceChangesXML', choicesXMLpath])
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
while True:
installinfo = proc.stdout.readline().decode('UTF-8')
if not installinfo and (proc.poll() != None):
break
@@ -196,7 +196,7 @@ def install(pkgpath, choicesXMLpath=None, suppressBundleRelocation=False):
munkicommon.log("Install of %s was successful." % packagename)
if munkicommon.munkistatusoutput:
munkistatus.percent(100)
return (retcode, restartneeded)
@@ -234,22 +234,22 @@ def installall(dirpath, choicesXMLpath=None, suppressBundleRelocation=False):
if retcode:
# ran into error; should unmount and stop.
munkicommon.unmountdmg(mountpoints[0])
return (retcode, restartflag)
return (retcode, restartflag)
munkicommon.unmountdmg(mountpoints[0])
if (item.endswith(".pkg") or item.endswith(".mpkg")):
(retcode, needsrestart) = install(itempath, choicesXMLpath,
(retcode, needsrestart) = install(itempath, choicesXMLpath,
suppressBundleRelocation)
if needsrestart:
restartflag = True
if retcode:
# ran into error; should stop.
return (retcode, restartflag)
return (retcode, restartflag)
def copyAppFromDMG(dmgpath):
'''copies application from DMG to /Applications'''
munkicommon.display_status("Mounting disk image %s" %
@@ -265,8 +265,8 @@ def copyAppFromDMG(dmgpath):
if munkicommon.isApplication(itempath):
appname = item
break
if appname:
if appname:
destpath = os.path.join("/Applications", appname)
if os.path.exists(destpath):
retcode = subprocess.call(["/bin/rm", "-r", destpath])
@@ -276,48 +276,48 @@ def copyAppFromDMG(dmgpath):
if retcode == 0:
munkicommon.display_status(
"Copying %s to Applications folder" % appname)
retcode = subprocess.call(["/bin/cp", "-R",
retcode = subprocess.call(["/bin/cp", "-R",
itempath, destpath])
if retcode:
munkicommon.display_error("Error copying %s to %s" %
munkicommon.display_error("Error copying %s to %s" %
(itempath, destpath))
if retcode == 0:
# remove com.apple.quarantine attribute from copied app
cmd = ["/usr/bin/xattr", destpath]
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, unused_err) = proc.communicate()
if out:
xattrs = str(out).splitlines()
if "com.apple.quarantine" in xattrs:
unused_result = subprocess.call(
["/usr/bin/xattr", "-d",
"com.apple.quarantine",
["/usr/bin/xattr", "-d",
"com.apple.quarantine",
destpath])
# let the user know we completed successfully
munkicommon.display_status(
"The software was successfully installed.")
munkicommon.unmountdmg(mountpoint)
if not appname:
munkicommon.display_error("No application found on %s" %
munkicommon.display_error("No application found on %s" %
os.path.basename(dmgpath))
retcode = -2
return retcode
else:
munkicommon.display_error("No mountable filesystems on %s" %
munkicommon.display_error("No mountable filesystems on %s" %
os.path.basename(dmgpath))
return -1
def copyFromDMG(dmgpath, itemlist):
'''copies items from DMG to local disk'''
if not itemlist:
munkicommon.display_error("No items to copy!")
return -1
munkicommon.display_status("Mounting disk image %s" %
os.path.basename(dmgpath))
mountpoints = munkicommon.mountdmg(dmgpath)
@@ -329,7 +329,7 @@ def copyFromDMG(dmgpath, itemlist):
if not itemname:
munkicommon.display_error("Missing name of item to copy!")
retcode = -1
if retcode == 0:
itempath = os.path.join(mountpoint, itemname)
if os.path.exists(itempath):
@@ -351,69 +351,69 @@ def copyFromDMG(dmgpath, itemlist):
munkicommon.display_error(
"Source item %s does not exist!" % itemname)
retcode = -1
if retcode == 0:
munkicommon.display_status(
"Copying %s to %s" % (itemname, destpath))
retcode = subprocess.call(["/bin/cp", "-R",
retcode = subprocess.call(["/bin/cp", "-R",
itempath, destpath])
if retcode:
munkicommon.display_error(
"Error copying %s to %s" %
"Error copying %s to %s" %
(itempath, destpath))
destitem = os.path.join(destpath, itemname)
if (retcode == 0) and ('user' in item):
munkicommon.display_detail(
"Setting owner for '%s' to '%s'" %
"Setting owner for '%s' to '%s'" %
(destitem, item['user']))
cmd = ['/usr/sbin/chown', '-R', item['user'], destitem]
retcode = subprocess.call(cmd)
if retcode:
munkicommon.display_error("Error setting owner for %s" %
munkicommon.display_error("Error setting owner for %s" %
(destitem))
if (retcode == 0) and ('group' in item):
munkicommon.display_detail(
"Setting group for '%s' to '%s'" %
"Setting group for '%s' to '%s'" %
(destitem, item['group']))
cmd = ['/usr/bin/chgrp', '-R', item['group'], destitem]
retcode = subprocess.call(cmd)
if retcode:
munkicommon.display_error("Error setting group for %s" %
munkicommon.display_error("Error setting group for %s" %
(destitem))
if (retcode == 0) and ('mode' in item):
munkicommon.display_detail(
"Setting mode for '%s' to '%s'" %
"Setting mode for '%s' to '%s'" %
(destitem, item['mode']))
cmd = ['/bin/chmod', '-R', item['mode'], destitem]
retcode = subprocess.call(cmd)
if retcode:
munkicommon.display_error("Error setting mode for %s" %
munkicommon.display_error("Error setting mode for %s" %
(destitem))
if retcode == 0:
# remove com.apple.quarantine attribute from copied item
cmd = ["/usr/bin/xattr", destitem]
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(out, unused_err) = proc.communicate()
if out:
xattrs = str(out).splitlines()
if "com.apple.quarantine" in xattrs:
unused_result = subprocess.call(
["/usr/bin/xattr", "-d",
"com.apple.quarantine",
["/usr/bin/xattr", "-d",
"com.apple.quarantine",
destitem])
if retcode:
# we encountered an error on this iteration;
# we encountered an error on this iteration;
# should not continue.
break
if retcode == 0:
# let the user know we completed successfully
munkicommon.display_status(
@@ -421,7 +421,7 @@ def copyFromDMG(dmgpath, itemlist):
munkicommon.unmountdmg(mountpoint)
return retcode
else:
munkicommon.display_error("No mountable filesystems on %s" %
munkicommon.display_error("No mountable filesystems on %s" %
os.path.basename(dmgpath))
return -1
@@ -433,7 +433,7 @@ def removeCopiedItems(itemlist):
if not itemlist:
munkicommon.display_error("Nothing to remove!")
return -1
for item in itemlist:
itemname = item.get("source_item")
if not itemname:
@@ -458,7 +458,7 @@ def removeCopiedItems(itemlist):
# note it, but not an error
munkicommon.display_detail("Path %s doesn't exist." %
path_to_remove)
return retcode
def installWithInfo(dirpath, installlist):
@@ -477,14 +477,14 @@ def installWithInfo(dirpath, installlist):
item.get('manifestitem')
version_to_install = item.get('version_to_install','')
if munkicommon.munkistatusoutput:
munkistatus.message("Installing %s (%s of %s)..." %
(display_name, itemindex,
munkistatus.message("Installing %s (%s of %s)..." %
(display_name, itemindex,
len(installlist)))
munkistatus.detail("")
munkistatus.percent(-1)
else:
munkicommon.display_status("Installing %s (%s of %s)" %
(display_name, itemindex,
munkicommon.display_status("Installing %s (%s of %s)" %
(display_name, itemindex,
len(installlist)))
itempath = os.path.join(dirpath, item["installer_item"])
if not os.path.exists(itempath):
@@ -513,7 +513,7 @@ def installWithInfo(dirpath, installlist):
elif installer_type == "appdmg":
retcode = copyAppFromDMG(itempath)
elif installer_type != "":
# we've encountered an installer type
# we've encountered an installer type
# we don't know how to handle
munkicommon.log("Unsupported install type: %s" %
installer_type)
@@ -525,7 +525,7 @@ def installWithInfo(dirpath, installlist):
munkicommon.display_debug1("suppress_bundle_relocation: %s" %
suppressBundleRelocation )
if 'installer_choices_xml' in item:
choicesXMLfile = os.path.join(munkicommon.tmpdir,
choicesXMLfile = os.path.join(munkicommon.tmpdir,
"choices.xml")
FoundationPlist.writePlist(item['installer_choices_xml'],
choicesXMLfile)
@@ -538,7 +538,7 @@ def installWithInfo(dirpath, installlist):
# we need to mount the diskimage as read/write to
# be able to modify the package to suppress bundle
# relocation
mountpoints = munkicommon.mountdmg(itempath,
mountpoints = munkicommon.mountdmg(itempath,
use_shadow=mountWithShadow)
if mountpoints == []:
munkicommon.display_error("No filesystems mounted "
@@ -551,9 +551,9 @@ def installWithInfo(dirpath, installlist):
needtorestart = False
if item.get('package_path','').endswith('.pkg') or \
item.get('package_path','').endswith('.mpkg'):
# admin has specified the relative path of the pkg
# admin has specified the relative path of the pkg
# on the DMG
# this is useful if there is more than one pkg on
# this is useful if there is more than one pkg on
# the DMG, or the actual pkg is not at the root
# of the DMG
fullpkgpath = os.path.join(mountpoints[0],
@@ -582,17 +582,17 @@ def installWithInfo(dirpath, installlist):
if needtorestart:
restartflag = True
elif os.path.isdir(itempath):
# directory of packages,
# directory of packages,
# like what we get from Software Update
(retcode, needtorestart) = installall(itempath,
choicesXMLfile,
suppressBundleRelocation)
if needtorestart:
restartflag = True
# record install success/failure
if retcode == 0:
success_msg = ("Install of %s-%s: SUCCESSFUL" %
success_msg = ("Install of %s-%s: SUCCESSFUL" %
(display_name, version_to_install))
munkicommon.log(success_msg, "Install.log")
munkicommon.report['InstallResults'].append(success_msg)
@@ -602,10 +602,10 @@ def installWithInfo(dirpath, installlist):
(display_name, version_to_install, retcode))
munkicommon.log(failure_msg, "Install.log")
munkicommon.report['InstallResults'].append(failure_msg)
# check to see if this installer item is needed by any additional
# check to see if this installer item is needed by any additional
# items in installinfo
# this might happen if there are multiple things being installed
# this might happen if there are multiple things being installed
# with choicesXML files applied to a metapackage or
# multiple packages being installed from a single DMG
foundagain = False
@@ -622,9 +622,9 @@ def installWithInfo(dirpath, installlist):
current_installer_item:
foundagain = True
break
if not foundagain:
# now remove the item from the install cache
# now remove the item from the install cache
# (if it's still there)
itempath = os.path.join(dirpath, current_installer_item)
if os.path.exists(itempath):
@@ -636,7 +636,7 @@ def installWithInfo(dirpath, installlist):
shadowfile = os.path.join(itempath,".shadow")
if os.path.exists(shadowfile):
retcode = subprocess.call(["/bin/rm", shadowfile])
return restartflag
@@ -650,19 +650,19 @@ def processRemovals(removallist):
if not item.get('installed'):
# not installed, so skip it
continue
index += 1
name = item.get('display_name') or item.get('name') or \
item.get('manifestitem')
if munkicommon.munkistatusoutput:
munkistatus.message("Removing %s (%s of %s)..." %
munkistatus.message("Removing %s (%s of %s)..." %
(name, index, len(removallist)))
munkistatus.detail("")
munkistatus.percent(-1)
else:
munkicommon.display_status("Removing %s (%s of %s)..." %
(name, index, len(removallist)))
if 'uninstall_method' in item:
uninstallmethod = item['uninstall_method'].split(' ')
if uninstallmethod[0] == "removepackages":
@@ -681,13 +681,13 @@ def processRemovals(removallist):
else:
munkicommon.log("Uninstall of %s was "
"successful." % name)
elif uninstallmethod[0].startswith("Adobe"):
retcode = adobeutils.doAdobeRemoval(item)
elif uninstallmethod[0] == "remove_copied_items":
retcode = removeCopiedItems(item.get('items_to_remove'))
elif uninstallmethod[0] == "remove_app":
remove_app_info = item.get('remove_app_info', None)
if remove_app_info:
@@ -702,9 +702,9 @@ def processRemovals(removallist):
path_to_remove)
else:
munkicommon.display_error("Application removal "
"info missing from %s" %
"info missing from %s" %
name)
elif os.path.exists(uninstallmethod[0]) and \
os.access(uninstallmethod[0], os.X_OK):
# it's a script or program to uninstall
@@ -712,20 +712,20 @@ def processRemovals(removallist):
munkistatus.message("Running uninstall script "
"for %s..." % name)
munkistatus.detail("")
# set indeterminate progress bar
# set indeterminate progress bar
munkistatus.percent(-1)
if item.get('RestartAction') == "RequireRestart":
restartFlag = True
cmd = uninstallmethod
uninstalleroutput = []
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
proc = subprocess.Popen(cmd, shell=False, bufsize=1,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
while (proc.poll() == None):
while (proc.poll() == None):
msg = proc.stdout.readline().decode('UTF-8')
# save all uninstaller output in case there is
# an error so we can dump it to the log
@@ -736,7 +736,7 @@ def processRemovals(removallist):
pass
else:
print msg
retcode = proc.poll()
if retcode:
message = "Uninstall of %s failed." % name
@@ -756,17 +756,17 @@ def processRemovals(removallist):
else:
munkicommon.log("Uninstall of %s was "
"successful." % name)
if munkicommon.munkistatusoutput:
# clear indeterminate progress bar
# clear indeterminate progress bar
munkistatus.percent(0)
else:
munkicommon.log("Uninstall of %s failed because "
"there was no valid uninstall "
"there was no valid uninstall "
"method." % name)
retcode = -99
# record removal success/failure
if retcode == 0:
success_msg = "Removal of %s: SUCCESSFUL" % name
@@ -780,7 +780,7 @@ def processRemovals(removallist):
munkicommon.log(failure_msg, "Install.log")
munkicommon.report[
'RemovalResults'].append(failure_msg)
return restartFlag
@@ -804,17 +804,25 @@ def removeItemFromSelfServeUninstallList(itemname):
try:
FoundationPlist.writePlist(plist, selfservemanifest)
except FoundationPlist.FoundationPlistException:
pass
pass
def run():
'''Runs the install/removal session'''
def run(only_forced=False):
"""Runs the install/removal session.
Args:
only_forced: Boolean. If True, only do forced installs/removals.
"""
managedinstallbase = munkicommon.pref('ManagedInstallDir')
installdir = os.path.join(managedinstallbase , 'Cache')
removals_need_restart = installs_need_restart = False
munkicommon.log("### Beginning managed installer session ###")
if only_forced:
munkicommon.log("### Beginning forced installer session ###")
else:
munkicommon.log("### Beginning managed installer session ###")
installinfo = os.path.join(managedinstallbase, 'InstallInfo.plist')
if os.path.exists(installinfo):
try:
@@ -822,40 +830,51 @@ def run():
except FoundationPlist.NSPropertyListSerializationException:
print >> sys.stderr, "Invalid %s" % installinfo
return -1
# remove the install info file
# it's no longer valid once we start running
try:
os.unlink(installinfo)
except (OSError, IOError):
munkicommon.display_warning("Could not remove %s" % installinfo)
if (munkicommon.munkistatusoutput and
munkicommon.display_warning(
"Could not remove %s" % installinfo)
if (munkicommon.munkistatusoutput and
munkicommon.pref('SuppressStopButtonOnInstall')):
munkistatus.hideStopButton()
if "removals" in plist:
# filter list to items that need to be removed
removallist = [item for item in plist['removals']
if item.get('installed')]
if only_forced:
removallist = [item for item in plist['removals']
if item.get('installed') and \
item.get('forced_uninstall', False)]
else:
removallist = [item for item in plist['removals']
if item.get('installed')]
munkicommon.report['ItemsToRemove'] = removallist
if removallist:
if munkicommon.munkistatusoutput:
if len(removallist) == 1:
munkistatus.message("Removing 1 item...")
else:
munkistatus.message("Removing %i items..." %
munkistatus.message("Removing %i items..." %
len(removallist))
munkistatus.detail("")
# set indeterminate progress bar
# set indeterminate progress bar
munkistatus.percent(-1)
munkicommon.log("Processing removals")
removals_need_restart = processRemovals(removallist)
if "managed_installs" in plist:
if not munkicommon.stopRequested():
# filter list to items that need to be installed
installlist = [item for item in plist['managed_installs']
if item.get('installed') == False]
if only_forced:
installlist = [item for item in plist['managed_installs']
if not item.get('installed') and \
item.get('forced_install', False)]
else:
installlist = [item for item in plist['managed_installs']
if item.get('installed') == False]
munkicommon.report['ItemsToInstall'] = installlist
if installlist:
if munkicommon.munkistatusoutput:
@@ -865,17 +884,22 @@ def run():
munkistatus.message("Installing %i items..." %
len(installlist))
munkistatus.detail("")
# set indeterminate progress bar
# set indeterminate progress bar
munkistatus.percent(-1)
munkicommon.log("Processing installs")
installs_need_restart = installWithInfo(installdir,
installlist)
else:
munkicommon.log("No %s found." % installinfo)
munkicommon.log("### End managed installer session ###")
if not only_forced: # not need to log that no forced found.
munkicommon.log("No %s found." % installinfo)
if only_forced:
munkicommon.log("### End forced installer session ###")
else:
munkicommon.log("### End managed installer session ###")
munkicommon.savereport()
return (removals_need_restart or installs_need_restart)
+4 -3
View File
@@ -1335,6 +1335,8 @@ def processInstall(manifestitem, cataloglist, installinfo):
iteminfo['installer_item_size'] = item_pl.get('installer_item_size', 0)
iteminfo['installed_size'] = item_pl.get('installer_item_size',
iteminfo['installer_item_size'])
iteminfo['forced_install'] = item_pl.get('forced_install', False)
iteminfo['forced_uninstall'] = item_pl.get('forced_uninstall', False)
if not isInstalled(item_pl):
munkicommon.display_detail('Need to install %s' % manifestitemname)
@@ -1366,9 +1368,8 @@ def processInstall(manifestitem, cataloglist, installinfo):
'adobe_package_name',
'package_path',
'items_to_copy', # used w/ copy_from_dmg
'copy_local', # used w/ AdobeCS5 Updaters
'silent_install'] # just install without
# bothering the user
'copy_local'] # used w/ AdobeCS5 Updaters
for key in optional_keys:
if key in item_pl:
iteminfo[key] = item_pl[key]