# -*- coding: utf-8 -*-
'''
Remote package support using ``pkg_add(1)``

.. important::
    If you feel that Salt should be using this module to manage packages on a
    minion, and it is using a different module (or gives an error similar to
    *'pkg.install' is not available*), see :ref:`here
    <module-provider-override>`.

.. warning::

    This module has been completely rewritten. Up to and including version
    0.17.0, it supported ``pkg_add(1)``, but checked for the existence of a
    pkgng local database and, if found,  would provide some of pkgng's
    functionality. The rewrite of this module has removed all pkgng support,
    and moved it to the :mod:`pkgng <salt.modules.pkgng>` execution module. For
    versions <= 0.17.0, the documentation here should not be considered
    accurate. If your Minion is running one of these versions, then the
    documentation for this module can be viewed using the :mod:`sys.doc
    <salt.modules.sys.doc>` function:

    .. code-block:: bash

        salt bsdminion sys.doc pkg


This module acts as the default package provider for FreeBSD 9 and older. If
you need to use pkgng on a FreeBSD 9 system, you will need to override the
``pkg`` provider by setting the :conf_minion:`providers` parameter in your
Minion config file, in order to use pkgng.

.. code-block:: yaml

    providers:
      pkg: pkgng

More information on pkgng support can be found in the documentation for the
:mod:`pkgng <salt.modules.pkgng>` module.

This module will respect the ``PACKAGEROOT`` and ``PACKAGESITE`` environment
variables, if set, but these values can also be overridden in several ways:

1. :strong:`Salt configuration parameters.` The configuration parameters
   ``freebsdpkg.PACKAGEROOT`` and ``freebsdpkg.PACKAGESITE`` are recognized.
   These config parameters are looked up using :mod:`config.get
   <salt.modules.config.get>` and can thus be specified in the Master config
   file, Grains, Pillar, or in the Minion config file. Example:

   .. code-block:: yaml

        freebsdpkg.PACKAGEROOT: ftp://ftp.freebsd.org/
        freebsdpkg.PACKAGESITE: ftp://ftp.freebsd.org/pub/FreeBSD/ports/ia64/packages-9-stable/Latest/

2. :strong:`CLI arguments.` Both the ``packageroot`` (used interchangeably with
   ``fromrepo`` for API compatibility) and ``packagesite`` CLI arguments are
   recognized, and override their config counterparts from section 1 above.

   .. code-block:: bash

        salt -G 'os:FreeBSD' pkg.install zsh fromrepo=ftp://ftp2.freebsd.org/
        salt -G 'os:FreeBSD' pkg.install zsh packageroot=ftp://ftp2.freebsd.org/
        salt -G 'os:FreeBSD' pkg.install zsh packagesite=ftp://ftp2.freebsd.org/pub/FreeBSD/ports/ia64/packages-9-stable/Latest/

    .. note::

        These arguments can also be passed through in states:

        .. code-block:: yaml

            zsh:
              pkg.installed:
                - fromrepo: ftp://ftp2.freebsd.org/
'''
from __future__ import absolute_import

# Import python libs
import copy
import logging
import re

# Import salt libs
import salt.utils
from salt.exceptions import CommandExecutionError, MinionError
import salt.ext.six as six

log = logging.getLogger(__name__)

# Define the module's virtual name
__virtualname__ = 'pkg'


def __virtual__():
    '''
    Load as 'pkg' on FreeBSD versions less than 10.
    Don't load on FreeBSD 9 when the config option
    ``providers:pkg`` is set to 'pkgng'.
    '''
    if __grains__['os'] == 'FreeBSD' and float(__grains__['osrelease']) < 10:
        providers = {}
        if 'providers' in __opts__:
            providers = __opts__['providers']
        if providers and 'pkg' in providers and providers['pkg'] == 'pkgng':
            log.debug('Configuration option \'providers:pkg\' is set to '
                    '\'pkgng\', won\'t load old provider \'freebsdpkg\'.')
            return (False, 'The freebsdpkg execution module cannot be loaded: the configuration option \'providers:pkg\' is set to \'pkgng\'')
        return __virtualname__
    return (False, 'The freebsdpkg execution module cannot be loaded: either the os is not FreeBSD or the version of FreeBSD is >= 10.')


def _get_repo_options(fromrepo=None, packagesite=None):
    '''
    Return a list of tuples to seed the "env" list, which is used to set
    environment variables for any pkg_add commands that are spawned.

    If ``fromrepo`` or ``packagesite`` are None, then their corresponding
    config parameter will be looked up with config.get.

    If both ``fromrepo`` and ``packagesite`` are None, and neither
    freebsdpkg.PACKAGEROOT nor freebsdpkg.PACKAGESITE are specified, then an
    empty list is returned, and it is assumed that the system defaults (or
    environment variables) will be used.
    '''
    root = fromrepo if fromrepo is not None \
        else __salt__['config.get']('freebsdpkg.PACKAGEROOT', None)
    site = packagesite if packagesite is not None \
        else __salt__['config.get']('freebsdpkg.PACKAGESITE', None)
    ret = {}
    if root is not None:
        ret['PACKAGEROOT'] = root
    if site is not None:
        ret['PACKAGESITE'] = site
    return ret


def _match(names):
    '''
    Since pkg_delete requires the full "pkgname-version" string, this function
    will attempt to match the package name with its version. Returns a list of
    partial matches and package names that match the "pkgname-version" string
    required by pkg_delete, and a list of errors encountered.
    '''
    pkgs = list_pkgs(versions_as_list=True)