class Site(object): def __init__(self, root, dest): self.root = root if op.exists(dest): shutil.rmtree(dest) self.settings = Settings(parent_tmpl='_base.html') conf = op.join(self.root, 'settings.cfg') if op.exists(conf): self.settings.read(file(conf).read().decode('utf-8')) site_base_path = base_path(self.url) self.dest = op.join(dest, url2path(site_base_path[1:])) self.env = initialize_env(root) self.env.globals['site'] = self self.entries = [] self.settings.meta = {} self.settings.meta['generator'] = "Conrad 2.6alpha" if self.settings.get('sitecallback'): callback = impcallback(self.settings.sitecallback, self.root) callback(self) self._traverse() @property def url(self): return getattr(self.settings, 'url', '/') def __repr__(self): return '<Site: %r>' % self.root def __getitem__(self, name): return self.settings[name] def __getattr__(self, name): try: return self.settings[name] except KeyError, e: raise AttributeError(str(e))
class Entry(object): def __init__(self, site, path, source=None): '''Initialize an entry This involves change of base class by running static method Class.check of every member of models.TYPE_LIST. Arguments: - `site`: site this entry belongs to - `path`: relative path to source template and to result - `source`: optional source template path. Can be used to trick system to have virtual entries (with no real equivalent in source directory) ''' self.site = site self.path = path self.source = source self.mtime = self.get_mtime() self.settings = Settings(parent=self.site.settings) base = '_%s.html' % self.__class__.__name__.lower() if os.path.exists(os.path.join(self.site.root, base)): self.settings.parent_tmpl = base self.template = self.get_template() self.settings.base, self.settings.slug = os.path.split(self.path) self.collect() if hasattr(self, 'init'): self.init() def __repr__(self): return '<%s: %r>' % (self.__class__.__name__, self.path) def __getitem__(self, name): return self.settings[name] def __getattr__(self, name): try: return self.settings[name] except KeyError: raise AttributeError(name) def get_mtime(self): '''Determine modification time (with date) As in modification time vs creation time. If source is not null and path does not exist, then entry is virtual and returns current datetime. ''' path = os.path.join(self.site.root, self.path) if self.source and not os.path.exists(path): return datetime.datetime.now() mtime = os.path.getmtime(path) return datetime.datetime(*time.gmtime(mtime)[:6]) def get_template(self): '''Get Jinja2 template of entry to render ''' return self.site.env.get_template(self.source or self.path, globals={'entry': self}) def collect(self): '''Collect settings information from entry Renders Jinja2 template to get this information from {% meta %} ''' self.template.render() def isdir(self): '''Determines if entry should be rendered as directory ''' return self.settings.get('isdir', True) def get_dest(self): path = os.path.join(self.site.dest, url2path(self.get_relative_url())) if self.isdir(): path = os.path.join(path, 'index.html') return path def get_relative_url(self): return self.path def get_url(self): return safe_url_join(base_path(self.site.url), self.get_relative_url()) def get_absolute_url(self): return safe_url_join(self.site.url, self.get_relative_url()) def render(self): logger.info('Rendering %r' % self) # workaround for a dumb bug # no ideas why but all tag templates contain same self inside self.template.globals['entry'] = self path = self.get_dest() makedirs(os.path.dirname(path)) file(path, 'w').write(self.template.render().encode('utf-8'))