CrontabParser raises an exception on syntax error in config file
[dbuscron] / dbuscron / parser.py
1 from __future__ import with_statement
2 import re
3 from dbuscron.bus import DbusBus
4
5 def product(*args):
6     if args:
7         head, tail = args[0], args[1:]
8         for h in head:
9             for t in product(*tail):
10                 yield (h,) + t
11
12     else:
13         yield ()
14
15 class CrontabParserError(SyntaxError):
16     pass
17
18 class CrontabParser(object):
19     __fields_sep = re.compile(r'\s+')
20     __envvar_sep = re.compile(r'\s*=\s*')
21     __fields = [
22             'bus_',
23             'type_',
24             'sender_',
25             'interface_',
26             'path_',
27             'member_',
28             'destination_',
29             'args_',
30             #'command'
31             ]
32
33     def __init__(self, fname):
34         self.__bus = DbusBus()
35         self.__filename = fname
36         self.__environ = dict()
37
38     @property
39     def environ(self):
40         return self.__environ
41
42     def __iter__(self):
43         # bus type sender interface path member destination args command
44         lineno = 0
45         with open(self.__filename) as f:
46             for line in f:
47                 lineno += 1
48                 line = line.strip()
49
50                 if not line or line.startswith('#'):
51                     continue
52
53                 parts = self.__fields_sep.split(line, 8)
54                 if len(parts) < 9:
55                     parts = self.__envvar_sep(line, 1)
56                     if len(parts) == 2:
57                         self.__environ[parts[0]] = parts[1]
58                         continue
59
60                     raise SyntaxError('Unexpected number of records at line #%d.' % (lineno))
61
62                 rule = [('s','S'), ('signal','method_call','method_return','error'), (None,), (None,), (None,), (None,), (None,), (None,)]
63
64                 for p in range(0, 8):
65                     if parts[p] != '*':
66                         rule[p] = parts[p].split(',')
67
68                 command = parts[8]
69  
70                 for r in product(*rule):
71                     r = list(r)
72                     if r[0] == 'S':
73                         r[0] = self.__bus.system
74                     elif r[0] == 's':
75                         r[0] = self.__bus.session
76                     else:
77                         continue
78         
79                     if r[7]:
80                         r[7] = r[7].split(';')
81
82                     ruled = dict()
83                     for i, f in enumerate(self.__fields):
84                         ruled[f] = r[i]
85                     yield ruled, command
86
87 class OptionsParser(dict):
88     def __init__(self, opts, args=None):
89         super(OptionsParser, self).__init__()
90
91         if args is None:
92             import sys
93             args = sys.argv[1:]
94
95         from getopt import getopt
96         go, _ = getopt(args, opts)
97
98         for o, v in go:
99             k = o.strip('-')
100             withval = k+':' in opts
101
102             if self.has_key(k):
103                 if withval:
104                     if isinstance(self[k], list):
105                         self[k].append(v)
106                     else:
107                         self[k] = [ self[k], v ]
108
109                 else:
110                     self[k] += 1
111
112             else:
113                 self[k] = v if withval else 1
114
115     def __getitem__(self, k):
116         if not self.has_key(k):
117             return False
118         return super(OptionsParser, self).__getitem__(k)
119
120     def __getattr__(self, k):
121         return self[k]
122