Below is the file 'yowie.py' from this revision. You can also download the file.
#!/usr/bin/env python2.4 import config import pipes import time import csv import sha import sys import os class DeviceProxy: def __init__(self, device_name, device_config): self.config = device_config self.device_name = device_name for required in ('driver', 'zone'): if not self.config.has_key(required): raise Exception('Cannot initialize device %s: required config item %s unspecified.' % (device_name, required)) class Table: def __init__(self, table_name, column_file): self.table_name = table_name def load_columns(): return csv.reader(open(column_file)).next() self.columns = load_columns() self.hash = sha.new(str(self.columns)).hexdigest() class TableIO: def __init__(self, implement, filename): self.implement, self.filename = implement, filename def read_last_values(self): if os.access(self.filename, os.R_OK): for row in csv.reader(open(self.filename)): yield row def write(self, rows, rowlen): fd = open(self.filename, "w") writer = csv.writer(fd) for row in rows: if len(row) != rowlen: raise Exception("Row has length %d (must be %d)" % (len(row), rowlen)) writer.writerow(row) export_funcs = {} def export_to_drivers(f): export_funcs[f.__name__] = f return f @export_to_drivers def now(): return int(time.time()) @export_to_drivers def log(*args): if len(args) == 1: args = args[0] else: args = str(args) print "%s : %s" % (time.ctime(), args) @export_to_drivers def simple_has_table(supported): return lambda a : supported.has_key(a) @export_to_drivers def simple_get_table(supported): def __get_table(*args, **kwargs): return supported[args[0]](*args, **kwargs) return __get_table def monotone_commit(): def s(*args, **kwargs): return os.system(*args, **kwargs) >> 8 os.chdir(config.data_path) pq = pipes.quote if not os.access(config.mtn_database, os.R_OK): rv = s(config.mtn + ' --db=%s db init' % pq(config.mtn_database)) if rv != 0: raise Exception("Unable to initialise monotone database: %s" % config.mtn_database) base_cmd = '%s --db=%s --branch=%s ' % (config.mtn, pq(config.mtn_database), pq(config.mtn_branch)) if __name__ == '__main__': def init_drivers(): rv = {} orig_path = sys.path if hasattr(config, 'plugin_path'): sys.path.insert(0, config.plugin_path) for name in config.drivers: mod = __import__('%s' % name, None, None, None) for e in export_funcs: setattr(mod, e, export_funcs[e]) export = {'has_table' : None, 'get_table' : None} setattr(mod, 'export', export) if hasattr(mod, 'init'): mod.init() rv[name] = export sys.path = orig_path return rv def init_devices(): rv = {} for name in config.devices: p = DeviceProxy(name, config.devices[name]) rv[name] = p return rv def init_tables(): rv = {} for table_file in config.tables: table_name = os.path.split(table_file)[-1].rsplit('.', 1)[0] table = Table(table_name, table_file) rv[table_name] = table return rv def ensure_datadir(device): datadir = os.path.join(config.data_path, device) if not os.access(datadir, os.R_OK): os.mkdir(datadir) return datadir def get_filename(device, table): return os.path.join(config.data_path, device, table) + '.csv' def update_device(device): log("updating: " + device) export = drivers[devices[device].config['driver']] has_table, get_table = export.get('has_table'), export.get('get_table') if not has_table or not get_table: log("device does not implement basic functionality: " + device) return ensure_datadir(device) for table in tables: if not has_table(table): continue log("updating table %s on: %s" % (table, device)) tio = TableIO(tables[table], get_filename(device, table)) rowlen = len(tables[table].columns) tio.write(get_table(table, tio, devices[device]), rowlen) drivers = init_drivers() devices = init_devices() tables = init_tables() map(update_device, devices) # commit changes to the data repository monotone_commit()