def downloadAvailableUpdates(): '''Downloads the available Apple updates using our local filtered sucatalog. Returns True if successful, False otherwise.''' msg = "Downloading available Apple Software Updates..." if munkicommon.munkistatusoutput: munkistatus.message(msg) munkistatus.detail("") munkistatus.percent(-1) munkicommon.log(msg) else: munkicommon.display_status(msg) # use our filtered local catalog catalogpath = os.path.join(swupdCacheDir(), 'content/catalogs/local_download.sucatalog') if not os.path.exists(catalogpath): munkicommon.display_error( 'Missing local Software Update catalog at %s', catalogpath) return False catalogURL = 'file://localhost' + urllib2.quote(catalogpath) # get the OS version osvers = int(os.uname()[2].split('.')[0]) if osvers == 9: retcode = leopardDownloadAvailableUpdates(catalogURL) else: retcode = run_softwareupdate(['--CatalogURL', catalogURL, '-d', '-a']) if retcode: # there was an error munkicommon.display_error("softwareupdate error: %s" % retcode) return False return True
def getpathstoremove(pkgkeylist): """ Queries our database for paths to remove. """ pkgkeys = tuple(pkgkeylist) # open connection and cursor to our database conn = sqlite3.connect(packagedb) curs = conn.cursor() # set up some subqueries: # all the paths that are referred to by the selected packages: if len(pkgkeys) > 1: in_selected_packages = \ "select distinct path_key from pkgs_paths where pkg_key in %s" % \ str(pkgkeys) else: in_selected_packages = \ "select distinct path_key from pkgs_paths where pkg_key = %s" % \ str(pkgkeys[0]) # all the paths that are referred to by every package # except the selected packages: if len(pkgkeys) > 1: not_in_other_packages = \ "select distinct path_key from pkgs_paths where pkg_key not in %s" % \ str(pkgkeys) else: not_in_other_packages = \ "select distinct path_key from pkgs_paths where pkg_key != %s" % \ str(pkgkeys[0]) # every path that is used by the selected packages and no other packages: combined_query = \ "select path from paths where " + \ "(path_key in (%s) and path_key not in (%s))" % \ (in_selected_packages, not_in_other_packages) munkicommon.display_status_minor( 'Determining which filesystem items to remove') if munkicommon.munkistatusoutput: munkistatus.percent(-1) curs.execute(combined_query) results = curs.fetchall() curs.close() conn.close() removalpaths = [] for item in results: removalpaths.append(item[0]) return removalpaths
def getAvailableUpdates(): '''Returns a list of product IDs of available Apple updates''' msg = "Checking for available Apple Software Updates..." if munkicommon.munkistatusoutput: munkistatus.message(msg) munkistatus.detail("") munkistatus.percent(-1) munkicommon.log(msg) else: munkicommon.display_status(msg) applicable_updates = os.path.join(swupdCacheDir(), 'ApplicableUpdates.plist') if os.path.exists(applicable_updates): # remove any old item try: os.unlink(applicable_updates) except (OSError, IOError): pass # use our locally-cached Apple catalog catalogpath = os.path.join(swupdCacheDir(), 'content/catalogs/apple_index.sucatalog') catalogURL = 'file://localhost' + urllib2.quote(catalogpath) su_options = ['--CatalogURL', catalogURL, '-l', '-f', applicable_updates] retcode = run_softwareupdate(su_options) if retcode: # there was an error osvers = int(os.uname()[2].split('.')[0]) if osvers == 9: # always a non-zero retcode on Leopard pass else: munkicommon.display_error("softwareupdate error: %s" % retcode) return [] if os.path.exists(applicable_updates): try: updatelist = FoundationPlist.readPlist(applicable_updates) if updatelist: results_array = updatelist.get('phaseResultsArray', []) return [ item['productKey'] for item in results_array if 'productKey' in item ] except FoundationPlist.NSPropertyListSerializationException: return [] return []
def getAvailableUpdates(): '''Returns a list of product IDs of available Apple updates''' msg = "Checking for available Apple Software Updates..." if munkicommon.munkistatusoutput: munkistatus.message(msg) munkistatus.detail("") munkistatus.percent(-1) munkicommon.log(msg) else: munkicommon.display_status(msg) applicable_updates = os.path.join(swupdCacheDir(), 'ApplicableUpdates.plist') if os.path.exists(applicable_updates): # remove any old item try: os.unlink(applicable_updates) except (OSError, IOError): pass # use our locally-cached Apple catalog catalogpath = os.path.join(swupdCacheDir(), 'content/catalogs/apple_index.sucatalog') catalogURL = 'file://localhost' + urllib2.quote(catalogpath) su_options = ['--CatalogURL', catalogURL, '-l', '-f', applicable_updates] retcode = run_softwareupdate(su_options) if retcode: # there was an error osvers = int(os.uname()[2].split('.')[0]) if osvers == 9: # always a non-zero retcode on Leopard pass else: munkicommon.display_error("softwareupdate error: %s" % retcode) return [] if os.path.exists(applicable_updates): try: updatelist = FoundationPlist.readPlist(applicable_updates) if updatelist: results_array = updatelist.get('phaseResultsArray', []) return [item['productKey'] for item in results_array if 'productKey' in item] except FoundationPlist.NSPropertyListSerializationException: return [] return []
def installAppleUpdates(): '''Uses /usr/sbin/softwareupdate to install previously downloaded updates. Returns True if a restart is needed after install, False otherwise.''' msg = "Installing available Apple Software Updates..." if munkicommon.munkistatusoutput: munkistatus.message(msg) munkistatus.detail("") munkistatus.percent(-1) munkicommon.log(msg) else: munkicommon.display_status(msg) restartneeded = restartNeeded() # use our filtered local catalog catalogpath = os.path.join(swupdCacheDir(), 'content/catalogs/local_install.sucatalog') if not os.path.exists(catalogpath): munkicommon.display_error( 'Missing local Software Update catalog at %s', catalogpath) # didn't do anything, so no restart needed return False installlist = getSoftwareUpdateInfo() installresults = {'installed': [], 'download': []} catalogURL = 'file://localhost' + urllib2.quote(catalogpath) retcode = run_softwareupdate(['--CatalogURL', catalogURL, '-i', '-a'], mode='install', results=installresults) if not 'InstallResults' in munkicommon.report: munkicommon.report['InstallResults'] = [] for item in installlist: rep = {} rep['name'] = item.get('display_name') rep['version'] = item.get('version_to_install', '') rep['applesus'] = True rep['productKey'] = item.get('productKey', '') message = "Apple Software Update install of %s-%s: %s" if rep['name'] in installresults['installed']: rep['status'] = 0 install_status = 'SUCCESSFUL' elif rep['name'] in installresults['download']: rep['status'] = -1 install_status = 'FAILED due to missing package.' munkicommon.display_warning( 'Apple update %s, %s failed. A sub-package was missing ' 'on disk at time of install.' % (rep['name'], rep['productKey'])) else: rep['status'] = -2 install_status = 'FAILED for unknown reason' munkicommon.display_warning( 'Apple update %s, %s failed to install. No record of ' 'success or failure.' % (rep['name'], rep['productKey'])) munkicommon.report['InstallResults'].append(rep) log_msg = message % (rep['name'], rep['version'], install_status) munkicommon.log(log_msg, "Install.log") if retcode: # there was an error munkicommon.display_error("softwareupdate error: %s" % retcode) # clean up our now stale local cache cachedir = os.path.join(swupdCacheDir()) if os.path.exists(cachedir): unused_retcode = subprocess.call(['/bin/rm', '-rf', cachedir]) # remove the now invalid appleUpdatesFile try: os.unlink(appleUpdatesFile()) except OSError: pass # Also clear our pref value for last check date. We may have # just installed an update which is a pre-req for some other update. # Let's check again soon. munkicommon.set_pref('LastAppleSoftwareUpdateCheck', None) return restartneeded
except ValueError: percent = -1 munkicommon.display_percent_done(percent, 100) elif output.startswith('Software Update Tool'): # don't display this pass elif output.startswith('Copyright 2'): # don't display this pass elif output.startswith('Installing ') and mode == 'install': item = output[11:] if item: if munkicommon.munkistatusoutput: munkistatus.message(output) munkistatus.detail("") munkistatus.percent(-1) munkicommon.log(output) else: munkicommon.display_status(output) elif output.startswith('Installed '): # 10.6 / 10.7. Successful install of package name. if mode == 'install': munkicommon.display_status(output) results['installed'].append(output[10:]) else: pass # don't display. # softwareupdate logging "Installed" at the end of a # successful download-only session is odd. elif output.startswith('Done '): # 10.5. Successful install of package name.
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_minor( '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): fileobj = open(appListFile, mode='r', buffering=1) if fileobj: for line in fileobj.readlines(): appList.append(line) fileobj.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_minor('Searching for %s' % appname) # first look in the obvious place pathname = os.path.join("/Applications/Adobe Acrobat 9 Pro", appname) if os.path.exists(pathname): item = {} item['path'] = pathname candidates = [item] else: # use system_profiler to search for the app candidates = [item for item in munkicommon.getAppData() if item['path'].endswith('/' + appname)] # 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_minor('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) 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() if retcode != 0: munkicommon.display_error("Error patching %s: %s" % (appname, retcode)) break else: munkicommon.display_status_minor( 'Patching %s complete.' % appname) munkicommon.display_status_minor('Done.') if munkicommon.munkistatusoutput: munkistatus.percent(100) munkicommon.unmountdmg(installroot) return retcode
def runAdobeInstallTool(cmd, number_of_payloads=0, killAdobeAIR=False): '''An abstraction of the tasks for running Adobe Setup, AdobeUberInstaller, AdobeUberUninstaller, AdobeDeploymentManager, etc''' if munkicommon.munkistatusoutput and not number_of_payloads: # indeterminate progress bar munkistatus.percent(-1) proc = subprocess.Popen(cmd, shell=False, bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) old_payload_completed_count = 0 payloadname = "" while (proc.poll() == None): time.sleep(1) (payload_completed_count, payloadname) = \ getAdobeInstallProgressInfo(old_payload_completed_count, payloadname) if payload_completed_count > old_payload_completed_count: old_payload_completed_count = payload_completed_count if payloadname: payloadinfo = " - " + payloadname else: payloadinfo = "" if number_of_payloads: munkicommon.display_status_minor( 'Completed payload %s of %s%s' % (payload_completed_count, number_of_payloads, payloadinfo)) else: munkicommon.display_status_minor('Completed payload %s%s' % (payload_completed_count, payloadinfo)) if munkicommon.munkistatusoutput: munkistatus.percent(getPercent(payload_completed_count, number_of_payloads)) # Adobe AIR Installer workaround/hack # CSx installs at the loginwindow hang when Adobe AIR is installed. # So we check for this and kill the process. Ugly. # Hopefully we can disable this in the future. if killAdobeAIR: if (not munkicommon.getconsoleuser() or munkicommon.getconsoleuser() == u"loginwindow"): # we're at the loginwindow. killStupidProcesses() # run of tool completed retcode = proc.poll() #check output for errors output = proc.stdout.readlines() for line in output: line = line.rstrip("\n") if line.startswith("Error"): munkicommon.display_error(line) if line.startswith("Exit Code:"): if retcode == 0: try: retcode = int(line[11:]) except (ValueError, TypeError): retcode = -1 if retcode != 0 and retcode != 8: munkicommon.display_error("Adobe Setup error: %s: %s" % (retcode, adobeSetupError(retcode))) else: if munkicommon.munkistatusoutput: munkistatus.percent(100) munkicommon.display_status_minor('Done.') return retcode
def installAppleUpdates(): '''Uses /usr/sbin/softwareupdate to install previously downloaded updates. Returns True if a restart is needed after install, False otherwise.''' msg = "Installing available Apple Software Updates..." if munkicommon.munkistatusoutput: munkistatus.message(msg) munkistatus.detail("") munkistatus.percent(-1) munkicommon.log(msg) else: munkicommon.display_status(msg) restartneeded = restartNeeded() # use our filtered local catalog catalogpath = os.path.join(swupdCacheDir(), 'content/catalogs/local_install.sucatalog') if not os.path.exists(catalogpath): munkicommon.display_error( 'Missing local Software Update catalog at %s', catalogpath) # didn't do anything, so no restart needed return False installlist = getSoftwareUpdateInfo() installresults = {'installed':[], 'download':[]} catalogURL = 'file://localhost' + urllib2.quote(catalogpath) retcode = run_softwareupdate(['--CatalogURL', catalogURL, '-i', '-a'], mode='install', results=installresults) if not 'InstallResults' in munkicommon.report: munkicommon.report['InstallResults'] = [] for item in installlist: rep = {} rep['name'] = item.get('display_name') rep['version'] = item.get('version_to_install', '') rep['applesus'] = True rep['productKey'] = item.get('productKey', '') message = "Apple Software Update install of %s-%s: %s" if rep['name'] in installresults['installed']: rep['status'] = 0 install_status = 'SUCCESSFUL' elif rep['name'] in installresults['download']: rep['status'] = -1 install_status = 'FAILED due to missing package.' munkicommon.display_warning( 'Apple update %s, %s failed. A sub-package was missing ' 'on disk at time of install.' % (rep['name'], rep['productKey'])) else: rep['status'] = -2 install_status = 'FAILED for unknown reason' munkicommon.display_warning( 'Apple update %s, %s failed to install. No record of ' 'success or failure.' % (rep['name'],rep['productKey'])) munkicommon.report['InstallResults'].append(rep) log_msg = message % (rep['name'], rep['version'], install_status) munkicommon.log(log_msg, "Install.log") if retcode: # there was an error munkicommon.display_error("softwareupdate error: %s" % retcode) # clean up our now stale local cache cachedir = os.path.join(swupdCacheDir()) if os.path.exists(cachedir): unused_retcode = subprocess.call(['/bin/rm', '-rf', cachedir]) # remove the now invalid appleUpdatesFile try: os.unlink(appleUpdatesFile()) except OSError: pass # Also clear our pref value for last check date. We may have # just installed an update which is a pre-req for some other update. # Let's check again soon. munkicommon.set_pref('LastAppleSoftwareUpdateCheck', None) return restartneeded