docs: def install(name=None,
              refresh=False,
              fromrepo=None,
              skip_verify=False,
              debconf=None,
              pkgs=None,
              sources=None,
              reinstall=False,
              ignore_epoch=False,
              **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 apt-get/dpkg 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, add refresh=True to update the dpkg database.
  
      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 install packages from a
          software repository. To install a package file manually, use the
          "sources" option.
  
          32-bit packages can be installed on 64-bit systems by appending the
          architecture designation (``:i386``, etc.) to the end of the package
          name.
  
          CLI Example:
  
          .. code-block:: bash
  
              salt '*' pkg.install <package name>
  
      refresh
          Whether or not to refresh the package database before installing.
  
      cache_valid_time
  
          .. versionadded:: 2016.11.0
  
          Skip refreshing the package database if refresh has already occurred within
          <value> seconds
  
      fromrepo
          Specify a package repository to install from
          (e.g., ``apt-get -t unstable install somepackage``)
  
      skip_verify
          Skip the GPG verification check (e.g., ``--allow-unauthenticated``, or
          ``--force-bad-verify`` for install from package file).
  
      debconf
          Provide the path to a debconf answers file, processed before
          installation.
  
      version
          Install a specific version of the package, e.g. 1.2.3~0ubuntu0. Ignored
          if "pkgs" or "sources" is passed.
  
          .. versionchanged:: 2018.3.0
              version can now contain comparison operators (e.g. ``>1.2.3``,
              ``<=2.0``, etc.)
  
      reinstall : False
          Specifying reinstall=True will use ``apt-get install --reinstall``
          rather than simply ``apt-get install`` for requested packages that are
          already installed.
  
          If a version is specified with the requested package, then ``apt-get
          install --reinstall`` will only be used if the installed version
          matches the requested version.
  
          .. versionadded:: 2015.8.0
  
      ignore_epoch : False
          Only used when the version of a package is specified using a comparison
          operator (e.g. ``>4.1``). If set to ``True``, then the epoch will be
          ignored when comparing the currently-installed version to the desired
          version.
  
          .. versionadded:: 2018.3.0
  
      Multiple Package Installation Options:
  
      pkgs
          A list of packages to install from a software repository. Must be
          passed as a python list.
  
          CLI Example:
  
          .. code-block:: bash
  
              salt '*' pkg.install pkgs='["foo", "bar"]'
              salt '*' pkg.install pkgs='["foo", {"bar": "1.2.3-0ubuntu0"}]'
  
      sources
          A list of DEB 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.  Dependencies are automatically resolved
          and marked as auto-installed.
  
          32-bit packages can be installed on 64-bit systems by appending the
          architecture designation (``:i386``, etc.) to the end of the package
          name.
  
          .. versionchanged:: 2014.7.0
  
          CLI Example:
  
          .. code-block:: bash
  
              salt '*' pkg.install sources='[{"foo": "salt://foo.deb"},{"bar": "salt://bar.deb"}]'
  
      force_yes
          Passes ``--force-yes`` to the apt-get command.  Don't use this unless
          you know what you're doing.
  
          .. versionadded:: 0.17.4
  
      install_recommends
          Whether to install the packages marked as recommended.  Default is True.
  
          .. versionadded:: 2015.5.0
  
      only_upgrade
          Only upgrade the packages, if they are already installed. Default is False.
  
          .. versionadded:: 2015.5.0
  
      force_conf_new
          Always install the new version of any configuration files.
  
          .. versionadded:: 2015.8.0
  
      Returns a dict containing the new package names and versions::
  
          {'<package>': {'old': '<old-version>',
                         'new': '<new-version>'}}
      '''
      _refresh_db = False
      if salt.utils.data.is_true(refresh):
          _refresh_db = True
          if 'version' in kwargs and kwargs['version']:
              _refresh_db = False
              _latest_version = latest_version(name,
                                               refresh=False,
                                               show_installed=True)
              _version = kwargs.get('version')
              # If the versions don't match, refresh is True, otherwise no need
              # to refresh
              if not _latest_version == _version:
                  _refresh_db = True
  
          if pkgs:
              _refresh_db = False
              for pkg in pkgs:
                  if isinstance(pkg, dict):
                      _name = next(six.iterkeys(pkg))
                      _latest_version = latest_version(_name,
                                                       refresh=False,
                                                       show_installed=True)
                      _version = pkg[_name]
                      # If the versions don't match, refresh is True, otherwise
                      # no need to refresh
                      if not _latest_version == _version:
                          _refresh_db = True
                  else:
                      # No version specified, so refresh should be True
                      _refresh_db = True
  
      if debconf:
          __salt__['debconf.set_file'](debconf)
  
      try:
          pkg_params, pkg_type = __salt__['pkg_resource.parse_targets'](
              name, pkgs, sources, **kwargs
          )
      except MinionError as exc:
          raise CommandExecutionError(exc)
  
      # Support old "repo" argument
      repo = kwargs.get('repo', '')
      if not fromrepo and repo:
          fromrepo = repo
  
      if not pkg_params:
          return {}
  
      cmd_prefix = []
  
      old = list_pkgs()
      targets = []
      downgrade = []
      to_reinstall = {}
      errors = []
      if pkg_type == 'repository':
          pkg_params_items = list(six.iteritems(pkg_params))
          has_comparison = [x for x, y in pkg_params_items
                            if y is not None
                            and (y.startswith('<') or y.startswith('>'))]
          _available = list_repo_pkgs(*has_comparison, byrepo=False, **kwargs) \
              if has_comparison else {}
          # Build command prefix
          cmd_prefix.extend(['apt-get', '-q', '-y'])
          if kwargs.get('force_yes', False):
              cmd_prefix.append('--force-yes')
          if 'force_conf_new' in kwargs and kwargs['force_conf_new']:
              cmd_prefix.extend(['-o', 'DPkg::Options::=--force-confnew'])
          else:
              cmd_prefix.extend(['-o', 'DPkg::Options::=--force-confold'])
          cmd_prefix += ['-o', 'DPkg::Options::=--force-confdef']
          if 'install_recommends' in kwargs:
              if not kwargs['install_recommends']:
                  cmd_prefix.append('--no-install-recommends')
              else:
                  cmd_prefix.append('--install-recommends')
          if 'only_upgrade' in kwargs and kwargs['only_upgrade']:
              cmd_prefix.append('--only-upgrade')
          if skip_verify:
              cmd_prefix.append('--allow-unauthenticated')
          if fromrepo:
              cmd_prefix.extend(['-t', fromrepo])
          cmd_prefix.append('install')
      else:
          pkg_params_items = []
          for pkg_source in pkg_params:
              if 'lowpkg.bin_pkg_info' in __salt__:
                  deb_info = __salt__['lowpkg.bin_pkg_info'](pkg_source)
              else:
                  deb_info = None
              if deb_info is None:
                  log.error(
                      'pkg.install: Unable to get deb information for %s. '
                      'Version comparisons will be unavailable.', pkg_source
                  )
                  pkg_params_items.append([pkg_source])
              else:
                  pkg_params_items.append(
                      [deb_info['name'], pkg_source, deb_info['version']]
                  )
          # Build command prefix
          if 'force_conf_new' in kwargs and kwargs['force_conf_new']:
              cmd_prefix.extend(['dpkg', '-i', '--force-confnew'])
          else:
              cmd_prefix.extend(['dpkg', '-i', '--force-confold'])
          if skip_verify:
              cmd_prefix.append('--force-bad-verify')
          if HAS_APT:
              _resolve_deps(name, pkg_params, **kwargs)
  
      for pkg_item_list in pkg_params_items:
          if pkg_type == 'repository':
              pkgname, version_num = pkg_item_list
              if name \
                      and pkgs is None \
                      and kwargs.get('version') \
                      and len(pkg_params) == 1:
                  # Only use the 'version' param if 'name' was not specified as a
                  # comma-separated list
                  version_num = kwargs['version']
          else:
              try:
                  pkgname, pkgpath, version_num = pkg_item_list
              except ValueError:
                  pkgname = None
                  pkgpath = pkg_item_list[0]
                  version_num = None
  
          if version_num is None:
              if pkg_type == 'repository':
                  if reinstall and pkgname in old:
                      to_reinstall[pkgname] = pkgname
                  else:
                      targets.append(pkgname)
              else:
                  targets.append(pkgpath)
          else:
              # If we are installing a package file and not one from the repo,
              # and version_num is not None, then we can assume that pkgname is
              # not None, since the only way version_num is not None is if DEB
              # metadata parsing was successful.
              if pkg_type == 'repository':
                  # Remove leading equals sign(s) to keep from building a pkgstr
                  # with multiple equals (which would be invalid)
                  version_num = version_num.lstrip('=')
                  if pkgname in has_comparison:
                      candidates = _available.get(pkgname, [])
                      target = salt.utils.pkg.match_version(
                          version_num,
                          candidates,
                          cmp_func=version_cmp,
                          ignore_epoch=ignore_epoch,
                      )
                      if target is None:
                          errors.append(
                              'No version matching \'{0}{1}\' could be found '
                              '(available: {2})'.format(
                                  pkgname,
                                  version_num,
                                  ', '.join(candidates) if candidates else None
                              )
                          )
                          continue
                      else:
                          version_num = target
                  pkgstr = '{0}={1}'.format(pkgname, version_num)
              else:
                  pkgstr = pkgpath
  
              cver = old.get(pkgname, '')
              if reinstall and cver \
                      and salt.utils.versions.compare(ver1=version_num,
                                                      oper='==',
                                                      ver2=cver,
                                                      cmp_func=version_cmp):
                  to_reinstall[pkgname] = pkgstr
              elif not cver or salt.utils.versions.compare(ver1=version_num,
                                                           oper='>=',
                                                           ver2=cver,
                                                           cmp_func=version_cmp):
                  targets.append(pkgstr)
              else:
                  downgrade.append(pkgstr)
  
      if fromrepo and not sources:
          log.info('Targeting repo \'%s\'', fromrepo)
  
      cmds = []
      all_pkgs = []
      if targets:
          all_pkgs.extend(targets)
          cmd = copy.deepcopy(cmd_prefix)
          cmd.extend(targets)
          cmds.append(cmd)
  
      if downgrade:
          cmd = copy.deepcopy(cmd_prefix)
          if pkg_type == 'repository' and '--force-yes' not in cmd:
              # Downgrading requires --force-yes. Insert this before 'install'
              cmd.insert(-1, '--force-yes')
          cmd.extend(downgrade)
          cmds.append(cmd)
  
      if to_reinstall:
          all_pkgs.extend(to_reinstall)
          cmd = copy.deepcopy(cmd_prefix)
          if not sources:
              cmd.append('--reinstall')
          cmd.extend([x for x in six.itervalues(to_reinstall)])
          cmds.append(cmd)
  
      if not cmds:
          ret = {}
      else:
          cache_valid_time = kwargs.pop('cache_valid_time', 0)
          if _refresh_db:
              refresh_db(cache_valid_time)
  
          env = _parse_env(kwargs.get('env'))
          env.update(DPKG_ENV_VARS.copy())
  
          hold_pkgs = get_selections(state='hold').get('hold', [])
          # all_pkgs contains the argument to be passed to apt-get install, which
          # when a specific version is requested will be in the format
          # name=version.  Strip off the '=' if present so we can compare the
          # held package names against the pacakges we are trying to install.
          targeted_names = [x.split('=')[0] for x in all_pkgs]
          to_unhold = [x for x in hold_pkgs if x in targeted_names]
  
          if to_unhold:
              unhold(pkgs=to_unhold)
  
          for cmd in cmds:
              out = _call_apt(cmd)
              if out['retcode'] != 0 and out['stderr']:
                  errors.append(out['stderr'])
  
          __context__.pop('pkg.list_pkgs', None)
          new = list_pkgs()
          ret = salt.utils.data.compare_dicts(old, new)
  
          for pkgname in to_reinstall:
              if pkgname not in ret or pkgname in old:
                  ret.update({pkgname: {'old': old.get(pkgname, ''),
                                        'new': new.get(pkgname, '')}})
  
          if to_unhold:
              hold(pkgs=to_unhold)
  
      if errors:
          raise CommandExecutionError(
              'Problem encountered installing package(s)',
              info={'errors': errors, 'changes': ret}
          )
  
      return ret