.. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
        On minions running systemd>=205, `systemd-run(1)`_ is now used to
        isolate commands which modify installed packages from the
        ``salt-minion`` daemon's control group. This is done to keep systemd
        from killing any emerge commands spawned by Salt when the
        ``salt-minion`` service is restarted. (see ``KillMode`` in the
        `systemd.kill(5)`_ manpage for more information). If desired, usage of
        `systemd-run(1)`_ can be suppressed by setting a :mod:`config option
        <salt.modules.config.get>` called ``systemd.scope``, with a value of
        ``False`` (no quotes).

    .. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
    .. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html

    Install the passed package(s), add refresh=True to sync the portage tree
    before package is installed.

    name
        The name of the package to be installed. Note that this parameter is
        ignored if either "pkgs" or "sources" is passed. Additionally, please
        note that this option can only be used to emerge a package from the
        portage tree. To install a tbz2 package manually, use the "sources"
        option described below.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install <package name>

    refresh
        Whether or not to sync the portage tree before installing.

    version
        Install a specific version of the package, e.g. 1.0.9-r1. Ignored
        if "pkgs" or "sources" is passed.

    slot
        Similar to version, but specifies a valid slot to be installed. It
        will install the latest available version in the specified slot.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sys-devel/gcc slot='4.4'

    fromrepo
        Similar to slot, but specifies the repository from the package will be
        installed. It will install the latest available version in the
        specified repository.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install salt fromrepo='gentoo'

    uses
        Similar to slot, but specifies a list of use flag.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sys-devel/gcc uses='["nptl","-nossp"]'


    Multiple Package Installation Options:

    pkgs
        A list of packages to install from the portage tree. Must be passed as
        a python list.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install pkgs='["foo","bar","~category/package:slot::repository[use]"]'

    sources
        A list of tbz2 packages to install. Must be passed as a list of dicts,
        with the keys being package names, and the values being the source URI
        or local path to the package.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sources='[{"foo": "salt://foo.tbz2"},{"bar": "salt://bar.tbz2"}]'
    binhost
        has two options try and force.
        try - tells emerge to try and install the package from a configured binhost.
        force - forces emerge to install the package from a binhost otherwise it fails out.

    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}

