def processInstall(manifestitem, cataloglist, installinfo,
                   is_managed_update=False):
    """Processes a manifest item for install. Determines if it needs to be
    installed, and if so, if any items it is dependent on need to
    be installed first.  Installation detail is added to
    installinfo['managed_installs']
    Calls itself recursively as it processes dependencies.
    Returns a boolean; when processing dependencies, a false return
    will stop the installation of a dependent item
    """

    if munkicommon.munkistatusoutput:
        # reset progress indicator and detail field
        munkistatus.percent('-1')
        munkistatus.detail('')

    manifestitemname = os.path.split(manifestitem)[1]
    munkicommon.display_debug1(
        '* Processing manifest item %s for install', manifestitemname)
    (manifestitemname_withoutversion, includedversion) = nameAndVersion(
        manifestitemname)
    # have we processed this already?
    if manifestitemname in installinfo['processed_installs']:
        munkicommon.display_debug1(
            '%s has already been processed for install.', manifestitemname)
        return True
    elif (manifestitemname_withoutversion in
          installinfo['processed_uninstalls']):
        munkicommon.display_warning(
            'Will not process %s for install because it has already '
            'been processed for uninstall!', manifestitemname)
        return False

    item_pl = getItemDetail(manifestitem, cataloglist)
    if not item_pl:
        munkicommon.display_warning(
            'Could not process item %s for install. '
            'No pkginfo found in catalogs: %s ',
            manifestitem, ', '.join(cataloglist))
        return False
    elif is_managed_update:
        # we're processing this as a managed update, so don't
        # add it to the processed_installs list
        pass
    else:
        # we found it, so add it to our list of procssed installs
        # so we don't process it again in the future
        munkicommon.display_debug2('Adding %s to list of processed installs'
                                   % manifestitemname)
        installinfo['processed_installs'].append(manifestitemname)

    if isItemInInstallInfo(item_pl, installinfo['managed_installs'],
                           vers=item_pl.get('version')):
        # has this item already been added to the list of things to install?
        munkicommon.display_debug1(
            '%s is or will be installed.', manifestitemname)
        return True

    # check dependencies
    dependenciesMet = True

    # there are two kinds of dependencies/relationships.
    #
    # 'requires' are prerequistes:
    #  package A requires package B be installed first.
    #  if package A is removed, package B is unaffected.
    #  requires can be a one to many relationship.
    #
    #  The second type of relationship is 'update_for'.
    #  This signifies that that current package should be considered an update
    #  for the packages listed in the 'update_for' array. When processing a
    #  package, we look through the catalogs for other packages that declare
    #  they are updates for the current package and install them if needed.
    #  This can be a one-to-many relationship - one package can be an update
    #  for several other packages; for example, 'PhotoshopCS4update-11.0.1'
    #  could be an update for PhotoshopCS4 and for AdobeCS4DesignSuite.
    #
    #  When removing an item, any updates for that item are removed as well.

    if 'requires' in item_pl:
        dependencies = item_pl['requires']
        # fix things if 'requires' was specified as a string
        # instead of an array of strings
        if isinstance(dependencies, basestring):
            dependencies = [dependencies]
        for item in dependencies:
            munkicommon.display_detail(
                '%s-%s requires %s. Getting info on %s...'
                % (item_pl.get('name', manifestitemname),
                   item_pl.get('version', ''), item, item))
            success = processInstall(item, cataloglist, installinfo,
                                     is_managed_update=is_managed_update)
            if not success:
                dependenciesMet = False

    iteminfo = {}
    iteminfo['name'] = item_pl.get('name', '')
    iteminfo['display_name'] = item_pl.get('display_name', iteminfo['name'])
    iteminfo['description'] = item_pl.get('description', '')

    if not dependenciesMet:
        munkicommon.display_warning('Didn\'t attempt to install %s '
                                    'because could not resolve all '
                                    'dependencies.', manifestitemname)
        # add information to managed_installs so we have some feedback
        # to display in MSC.app
        iteminfo['installed'] = False
        iteminfo['note'] = ('Can\'t install %s because could not resolve all '
                            'dependencies.' % iteminfo['display_name'])
        installinfo['managed_installs'].append(iteminfo)
        return False

    installed_state = installedState(item_pl)
    if installed_state == 0:
        munkicommon.display_detail('Need to install %s', manifestitemname)
        iteminfo['installer_item_size'] = item_pl.get(
            'installer_item_size', 0)
        iteminfo['installed_size'] = item_pl.get(
            'installed_size', iteminfo['installer_item_size'])
        try:
            # Get a timestamp, then download the installer item.
            start = datetime.datetime.now()
            if item_pl.get('installer_type', 0) == 'nopkg':
                # Packageless install
                download_speed = 0
                filename = 'packageless_install'
            else:
                if download_installeritem(item_pl, installinfo):
                    # Record the download speed to the InstallResults output.
                    end = datetime.datetime.now()
                    download_seconds = (end - start).seconds
                    try:
                        if iteminfo['installer_item_size'] < 1024:
                            # ignore downloads under 1 MB or speeds will
                            # be skewed.
                            download_speed = 0
                        else:
                            # installer_item_size is KBytes, so divide
                            # by seconds.
                            download_speed = int(
                                iteminfo['installer_item_size'] /
                                download_seconds)
                    except (__HOLE__, ValueError, ZeroDivisionError):
                        download_speed = 0
                else:
                    # Item was already in cache; set download_speed to 0.
                    download_speed = 0

                filename = getInstallerItemBasename(
                    item_pl['installer_item_location'])

            iteminfo['download_kbytes_per_sec'] = download_speed
            if download_speed:
                munkicommon.display_detail(
                    '%s downloaded at %d KB/s', filename, download_speed)

            # required keys
            iteminfo['installer_item'] = filename
            iteminfo['installed'] = False
            iteminfo['version_to_install'] = item_pl.get('version', 'UNKNOWN')

            # we will ignore the unattended_install key if the item needs a
            # restart or logout...
            if (item_pl.get('unattended_install') or
                    item_pl.get('forced_install')):
                if item_pl.get('RestartAction', 'None') != 'None':
                    munkicommon.display_warning(
                        'Ignoring unattended_install key for %s '
                        'because RestartAction is %s.',
                        item_pl['name'], item_pl.get('RestartAction'))
                else:
                    iteminfo['unattended_install'] = True

            # optional keys
            optional_keys = ['suppress_bundle_relocation',
                             'installer_choices_xml',
                             'installer_environment',
                             'adobe_install_info',
                             'RestartAction',
                             'installer_type',
                             'adobe_package_name',
                             'package_path',
                             'blocking_applications',
                             'installs',
                             'requires',
                             'update_for',
                             'payloads',
                             'preinstall_script',
                             'postinstall_script',
                             'items_to_copy',  # used w/ copy_from_dmg
                             'copy_local',     # used w/ AdobeCS5 Updaters
                             'force_install_after_date',
                             'apple_item',
                             'category',
                             'developer',
                             'icon_name',
                             'PayloadIdentifier',
                             'icon_hash',
                             'OnDemand']

            for key in optional_keys:
                if key in item_pl:
                    iteminfo[key] = item_pl[key]

            if not 'apple_item' in iteminfo:
                # admin did not explicitly mark this item; let's determine if
                # it's from Apple
                if isAppleItem(item_pl):
                    munkicommon.log(
                        'Marking %s as apple_item - this will block '
                        'Apple SUS updates' % iteminfo['name'])
                    iteminfo['apple_item'] = True

            installinfo['managed_installs'].append(iteminfo)

            update_list = []
            # (manifestitemname_withoutversion, includedversion) =
            # nameAndVersion(manifestitemname)
            if includedversion:
                # a specific version was specified in the manifest
                # so look only for updates for this specific version
                update_list = lookForUpdatesForVersion(
                    manifestitemname_withoutversion,
                    includedversion, cataloglist)
            else:
                # didn't specify a specific version, so
                # now look for all updates for this item
                update_list = lookForUpdates(manifestitemname_withoutversion,
                                             cataloglist)
                # now append any updates specifically
                # for the version to be installed
                update_list.extend(
                    lookForUpdatesForVersion(
                        manifestitemname_withoutversion,
                        iteminfo['version_to_install'],
                        cataloglist))

            for update_item in update_list:
                # call processInstall recursively so we get the
                # latest version and dependencies
                dummy_result = processInstall(
                    update_item, cataloglist, installinfo,
                    is_managed_update=is_managed_update)
            return True
        except fetch.PackageVerificationError:
            munkicommon.display_warning(
                'Can\'t install %s because the integrity check failed.',
                manifestitem)
            iteminfo['installed'] = False
            iteminfo['note'] = 'Integrity check failed'
            installinfo['managed_installs'].append(iteminfo)
            return False
        except fetch.GurlDownloadError, errmsg:
            munkicommon.display_warning(
                'Download of %s failed: %s', manifestitem, errmsg)
            iteminfo['installed'] = False
            iteminfo['note'] = 'Download failed (%s)' % errmsg
            installinfo['managed_installs'].append(iteminfo)
            return False
        except fetch.MunkiDownloadError, errmsg:
            munkicommon.display_warning(
                'Can\'t install %s because: %s', manifestitemname, errmsg)
            iteminfo['installed'] = False
            iteminfo['note'] = '%s' % errmsg
            installinfo['managed_installs'].append(iteminfo)
            return False
    else:
        iteminfo['installed'] = True
        # record installed size for reporting
        iteminfo['installed_size'] = item_pl.get(
            'installed_size', item_pl.get('installer_item_size', 0))
        if installed_state == 1:
            # just use the version from the pkginfo
            iteminfo['installed_version'] = item_pl['version']
        else:
            # might be newer; attempt to figure out the version
            installed_version = getInstalledVersion(item_pl)
            if installed_version == "UNKNOWN":
                installed_version = '(newer than %s)' % item_pl['version']
            iteminfo['installed_version'] = installed_version
        installinfo['managed_installs'].append(iteminfo)
        # remove included version number if any
        (name, includedversion) = nameAndVersion(manifestitemname)
        munkicommon.display_detail('%s version %s (or newer) is already '
                                   'installed.', name, item_pl['version'])
        update_list = []
        if not includedversion:
            # no specific version is specified;
            # the item is already installed;
            # now look for updates for this item
            update_list = lookForUpdates(name, cataloglist)
            # and also any for this specific version
            installed_version = iteminfo['installed_version']
            if not installed_version.startswith('(newer than '):
                update_list.extend(
                    lookForUpdatesForVersion(
                        name, installed_version, cataloglist))
        elif compareVersions(
                includedversion, iteminfo['installed_version']) == 1:
            # manifest specifies a specific version
            # if that's what's installed, look for any updates
            # specific to this version
            update_list = lookForUpdatesForVersion(
                manifestitemname_withoutversion, includedversion, cataloglist)
        # if we have any updates, process them
        for update_item in update_list:
            # call processInstall recursively so we get updates
            # and any dependencies
            dummy_result = processInstall(
                update_item, cataloglist, installinfo,
                is_managed_update=is_managed_update)

        return True
dataset/ETHPy150Open munki/munki/code/client/munkilib/updatecheck.py/processInstall