mirror of
https://github.com/munki/munki.git
synced 2026-04-22 20:48:36 -05:00
Output tweaks; munkicommon.mountdmg() can now mount disk images containing End User License Agreements
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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' %
|
||||
|
||||
Reference in New Issue
Block a user