# pyinfra
# File: pyinfra/facts/apt.py
# Desc: facts for the apt package manager & deb files

from __future__ import unicode_literals

import re

import six

from pyinfra.api import FactBase

from .util.packaging import parse_packages


def parse_apt_repo(name):
    regex = r'^(deb(?:-src)?)\s+([^\s]+)\s+([a-z-]+)\s+([a-z-\s]*)$'

    matches = re.match(regex, name)
    if matches:
        return {
            'type': matches.group(1),
            'url': matches.group(2),
            'distribution': matches.group(3),
            'components': set(matches.group(4).split()),
        }


class AptSources(FactBase):
    '''
    Returns a list of installed apt sources:

    .. code:: python

        {
            'type': 'deb',
            'url': 'http://archive.ubuntu.org',
            'distribution': 'trusty',
            'components', ['main', 'multiverse']
        },
        ...
    '''

    command = 'cat /etc/apt/sources.list /etc/apt/sources.list.d/*.list'
    default = list

    def process(self, output):
        repos = []

        for line in output:
            repo = parse_apt_repo(line)
            if repo:
                repos.append(repo)

        return repos


class DebPackages(FactBase):
    '''
    Returns a dict of installed dpkg packages:

    .. code:: python

        'package_name': 'version',
        ...
    '''

    command = 'dpkg -l'
    regex = r'^[a-z]+\s+([a-zA-Z0-9\+\-\.]+):?[a-zA-Z0-9]*\s+([a-zA-Z0-9:~\.\-\+]+).+$'
    default = dict

    def process(self, output):
        return parse_packages(self.regex, output)


class DebPackage(FactBase):
    '''
    Returns information on a .deb file.
    '''

    _regexes = {
        'name': r'^Package: ([a-zA-Z0-9\-]+)$',
        'version': r'^Version: ([0-9\.\-]+)$',
    }

    def command(self, name):
        return 'dpkg -I {0}'.format(name)

    def process(self, output):
        data = {}

        for line in output:
            for key, regex in six.iteritems(self._regexes):
                matches = re.match(regex, line)
                if matches:
                    value = matches.group(1)
                    data[key] = value
                    break

        return data

@@ -285,16 +285,45 @@
 :-src)?)
+(?:%5Cs+%5C%5B(%5Ba-zA-Z0-9=%5Cs%5D+)%5C%5D)?
 %5Cs+(%5B%5E%5Cs
@@ -391,23 +391,28 @@
 , name)%0A
+%0A
     if 
+not 
 matches:
@@ -426,23 +426,358 @@
   return
+%0A%0A    # Parse any options%0A    options =
  %7B
+%7D
 %0A    
+options_string = matches.group(2)%0A    if options_string:%0A        for option in options_string.split():%0A            key, value = option.split('=', 1)%0A            if ',' in value:%0A                value = value.split(',')%0A%0A            options%5Bkey%5D = value%0A%0A    return %7B%0A        'options': options,%0A
         
@@ -802,20 +802,16 @@
 oup(1),%0A
-    
         
@@ -835,16 +835,12 @@
 oup(
-2
+3
 ),%0A
-    
     
@@ -869,32 +869,28 @@
 tches.group(
-3
+4
 ),%0A
-    
         'com
@@ -917,17 +917,17 @@
 s.group(
-4
+5
 ).split(
@@ -930,20 +930,16 @@
 lit()),%0A
-    
     %7D%0A%0A%0A

Improve apt repo parsing: handle `[options=values]`.