def install(name=None,
            refresh=False,
            pkgs=None,
            sources=None,
            slot=None,
            fromrepo=None,
            uses=None,
            binhost=None,
            **kwargs):
    '''
    .. versionchanged:: 2015.8.12,2016.3.3,2016.11.0
        On minions running systemd>=205, `systemd-run(1)`_ is now used to
        isolate commands which modify installed packages from the
        ``salt-minion`` daemon's control group. This is done to keep systemd
        from killing any emerge commands spawned by Salt when the
        ``salt-minion`` service is restarted. (see ``KillMode`` in the
        `systemd.kill(5)`_ manpage for more information). If desired, usage of
        `systemd-run(1)`_ can be suppressed by setting a :mod:`config option
        <salt.modules.config.get>` called ``systemd.scope``, with a value of
        ``False`` (no quotes).

    .. _`systemd-run(1)`: https://www.freedesktop.org/software/systemd/man/systemd-run.html
    .. _`systemd.kill(5)`: https://www.freedesktop.org/software/systemd/man/systemd.kill.html

    Install the passed package(s), add refresh=True to sync the portage tree
    before package is installed.

    name
        The name of the package to be installed. Note that this parameter is
        ignored if either "pkgs" or "sources" is passed. Additionally, please
        note that this option can only be used to emerge a package from the
        portage tree. To install a tbz2 package manually, use the "sources"
        option described below.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install <package name>

    refresh
        Whether or not to sync the portage tree before installing.

    version
        Install a specific version of the package, e.g. 1.0.9-r1. Ignored
        if "pkgs" or "sources" is passed.

    slot
        Similar to version, but specifies a valid slot to be installed. It
        will install the latest available version in the specified slot.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sys-devel/gcc slot='4.4'

    fromrepo
        Similar to slot, but specifies the repository from the package will be
        installed. It will install the latest available version in the
        specified repository.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install salt fromrepo='gentoo'

    uses
        Similar to slot, but specifies a list of use flag.
        Ignored if "pkgs" or "sources" or "version" is passed.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sys-devel/gcc uses='["nptl","-nossp"]'


    Multiple Package Installation Options:

    pkgs
        A list of packages to install from the portage tree. Must be passed as
        a python list.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install pkgs='["foo","bar","~category/package:slot::repository[use]"]'

    sources
        A list of tbz2 packages to install. Must be passed as a list of dicts,
        with the keys being package names, and the values being the source URI
        or local path to the package.

        CLI Example:

        .. code-block:: bash

            salt '*' pkg.install sources='[{"foo": "salt://foo.tbz2"},{"bar": "salt://bar.tbz2"}]'
    binhost
        has two options try and force.
        try - tells emerge to try and install the package from a configured binhost.
        force - forces emerge to install the package from a binhost otherwise it fails out.

    Returns a dict containing the new package names and versions::

        {'<package>': {'old': '<old-version>',
                       'new': '<new-version>'}}
    '''
    log.debug('Called modules.pkg.install: %s',
        {
            'name': name,
            'refresh': refresh,
            'pkgs': pkgs,
            'sources': sources,
            'kwargs': kwargs,
            'binhost': binhost,
        }
    )
    if salt.utils.data.is_true(refresh):
        refresh_db()

    try:
        pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](
            name, pkgs, sources, **kwargs
        )
    except MinionError as exc:
        raise CommandExecutionError(exc)

    # Handle version kwarg for a single package target
    if pkgs is None and sources is None:
        version_num = kwargs.get('version')
        if not version_num:
            version_num = ''
            if slot is not None:
                version_num += ':{0}'.format(slot)
            if fromrepo is not None:
                version_num += '::{0}'.format(fromrepo)
            if uses is not None:
                version_num += '[{0}]'.format(','.join(uses))
            pkg_params = {name: version_num}

    if not pkg_params:
        return {}
    elif pkg_type == 'file':
        emerge_opts = ['tbz2file']
    else:
        emerge_opts = []

    if binhost == 'try':
        bin_opts = ['-g']
    elif binhost == 'force':
        bin_opts = ['-G']
    else:
        bin_opts = []

    changes = {}

    if pkg_type == 'repository':
        targets = list()
        for param, version_num in six.iteritems(pkg_params):
            original_param = param
            param = _p_to_cp(param)
            if param is None:
                raise portage.dep.InvalidAtom(original_param)

            if version_num is None:
                targets.append(param)
            else:
                keyword = None

                match = re.match('^(~)?([<>])?(=)?([^<>=]*)$', version_num)
                if match:
                    keyword, gt_lt, eq, verstr = match.groups()
                    prefix = gt_lt or ''
                    prefix += eq or ''
                    # If no prefix characters were supplied and verstr contains a version, use '='
                    if verstr and verstr[0] != ':' and verstr[0] != '[':
                        prefix = prefix or '='
                        target = '{0}{1}-{2}'.format(prefix, param, verstr)
                    else:
                        target = '{0}{1}'.format(param, verstr)
                else:
                    target = '{0}'.format(param)

                if '[' in target:
                    old = __salt__['portage_config.get_flags_from_package_conf']('use', target)
                    __salt__['portage_config.append_use_flags'](target)
                    new = __salt__['portage_config.get_flags_from_package_conf']('use', target)
                    if old != new:
                        changes[param + '-USE'] = {'old': old, 'new': new}
                    target = target[:target.rfind('[')]

                if keyword is not None:
                    __salt__['portage_config.append_to_package_conf']('accept_keywords',
                                                                        target,
                                                                        ['~ARCH'])
                    changes[param + '-ACCEPT_KEYWORD'] = {'old': '', 'new': '~ARCH'}

                if not changes:
                    inst_v = version(param)

                    # Prevent latest_version from calling refresh_db. Either we
                    # just called it or we were asked not to.
                    if latest_version(param, refresh=False) == inst_v:
                        all_uses = __salt__['portage_config.get_cleared_flags'](param)
                        if _flags_changed(*all_uses):
                            changes[param] = {'version': inst_v,
                                              'old': {'use': all_uses[0]},
                                              'new': {'use': all_uses[1]}}
                targets.append(target)
    else:
        targets = pkg_params

    cmd = []
    if salt.utils.systemd.has_scope(__context__) \
            and __salt__['config.get']('systemd.scope', True):
        cmd.extend(['systemd-run', '--scope'])
    cmd.extend(['emerge', '--ask', 'n', '--quiet'])
    cmd.extend(bin_opts)
    cmd.extend(emerge_opts)
    cmd.extend(targets)

    old = list_pkgs()
    call = __salt__['cmd.run_all'](cmd,
                                   output_loglevel='trace',
                                   python_shell=False)
    if call['retcode'] != 0:
        needed_changes = _process_emerge_err(call['stdout'], call['stderr'])
    else:
        needed_changes = []

    __context__.pop('pkg.list_pkgs', None)
    new = list_pkgs()
    changes.update(salt.utils.data.compare_dicts(old, new))

    if needed_changes:
        raise CommandExecutionError(
            'Error occurred installing package(s)',
            info={'needed changes': needed_changes, 'changes': changes}
        )

    return changes