def _load_rbr(self, load_ast=True): if load_ast: self.ast = build_ast(self.rbr_content) # looking for the root path for definition in self.ast: if definition.type != 'root': continue self.root_path = definition.value break self.globs = self._create_globs() self.types = self._create_types() self.mapper = WebMapper(self)
class RedBarrelApplication(object): def __init__(self, location=None, rbr_content=_RBR, app_content=_APP, context=None, name='undefined'): """ location contains the application, composed of: + an app.rbr file + an app.py file If location is not provided, will look into the current dir """ if location is not None and os.path.exists(location): self.root = location else: self.root = os.getcwd() self.name = name # rbr file self.rbr_file = os.path.join(self.root, '%s.rbr' % self.name) if os.path.exists(self.rbr_file): with open(self.rbr_file) as f: self.rbr_content = f.read() else: self.rbr_content = rbr_content # rbr file self.app_file = os.path.join(self.root, '%s.py' % self.name) if os.path.exists(self.app_file): with open(self.app_file) as f: self.app_content = f.read() else: self.app_content = app_content # XXX see how to do this in a more elegant way old = sys.path[:] sys.path.insert(0, self.root) try: self.module = VirtualModule(self.name, self.app_content) finally: sys.path[:] = old self.root_path = '' self.context = context self._load_rbr() self._commitmapper() def update_code(self, data): self.app_content = data self.module.update(data) def sync(self): # saving the RBR file with open(self.rbr_file, 'w') as f: # XXX should be str all the time if isinstance(self.rbr_content, unicode): self.rbr_content = self.rbr_content.encode('utf-8') f.write(self.rbr_content) # saving the Python file with open(self.app_file, 'w') as f: f.write(self.app_content) def _commitmapper(self): self._rbr_content = None self._app_content = None self._ast = None self._globs = None self._types = None self._mapper = None self.sync() def _backupmapper(self): self._rbr_content = self.rbr_content self._app_content = self.app_content self._ast = self.ast self._globs = self.globs self._types = self.types self._mapper = self.mapper def _rollbackmapper(self): if self._rbr_content is None: raise ValueError("Nothing to rollback") self.rbr_content = self._rbr_content self._app_content = self.app_content self.ast = self._ast self.globs = self._globs self.types = self._types self.mapper = self._mapper def _load_rbr(self, load_ast=True): if load_ast: self.ast = build_ast(self.rbr_content) # looking for the root path for definition in self.ast: if definition.type != 'root': continue self.root_path = definition.value break self.globs = self._create_globs() self.types = self._create_types() self.mapper = WebMapper(self) def _resolve_def(self, value, *args, **kw): if not isinstance(value, str): return value prefixed = value.split(':', 1) if prefixed[0] not in get_runner_names(): return value res = resolve_runner(value, self.root)(*args, **kw) if value == res: raise ImportError(value) else: value = res return value def _create_types(self): # reads the types definitions and loads them types = {} logger.info('Initializing types...') for definition in self.ast: if definition.type != 'type': continue name = definition.left types[name] = self._resolve_def(definition.right) return types def _create_globs(self): # reads the globs definitions and loads them globs = {} logger.info('Initializing globs...') for definition in self.ast: if definition.type != 'global': continue name = definition.left value = definition.right.value globs[name] = self._resolve_def(value, copy.copy(globs)) return globs def generate(self): logger.info('Generating the Web App...') for definition in self.ast: type_ = definition.type if type_ == 'meta': self.mapper.set_options(definition.value) continue elif type_ in _NONPATH: continue name = definition.left args = definition.right #print name #print args #if len(definition) > 2: # args = definition[2] #else: # args = [] self.mapper.add(name, args) logger.info('...ready') logger.info('') def __call__(self, request): return self.mapper(request) def get_options(self): return self.mapper.options def set_options(self, options): self.mapper.set_options(options) def add_def(self, name, definition): self.mapper.add(name, definition) def del_def(self, name): new_ast = [] for definition in self.ast: if definition.type == 'def' and definition.left == name: continue new_ast.append(definition) if len(new_ast) < len(self.ast): self.ast = new_ast self._load_rbr(load_ast=False) self.generate() def add_content(self, content): # syntax check try: ast = build_ast(content) except Exception, e: raise SyntaxError(e) if ast is None: raise SyntaxError() # actual ast change self._backupmapper() try: self.rbr_content += '\n%s' % content self._load_rbr() self.generate() self._commitmapper() except Exception: self._rollbackmapper() raise