]> andersk Git - sql.git/blob - lib/python/mitsql/templates.py
f72800564dbddc75e689d90f421da396126d130b
[sql.git] / lib / python / mitsql / templates.py
1 # Joe Presbrey  <presbrey@mit.edu>
2
3 import os, sys, types, time
4 import threading 
5 from pyinotify import WatchManager, Notifier, EventsCodes
6 from Cheetah.Template import Template as _Template
7
8 __all__ = ['Templates']
9
10 class Template(object):
11     def __init__(self, name, ns={}, path=['templates']):
12         self._name, self._ns, self._path = name, ns, path+[name]
13         assert self._template()
14     
15     def _template(self):
16         return sys.modules['.'.join(self._path)]
17     
18     def __getattr__(self, name):
19         return Template(name, self._ns, self._path)
20     
21     def __call__(self, **kw):
22         namespaces = self._ns.copy()
23         namespaces.update(kw)
24         return getattr(self._template(),
25                        self._name)(namespaces=namespaces).respond()
26
27 class Templates(object):
28     _base = ''
29     _mask = EventsCodes.ALL_FLAGS['IN_CREATE'] \
30           | EventsCodes.ALL_FLAGS['IN_MODIFY'] \
31           | EventsCodes.ALL_FLAGS['IN_DELETE'] \
32           | EventsCodes.ALL_FLAGS['IN_ATTRIB']
33     _watch_manager = None
34     _notifier = None
35     _thread = None
36     
37     _loaded = False
38     _files = {}
39     _modules = {}
40     
41     def __init__(self, template_path, global_namespace={}):
42         self._base = os.path.abspath(template_path)
43         self._event_init()
44         self._assert_module('templates', [template_path])
45         self._globals = global_namespace
46         self.load()
47         self._thread = threading.Thread(target=self.loop)
48         self._thread.setDaemon(True)
49         self._thread.start()
50
51     def _tree_walk(self, tree, path, func):
52         path = list(path)
53         if len(path) > 1:
54             x = path.pop(0)
55             if not x in tree:
56                 tree[x] = {}
57             return self._tree_walk(tree[x], path, func)
58         elif callable(func):
59             return func(tree, path[0])
60
61     def _tree_add(self, tree, path, value):
62         def _add(tree, key):
63             tree[key] = value
64             return value
65         print self._tree_walk(tree, path, _add)
66     
67     def _assert_module(self, name, path=None):
68         if not name in self._modules:
69             self._modules[name] = types.ModuleType(name)
70             if path:
71                 self._modules[name].__path__ = path
72             sys.modules[name] = self._modules[name]
73     
74     def _get_template_path(self, template_file):
75         r = template_file.startswith(self._base) \
76           and template_file[len(self._base)+1:].split(os.path.sep) or []
77         if r[-1].endswith('.tmpl'):
78             r[-1] = r[-1][:-5]
79         return tuple(r)
80     
81     def _compile(self, template_path):
82         template = _Template.compile(file=self._files[template_path],
83                                      returnAClass=False,
84                                      moduleName='.'.join(['templates']+list(template_path)),
85                                      className=template_path[-1],
86                                      useCache=False,
87                                      compilerSettings={'useStackFrames':False})
88         return template
89     
90     def add(self, template_file):
91         template_path = self._get_template_path(template_file)
92         template_name = '.'.join(['templates']+list(template_path))
93         template_pkg = '.'.join(['templates']+list(template_path[:-1]))
94         template_py = os.path.join(os.path.dirname(template_file), '%s.py' % template_path[-1])
95         self._assert_module(template_pkg, [os.path.dirname(template_file)])
96         self._files[template_path] = template_file
97         code = self._compile(template_path)
98         f_code = file(template_py, 'w')
99         f_code.write(code)
100         f_code.close()
101         if self._loaded and \
102            template_name in sys.modules:
103             reload(sys.modules[template_name])
104     
105     def remove(self, template_file):
106         #print 'removing', template_file
107         pass
108     
109     def _walk_load(self, args, dname, fnames):
110         for fname in fnames:
111             if fname.endswith('.tmpl'):
112                 template_file = os.path.join(dname, fname)
113                 self.add(template_file)
114     
115     def load(self):
116         if not self._loaded:
117             os.path.walk(self._base, self._walk_load, None)
118             for path, filename in self._files.items():
119                 __import__('.'.join(['templates']+list(path)))
120             self._loaded = True
121     
122     def _event_handler(self, event):
123         if event.name.endswith('.tmpl') and not event.name.startswith('.'):
124             if event.maskname == 'IN_DELETE':
125                 self.remove(event.pathname)
126             else:
127                 time.sleep(0.5)
128                 self.add(event.pathname)
129                 
130     
131     def _event_init(self):
132         self._watch_manager = WatchManager()
133         self._watch_manager.add_watch(self._base,
134                                       self._mask,
135                                       self._event_handler,
136                                       rec=True,
137                                       auto_add=True)
138         self._notifier = Notifier(self._watch_manager)
139     
140     def loop(self):
141         self.load()
142         while True:
143             try:
144                 self._notifier.process_events()
145                 if self._notifier.check_events():
146                     self._notifier.read_events()
147             except KeyboardInterrupt:
148                 self._notifier.stop()
149                 break
150     
151     def __getattr__(self, key):
152         return Template(key, self._globals)
153
154 if __name__ == '__main__':
155     t = Templates('/home/joe/templates')
This page took 0.268083 seconds and 3 git commands to generate.