+# encoding: utf-8
from __future__ import with_statement
+import os
import re
from dbuscron.bus import DbusBus
+def unescape_():
+ h = '[0-9A-Fa-f]'
+ r = re.compile(r'\\x('+h+r'{2})|\\u('+h+'{4})')
+
+ def unescape(value):
+ if not (value and
+ (r'\x' in value or r'\u' in value)):
+ return value
+
+ return r.sub(
+ lambda m: chr(int(m.group(1), 16))
+ if m.group(1) is not None else
+ unichr(int(m.group(2), 16))
+ .encode('utf-8'),\
+ value)
+ return unescape
+unescape = unescape_()
+
def product(*args):
if args:
head, tail = args[0], args[1:]
SyntaxError.__init__(self, msg)
-class CrontabParser(object):
+def CrontabParser(*filenames):
+ for filename in filenames:
+ if not os.path.exists(filename):
+ continue
+
+ if os.path.isfile(filename):
+ parser_class = FileParser
+
+ elif os.path.isdir(filename):
+ parser_class = DirectoryParser
+
+ else:
+ raise SystemError("I can parse only directories or simple files.")
+
+ return parser_class(filename)
+
+ raise SystemError("Can't find any config file or directory.")
+
+class FileParser(object):
__fields_sep = re.compile(r'\s+')
__envvar_sep = re.compile(r'\s*=\s*')
__fields_chk = {
'bus_' : None,
- 'type_' : ('signal','method_call','method_return','error'),
+ 'type_' : ('signal', 'method_call', 'method_return', 'error'),
'sender_' : None,
'interface_' : re.compile(r'^[a-zA-Z][a-zA-Z0-9_.]+$'),
'path_' : re.compile(r'^/[a-zA-Z0-9_/]+$'),
]
def __init__(self, fname):
- self.__bus = DbusBus()
- self.__filename = fname
- self.__environ = dict()
+ self._bus = DbusBus()
+ self._filename = fname
+ self._environ = dict()
@property
def environ(self):
- return self.__environ
+ return self._environ
- def __iter__(self):
+ @property
+ def filename(self):
+ return self._filename
+
+ def _iterate_file(self, filename):
# bus type sender interface path member destination args command
lineno = 0
- with open(self.__filename) as f:
+ with open(filename) as f:
for line in f:
lineno += 1
line = line.strip()
parts = self.__fields_sep.split(line, 8)
if len(parts) < 9:
- parts = self.__envvar_sep(line, 1)
+ parts = self.__envvar_sep.split(line, 1)
if len(parts) == 2:
self.__environ[parts[0]] = parts[1]
continue
raise CrontabParserError('Unexpected number of records', lineno)
- rule = [('s','S'), self.__fields_chk['type_'], (None,), (None,), (None,), (None,), (None,), (None,)]
+ rule = [('s', 'S'), self.__fields_chk['type_'], (None,), (None,), (None,), (None,), (None,), (None,)]
for p in range(0, 8):
if parts[p] != '*':
rule[p] = parts[p].split(',')
command = parts[8]
-
+
for r in product(*rule):
r = list(r)
if r[0] == 'S':
- r[0] = self.__bus.system
+ r[0] = self._bus.system
elif r[0] == 's':
- r[0] = self.__bus.session
+ r[0] = self._bus.session
else:
raise CrontabParserError('Unexpected bus value', lineno, expected=('S', 's', '*'))
if r[7]:
- r[7] = r[7].split(';')
+ r[7] = map(unescape, r[7].split(';'))
ruled = dict()
for i, f in enumerate(self.__fields):
- if self.__fields_chk[f]:
+ if r[i] is not None and self.__fields_chk[f]:
if isinstance(self.__fields_chk[f], tuple):
if r[i] not in self.__fields_chk[f]:
raise CrontabParserError('Unexpected %s value' % (f.strip('_')), lineno,
yield ruled, command
-class OptionsParser(dict):
- def __init__(self, opts, args=None):
- super(OptionsParser, self).__init__()
+ def __iter__(self):
+ return self._iterate_file(self._filename)
- if args is None:
- import sys
- args = sys.argv[1:]
+class DirectoryParser(FileParser):
- from getopt import getopt
- go, _ = getopt(args, opts)
+ def __init__(self, dirname, recursive=False):
+ self.__recursive = recursive
+ super(DirectoryParser, self).__init__(dirname)
- for o, v in go:
- k = o.strip('-')
- withval = k+':' in opts
+ def _dirwalker_plain(self):
+ for i in os.listdir(self._filename):
+ f = os.path.join(self._filename, i)
+ if os.path.isfile(f):
+ yield f
- if self.has_key(k):
- if withval:
- if isinstance(self[k], list):
- self[k].append(v)
- else:
- self[k] = [ self[k], v ]
+ def _dirwalker_recursive(self):
+ for r, d, f in os.walk(self._filename):
+ for i in f:
+ yield os.path.join(r, i)
+
+ def __iter__(self):
+ if self.__recursive:
+ dirwalker = self._dirwalker_recursive
+ else:
+ dirwalker = self._dirwalker_plain
- else:
- self[k] += 1
+ for fname in dirwalker():
+ for item in self._iterate_file(fname):
+ yield item
- else:
- self[k] = v if withval else 1
+def OptionsParser(args=None, help=u'', **opts):
- def __getitem__(self, k):
- if not self.has_key(k):
- return False
- return super(OptionsParser, self).__getitem__(k)
+ from optparse import OptionParser
+ import dbuscron
+ parser = OptionParser(usage=help, version="%prog " + dbuscron.__version__)
+ for opt, desc in opts.iteritems():
+ names = desc.pop('names')
+ desc['dest'] = opt
+ parser.add_option(*names, **desc)
- def __getattr__(self, k):
- return self[k]
+ return parser.parse_args(args)[0]