Output tweaks; munkicommon.mountdmg() can now mount disk images containing End User License Agreements

This commit is contained in:
Greg Neagle
2012-01-04 13:54:04 -08:00
parent a0decf2625
commit ca03bb0325
4 changed files with 74 additions and 69 deletions
-31
View File
@@ -37,7 +37,6 @@ import os
import re
import optparse
from optparse import OptionValueError
#from distutils import version
import subprocess
from munkilib import munkicommon
@@ -45,29 +44,6 @@ from munkilib import FoundationPlist
from munkilib import adobeutils
def DMGhasSLA(dmgpath):
'''Returns true if dmg has a Software License Agreement.
These dmgs cannot be attached without user intervention'''
hasSLA = False
proc = subprocess.Popen(
['/usr/bin/hdiutil', 'imageinfo', dmgpath, '-plist'],
bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(pliststr, err) = proc.communicate()
if err:
print >> sys.stderr, ("hdiutil error %s with image %s."
% (err, dmgpath))
if pliststr:
try:
plist = FoundationPlist.readPlistFromString(pliststr)
properties = plist.get('Properties')
if properties:
hasSLA = properties.get('Software License Agreement', False)
except FoundationPlist.NSPropertyListSerializationException:
pass
return hasSLA
def getCatalogInfoFromDmg(dmgpath, options):
"""
* Mounts a disk image
@@ -76,13 +52,6 @@ def getCatalogInfoFromDmg(dmgpath, options):
To-do: handle multiple installer items on a disk image(?)
"""
if DMGhasSLA(dmgpath):
print >> sys.stderr, \
"%s has an attached Software License Agreement." % dmgpath
print >> sys.stderr, \
"It cannot be automatically mounted. You'll need to create a new dmg."
exit(-1)
cataloginfo = None
mountpoints = munkicommon.mountdmg(dmgpath)
if not mountpoints:
+3 -3
View File
@@ -578,9 +578,9 @@ class AppleUpdates(object):
return False
if not force_check and not self._IsForceCheckNeccessary(before_hash):
munkicommon.log('Skipping Apple Software Update check because '
'sucatalog is unchanged, installed Apple packages '
'are unchanged and we recently did a full check.')
munkicommon.display_info('Skipping Apple Software Update check '
'because sucatalog is unchanged, installed Apple packages are '
'unchanged and we recently did a full check.')
return False
product_ids = self.GetAvailableUpdateProductIDs()
+68 -16
View File
@@ -300,7 +300,7 @@ def concat_log_message(msg, *args):
warnings.warn(
'String format does not match concat args: %s' % (
str(sys.exc_info())))
return msg
return msg.rstrip()
def display_status_major(msg, *args):
@@ -328,7 +328,7 @@ def display_status_minor(msg, *args):
for verbose/non-verbose and munkistatus-style output.
"""
msg = concat_log_message(msg, *args)
log(msg)
log(u' ' + msg)
if munkistatusoutput:
munkistatus.detail(msg)
elif verbose > 0:
@@ -345,11 +345,11 @@ def display_info(msg, *args):
Not displayed in MunkiStatus.
"""
msg = concat_log_message(msg, *args)
log(msg)
log(u' ' + msg)
if munkistatusoutput:
pass
elif verbose > 0:
print msg.encode('UTF-8')
print ' %s' % msg.encode('UTF-8')
sys.stdout.flush()
@@ -364,10 +364,10 @@ def display_detail(msg, *args):
if munkistatusoutput:
pass
elif verbose > 1:
print msg.encode('UTF-8')
print ' %s' % msg.encode('UTF-8')
sys.stdout.flush()
if pref('LoggingLevel') > 0:
log(msg)
log(u' ' + msg)
def display_debug1(msg, *args):
@@ -379,7 +379,7 @@ def display_debug1(msg, *args):
if munkistatusoutput:
pass
elif verbose > 2:
print msg.encode('UTF-8')
print ' %s' % msg.encode('UTF-8')
sys.stdout.flush()
if pref('LoggingLevel') > 1:
log('DEBUG1: %s' % msg)
@@ -394,7 +394,7 @@ def display_debug2(msg, *args):
if munkistatusoutput:
pass
elif verbose > 3:
print msg.encode('UTF-8')
print ' %s' % msg.encode('UTF-8')
if pref('LoggingLevel') > 2:
log('DEBUG2: %s' % msg)
@@ -687,8 +687,50 @@ def osascript(osastring):
return str(out).decode('UTF-8').rstrip('\n')
def getFirstPlist(textString):
"""Gets the next plist from a text string that may contain one or
more text-style plists.
Returns a tuple - the first plist (if any) and the remaining
string after the plist"""
plistStart = textString.find('<?xml version')
if plistStart == -1:
# not found
return ("", textString)
plistEnd = textString.find('</plist>', plistStart + 13)
if plistEnd == -1:
# not found
return ("", textString)
# adjust end value
plistEnd = plistEnd + 8
return (textString[plistStart:plistEnd], textString[plistEnd:])
# dmg helpers
def DMGhasSLA(dmgpath):
'''Returns true if dmg has a Software License Agreement.
These dmgs cannot be attached without user intervention'''
hasSLA = False
proc = subprocess.Popen(
['/usr/bin/hdiutil', 'imageinfo', dmgpath, '-plist'],
bufsize=-1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, err) = proc.communicate()
if err:
print >> sys.stderr, (
'hdiutil error %s with image %s.' % (err, dmgpath))
(pliststr, out) = getFirstPlist(out)
if pliststr:
try:
plist = FoundationPlist.readPlistFromString(pliststr)
properties = plist.get('Properties')
if properties:
hasSLA = properties.get('Software License Agreement', False)
except FoundationPlist.NSPropertyListSerializationException:
pass
return hasSLA
def mountdmg(dmgpath, use_shadow=False):
"""
Attempts to mount the dmg at dmgpath
@@ -697,22 +739,32 @@ def mountdmg(dmgpath, use_shadow=False):
"""
mountpoints = []
dmgname = os.path.basename(dmgpath)
SLA_is_present = DMGhasSLA(dmgpath)
stdin = ''
if SLA_is_present:
stdin = 'Y\n'
cmd = ['/usr/bin/hdiutil', 'attach', dmgpath,
'-mountRandom', '/tmp', '-nobrowse', '-plist']
if use_shadow:
cmd.append('-shadow')
proc = subprocess.Popen(cmd,
bufsize=1, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(pliststr, err) = proc.communicate()
stderr=subprocess.PIPE, stdin=subprocess.PIPE)
(out, err) = proc.communicate(stdin)
if proc.returncode:
display_error('Error: "%s" while mounting %s.' % (err, dmgname))
display_error(
'Error: "%s" while mounting %s.' % (err.rstrip(), dmgname))
(pliststr, out) = getFirstPlist(out)
if pliststr:
plist = FoundationPlist.readPlistFromString(pliststr)
for entity in plist['system-entities']:
if 'mount-point' in entity:
mountpoints.append(entity['mount-point'])
try:
plist = FoundationPlist.readPlistFromString(pliststr)
for entity in plist.get('system-entities', []):
if 'mount-point' in entity:
mountpoints.append(entity['mount-point'])
except FoundationPlist.NSPropertyListSerializationException:
display_error(
'Bad plist string returned when mounting diskimage %s:\n%s'
% (dmgname, pliststr))
return mountpoints
+3 -19
View File
@@ -137,23 +137,6 @@ def addPackageids(catalogitems, pkgid_table):
pkgid_table[name].append(receipt['packageid'])
def getFirstPlist(textString):
"""Gets the next plist from a set of concatenated text-style plists.
Returns a tuple - the first plist (if any) and the remaining
string"""
plistStart = textString.find('<?xml version')
if plistStart == -1:
# not found
return ("", textString)
plistEnd = textString.find('</plist>', plistStart + 13)
if plistEnd == -1:
# not found
return ("", textString)
# adjust end value
plistEnd = plistEnd + 8
return (textString[plistStart:plistEnd], textString[plistEnd:])
INSTALLEDPKGS = {}
def getInstalledPackages():
"""Builds a dictionary of installed receipts and their version number"""
@@ -166,7 +149,7 @@ def getInstalledPackages():
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(out, unused_err) = proc.communicate()
while out:
(pliststr, out) = getFirstPlist(out)
(pliststr, out) = munkicommon.getFirstPlist(out)
if pliststr:
plist = FoundationPlist.readPlistFromString(pliststr)
if 'pkg-version' in plist and 'pkgid' in plist:
@@ -2525,8 +2508,9 @@ def check(client_id='', localmanifestpath=None):
munkicommon.log('')
if installcount:
munkicommon.display_info('')
munkicommon.display_info(
'\nThe following items will be installed or upgraded:')
'The following items will be installed or upgraded:')
for item in installinfo.get('managed_installs', []):
if item.get('installer_item'):
munkicommon.display_info(' + %s-%s' %