1#!/usr/bin/python
2
3import os
4import logging
5import xml.etree.ElementTree as ET
6
7# Default INDI data directory
8INDI_DATA_DIR = "/usr/local/share/indi/"
9
10
11class DeviceDriver:
12    """Device driver container"""
13
14    def __init__(self, name, label, version, binary, family, skel=None, custom=False):
15        self.name = name
16        self.label = label
17        self.skeleton = skel
18        self.version = version
19        self.binary = binary
20        self.family = family
21        self.custom = custom
22
23
24class DriverCollection:
25    """A collection of drivers"""
26
27    def __init__(self, path=INDI_DATA_DIR):
28        self.path = path
29        self.drivers = []
30        self.files = []
31        self.parse_drivers()
32
33    def parse_drivers(self):
34        for fname in os.listdir(self.path):
35            # Skip Skeleton files
36            if fname.endswith('.xml') and '_sk' not in fname:
37                self.files.append(os.path.join(self.path, fname))
38
39        for fname in self.files:
40            try:
41                tree = ET.parse(fname)
42                root = tree.getroot()
43
44                for group in root.findall('devGroup'):
45                    family = group.attrib['group']
46
47                    for device in group.findall('device'):
48                        label = device.attrib['label']
49                        skel = device.attrib.get('skel', None)
50                        drv = device.find('driver')
51                        name = drv.attrib['name']
52                        binary = drv.text
53                        version = device.findtext('version', '0.0')
54
55                        skel_file = os.path.join(self.path, skel) if skel else None
56                        driver = DeviceDriver(name, label, version,
57                                              binary, family, skel_file)
58                        self.drivers.append(driver)
59
60            except KeyError as e:
61                logging.error("Error in file %s: attribute %s not found" % (fname, e))
62            except ET.ParseError as e:
63                logging.error("Error in file %s: %s" % (fname, e))
64
65        # Sort all drivers by label
66        self.drivers.sort(key=lambda x: x.label)
67
68    def parse_custom_drivers(self, drivers):
69        for custom in drivers:
70            driver = DeviceDriver(custom['name'], custom['label'], custom['version'], custom['exec'],
71                                  custom['family'], None, True)
72            self.drivers.append(driver)
73
74    def clear_custom_drivers(self):
75        self.drivers = list(filter(lambda driver: driver.custom is not True, self.drivers))
76
77    def by_label(self, label):
78        for driver in self.drivers:
79            if (driver.label == label):
80                return driver
81
82        return None
83
84    def by_name(self, name):
85        for driver in self.drivers:
86            if (driver.name == name):
87                return driver
88
89        return None
90
91    def by_binary(self, binary):
92        for driver in self.drivers:
93            if (driver.binary == binary):
94                return driver
95
96        return None
97
98    def get_families(self):
99        families = {}
100        for drv in self.drivers:
101            if drv.family in families:
102                families[drv.family].append(drv.label)
103            else:
104                families[drv.family] = [drv.label]
105        return families
106