LIRC libraries
Linux Infrared Remote Control
Loading...
Searching...
No Matches
database.py
1''' Read-only configuration database. '''
2
7
8
34
35
37
38
39import glob
40import os
41import os.path
42import subprocess
43import sys
44
45try:
46 import yaml
47 try:
48 from yaml import CLoader as Loader, CDumper as Dumper
49 except ImportError:
50 from yaml import Loader, Dumper
51except ImportError:
52 _YAML_MSG = '''
53"Cannot import the yaml library. Please install the python3
54yaml package, on many distributions known as python3-PyYAML. It is also
55available as a pypi package at https://pypi.python.org/pypi/PyYAML.'''
56 print(_YAML_MSG)
57 sys.exit(1)
58
59import config
60
61
62def _here(path):
63 ''' Return path added to current dir for __file__. '''
64 return os.path.join(os.path.dirname(os.path.abspath(__file__)), path)
65
66
67def _load_kerneldrivers(configdir):
68 ''' Parse the kerneldrivers.yaml file, discard unavailable
69 drivers.
70 '''
71
72 with open(os.path.join(configdir, "kernel-drivers.yaml")) as f:
73 cf = yaml.load(f.read(), Loader = Loader)
74 drivers = cf['drivers'].copy()
75 for driver in cf['drivers']:
76 if driver == 'default':
77 continue
78 with open('/dev/null', 'w') as f:
79 try:
80 subprocess.check_output([config.MODINFO, driver],
81 stderr=f)
82 except subprocess.CalledProcessError:
83 del drivers[driver]
84 return drivers
85
86
87class ItemLookupError(Exception):
88 """A lookup failed, either too namy or no matches found. """
89 pass
90
91
92class Config(object):
93 ''' The configuration selected, and it's sources. '''
94 # pylint: disable=too-many-instance-attributes
95
96 def __init__(self, cf=None):
97 self.device = None
98 self.driver = {}
99 self.config = {}
100 self.modinit = ""
101 self.modprobe = ""
102 self.lircd_conf = ""
103 self.lircmd_conf = ""
104 self.label = ""
105 if cf:
106 for key, value in cf.items():
107 setattr(self, key, value)
108
109 @property
110 def note(self):
111 ''' The possible note to display when selected. '''
112 if 'note' in self.config:
113 return self.config['note']
114 else:
115 return None
116
117
118class Database(object):
119 ''' Reflects the *.yaml files in the configs/ directory. '''
120
121 def __init__(self, path=None, yamlpath=None):
122
123 devel_path = _here('../../configs')
124 installed_path = os.path.join(config.DATADIR, 'lirc','configs')
125 if path and os.path.exists(path):
126 configdir = path
127 elif path:
128 raise FileNotFoundError(path)
129 elif os.path.exists(devel_path):
130 configdir = devel_path
131 elif os.path.exists(installed_path):
132 configdir = installed_path
133 else:
134 raise FileNotFoundError(devel_path + ':' + installed_path)
135 if not yamlpath:
136 yamlpath = configdir
137 db = {}
138 with open(os.path.join(yamlpath, "confs_by_driver.yaml")) as f:
139 cf = yaml.load(f.read(), Loader = Loader)
140 db['lircd_by_driver'] = cf['lircd_by_driver'].copy()
141 db['lircmd_by_driver'] = cf['lircmd_by_driver'].copy()
142
143 db['kernel-drivers'] = _load_kerneldrivers(configdir)
144 db['drivers'] = db['kernel-drivers'].copy()
145 with open(os.path.join(yamlpath, "drivers.yaml")) as f:
146 cf = yaml.load(f.read(), Loader = Loader)
147 db['drivers'].update(cf['drivers'].copy())
148 for key, d in db['drivers'].items():
149 d['id'] = key
150 hint = d['device_hint']
151 if not hint:
152 continue
153 hint = hint.strip()
154 if hint.startswith('"') and hint.endswith('"'):
155 hint = hint[1:-1]
156 hint = hint.replace(r'\"', "@$#!")
157 hint = hint.replace('"', '')
158 hint = hint.replace("@$#!", '"')
159 hint = hint.replace("\\\\", "\\")
160 d['device_hint'] = hint
161
162 configs = {}
163 for path in glob.glob(configdir + '/*.conf'):
164 with open(path) as f:
165 cf = yaml.load(f.read(), Loader = Loader)
166 configs[cf['config']['id']] = cf['config']
167 db['configs'] = configs
168 self.db = db
169
170 @property
171 def kernel_drivers(self):
172 ''' The kernel-drivers dictionary, drivers.yaml + kernel-drivers.yaml.
173 '''
174 return self.db['kernel-drivers']
175
176 @property
177 def drivers(self):
178 ''' The drivers dictionary, drivers.yaml + kernel-drivers.yaml. '''
179 return self.db['drivers']
180
181 @property
182 def configs(self):
183 ''' Return dict of parsed config/*.conf files, keyd by id. '''
184 return self.db['configs']
185
186 def remotes_by_driver(self, driver):
187 ''' Return the list of remotes suggested for a given driver. '''
188 if isinstance(driver, dict):
189 driver = driver['id']
190 try:
191 return self.db['lircd_by_driver'][driver]
192 except KeyError:
193 return []
194
195 def lircmd_by_driver(self, driver):
196 ''' Return list of lircmd.conf file for given driver or None. '''
197 if isinstance(driver, dict):
198 driver = driver['id']
199 try:
200 return self.db['lircmd_by_driver'][driver]
201 except KeyError:
202 return []
203
204 def driver_by_remote(self, remote):
205 ''' Return the driver (possibly None) suggested for a remote. '''
206 for driver, files in self.db['lircd_by_driver'].items():
207 if remote in files:
208 return self.db['drivers'][driver]
209 return None
210
211 def find_config(self, key, value):
212 ''' Return item (a config) in configs where config[key] == value. '''
213 found = [c for c in self.db['configs'].values()
214 if key in c and c[key] == value]
215 if len(found) > 1:
216 raise ItemLookupError(
217 "find_config: Too many matches for %s, %s): " % (key, value)
218 + ', '.join([c['id'] for c in found]))
219 elif not found:
220 raise ItemLookupError(
221 "find_config: Nothing found for %s, %s): " % (key, value))
222 found = dict(found[0])
223 if 'device_hint' not in found:
224 try:
225 found['device_hint'] = \
226 self.db['drivers'][found['driver']]['device_hint']
227 except KeyError:
228 found['device_hint'] = \
229 self.db['kernel-drivers'][found['driver']]['device_hint']
230 return found
231
232
234
235# vim: set expandtab ts=4 sw=4: