Handle optional items that are required by other optional items

This commit is contained in:
Greg Neagle
2014-03-16 10:57:00 -07:00
parent ae6eafbb53
commit 7643f03052
5 changed files with 90 additions and 27 deletions
@@ -161,9 +161,8 @@ def getEffectiveUpdateList():
mandatory_updates = [item for item in getUpdateList()
if (item['name'] in managed_update_names
or item.get('dependent_items')
or item['name'] not in optional_item_names)]
#optional_updates = [item for item in getUpdateList()
#if item not in mandatory_updates]
return mandatory_updates + optional_installs + optional_removals
@@ -182,6 +181,21 @@ def getMyItemsList():
return item_list
def dependentItems(this_name):
'''Returns the names of any (installed/to-be-installed) items that require this item'''
dependent_items = []
processed_installs = getInstallInfo().get('processed_installs', [])
optional_installs = getInstallInfo().get('optional_installs', [])
for name in processed_installs:
item_list = [item for item in optional_installs
if item['name'] == name]
for item in item_list:
if this_name in item.get('requires', []):
NSLog('%s requires %s' % (name, this_name))
dependent_items.append(name)
return dependent_items
class SelfService(object):
'''An object to wrap interactions with the SelfServiceManifest'''
def __init__(self):
@@ -253,9 +267,10 @@ class GenericItem(dict):
if not self.get('developer'):
self['developer'] = self.guess_developer()
if self.get('description'):
self['description'] = msulib.filtered_html(self['description'])
else:
self['description'] = ''
self['raw_description'] = msulib.filtered_html(self['description'])
del(self['description'])
if not 'raw_description' in self:
self['raw_description'] = ''
self['icon'] = self.getIcon()
self['due_date_sort'] = NSDate.distantFuture()
# sort items that need restart highest, then logout, then other
@@ -300,6 +315,9 @@ class GenericItem(dict):
else:
return attr
def description(self):
return self['raw_description']
def guess_developer(self):
'''Figure out something to use for the developer name'''
if self.get('apple_item'):
@@ -345,6 +363,9 @@ class GenericItem(dict):
'will-be-installed':
NSLocalizedString(u'Will be installed',
u'WillBeInstalledDisplayText').encode('utf-8'),
'must-be-installed':
NSLocalizedString(u'Will be installed',
u'InstallRequiredDisplayText').encode('utf-8'),
'will-be-removed':
NSLocalizedString(u'Will be removed',
u'WillBeRemovedDisplayText').encode('utf-8'),
@@ -380,6 +401,9 @@ class GenericItem(dict):
'will-be-installed':
NSLocalizedString(u'Cancel',
u'CancelInstallShortActionText').encode('utf-8'),
'must-be-installed':
NSLocalizedString(u'Required',
u'InstallRequiredShortActionText').encode('utf-8'),
'will-be-removed':
NSLocalizedString(u'Cancel',
u'CancelRemovalShortActionText').encode('utf-8'),
@@ -415,6 +439,9 @@ class GenericItem(dict):
'will-be-installed':
NSLocalizedString(u'Cancel install',
u'CancelInstallLongActionText').encode('utf-8'),
'must-be-installed':
NSLocalizedString(u'Install Required',
u'InstallRequiredLongActionText').encode('utf-8'),
'will-be-removed':
NSLocalizedString(u'Cancel removal',
u'CancelRemovalLongActionText').encode('utf-8'),
@@ -459,6 +486,10 @@ class GenericItem(dict):
'will-be-installed':
NSLocalizedString(u'Cancel install',
u'CancelInstallLongActionText').encode('utf-8'),
'must-be-installed':
NSLocalizedString(u'Required',
u'InstallRequiredLongActionText').encode('utf-8'),
}
return map.get(self['status'], self['status'])
@@ -504,6 +535,7 @@ class OptionalItem(GenericItem):
self['category'], self['developer'])
else:
self['category_and_developer'] = self['category']
self['dependent_items'] = dependentItems(self['name'])
if not self.get('status'):
self['status'] = self._get_status()
if self.get('installer_item_size'):
@@ -525,7 +557,9 @@ class OptionalItem(GenericItem):
status = 'will-be-removed'
else: # not in managed_uninstalls
if not self.get('needs_update'):
if self.get('uninstallable'):
if self['dependent_items']:
status = 'installed-not-removable'
elif self.get('uninstallable'):
status = 'installed'
else: # not uninstallable
status = 'installed-not-removable'
@@ -533,12 +567,16 @@ class OptionalItem(GenericItem):
if self['name'] in self_service_installs:
if self['name'] in managed_update_names:
status = 'update-must-be-installed'
elif self['dependent_items']:
status = 'update-must-be-installed'
else: # not in managed_updates
status = 'update-will-be-installed'
else: # not in managed_installs
status = 'update-available'
else: # not installed
if self['name'] in self_service_installs:
if self['dependent_items']:
status = 'must-be-installed'
elif self['name'] in self_service_installs:
status = 'will-be-installed'
else: # not in managed_installs
if ('licensed_seats_available' in self
@@ -554,6 +592,15 @@ class OptionalItem(GenericItem):
status = 'not-installed'
return status
def description(self):
_description = self['raw_description']
if self.get('dependent_items'):
# append dependency info to description:
_description += ('<br/><br/><strong>'
'This item is required by some other item that is installed '
'or is to be installed.</strong>')
return _description
def update_status(self):
# user clicked an item action button - update the item's state
managed_update_names = getInstallInfo().get('managed_updates', [])
@@ -595,15 +642,27 @@ class UpdateItem(GenericItem):
def __init__(self, *arg, **kw):
super(UpdateItem, self).__init__(*arg, **kw)
identifier = self.get('name', '') + '--' + self.get('version_to_install', '')
identifier = self.get('name', '') + '--version-' + self.get('version_to_install', '')
self['detail_link'] = ('updatedetail-%s.html'
% quote_plus(identifier))
if not self['status'] == 'will-be-removed':
force_install_after_date = self.get('force_install_after_date')
if force_install_after_date:
self['category'] = NSLocalizedString(
self['type'] = NSLocalizedString(
u'Critical Update', u'CriticalUpdateType')
self['due_date_sort'] = force_install_after_date
if not 'type' in self:
self['type'] = NSLocalizedString(u'Managed Update',
u'ManagedUpdateType').encode('utf-8')
self['hide_cancel_button'] = 'hidden'
self['dependent_items'] = dependentItems(self['name'])
def description(self):
_description = self['raw_description']
if not self['status'] == 'will-be-removed':
force_install_after_date = self.get('force_install_after_date')
if force_install_after_date:
# insert installation deadline into description
local_date = munki.discardTimeZoneFromDate(
force_install_after_date)
@@ -611,12 +670,14 @@ class UpdateItem(GenericItem):
forced_date_text = NSLocalizedString(
u'This item must be installed by %s',
u'ForcedDateWarning').encode('utf-8')
description = self['description']
# prepend deadline info to description.
self['description'] = (
'<span class="warning">' + forced_date_text % date_str
+ '</span><br><br>' + description)
if not 'category' in self:
self['category'] = NSLocalizedString(u'Managed Update',
u'ManagedUpdateType').encode('utf-8')
self['hide_cancel_button'] = 'hidden'
_description = ('<span class="warning">' + forced_date_text % date_str
+ '</span><br><br>' + _description)
if self.get('dependent_items'):
# append dependency info to description:
_description += ('<br/><br/><strong>'
'This item is required by some other item that is installed '
'or is to be installed.</strong>')
return _description
@@ -871,8 +871,11 @@ div.msu-button-inner {
padding-right: 10px;
}
div.msu-button-inner.installed-not-removable, div.msu-button-inner.no-licenses-available,
div.msu-button-inner.installing, div.msu-button-inner.removing {
div.msu-button-inner.installed-not-removable,
div.msu-button-inner.no-licenses-available,
div.msu-button-inner.installing,
div.msu-button-inner.must-be-installed,
div.msu-button-inner.removing {
background: none;
cursor: default;
pointer-events: none;
@@ -913,7 +916,8 @@ div.msu-button-inner.large {
-webkit-border-radius: 5px;
}
div.msu-button-inner.large.installed-not-removable,
div.msu-button-inner.large.installed-not-removable,
div.msu-button-inner.large.must-be-installed,
div.msu-button-inner.large.no-licenses-available,
div.msu-button-inner.large.installing,
div.msu-button-inner.large.removing {
@@ -953,6 +957,7 @@ div.msu-button-inner.install-updates {
div.msu-button-inner.install-updates.disabled,
div.msu-button-inner.install-updates.installed-not-removable,
div.msu-button-inner.install.must-be-installed,
div.msu-button-inner.install-updates.installing,
div.msu-button-inner.install-updates.removing {
background: none;
@@ -483,13 +483,10 @@ def build_updatedetail_page(identifier):
'''Build detail page for a non-optional update'''
items = MunkiItems.getUpdateList()
page_name = 'updatedetail-%s.html' % quote_plus(identifier)
name, sep, version = identifier.partition('--')
name, sep, version = identifier.partition('--version-')
for item in items:
if item['name'] == name and item['version_to_install'] == version:
if isinstance(item, MunkiItems.OptionalItem):
page = MunkiItems.OptionalItem(item)
else:
page = MunkiItems.UpdateItem(item)
page = MunkiItems.UpdateItem(item)
page['footer'] = msulib.getFooter()
msulib.addSidebarLabels(page)
force_install_after_date = item.get('force_install_after_date')
@@ -47,7 +47,7 @@
<h2>${informationLabel}</h2>
<div class="content">
<ul class="list">
<li><span class="label">${typeLabel} </span>${category}</li>
<li><span class="label">${typeLabel} </span>${type}</li>
<li><span class="label">${versionLabel} </span>${display_version}</li>
<li><span class="label">${sizeLabel} </span>${size}</li>
<li><span class="label">${developerLabel} </span>${developer}</li>
+1 -1
View File
@@ -1568,7 +1568,7 @@ def processOptionalInstall(manifestitem, cataloglist, installinfo):
iteminfo['description'] = item_pl.get('description', '')
iteminfo['version_to_install'] = item_pl.get('version', 'UNKNOWN')
iteminfo['display_name'] = item_pl.get('display_name', '')
for key in ['category', 'developer', 'icon_name']:
for key in ['category', 'developer', 'icon_name', 'requires']:
if key in item_pl:
iteminfo[key] = item_pl[key]
iteminfo['installed'] = someVersionInstalled(item_pl)