from docutils import core import os, urllib2, popen2 class Error(Exception): pass class Website: """A website consists of resources and pages. """ def __init__(self, website_path): self._website_path = website_path self._resource_infos = [] self._infos = [] def registerPages(self, pages, layouter, directory, **kw): """Register a set of pages. The pages all end up in the same directory and share a layouter. Optional keyword arguments are also passed through to all of them. """ dir_path = os.path.join(self._website_path, directory) for page in pages: path = os.path.join(dir_path, page.getName()) self._infos.append(Info(page, layouter, path, **kw)) def registerResources(self, resources, directory): """Register a set of resources. The resources all end up in the same directory. """ self.registerPages(resources, None, directory) def registerReleases(self, resources, directory): """Register a set of releases. Releases are normal resources, but end up in a special release directory. """ directory = os.path.join(directory, 'release') self.registerResources(resources, directory) def save(self): """Save all pages and resources. """ for info in self._infos: info.save() class Info: """Information describing what to do with a web page. i.e. how to layout it, where to place it when done. """ def __init__(self, resource, layouter, destination_path, **kw): self._resource = resource self._destination_path = destination_path self._layouter = layouter self._kw = kw def render(self): return self._resource.render(self._layouter, **self._kw) def save(self): """Save this resource. """ print "Saving", self._destination_path try: os.makedirs(os.path.dirname(self._destination_path)) except os.error: pass data = self.render() f = open(self._destination_path, 'w') f.write(data) f.close() class BaseResource: """Base class of all resources. """ def __init__(self, name): self._name = name def getName(self): """Name of resource when written. """ return self._name def render(self, layouter, **kw): raise NotImplementedError class BaseDataResource(BaseResource): """A resource that gets its main data from a data source. """ def __init__(self, data_source, name=None): BaseResource.__init__(self, name) if self._name is None: self._name = data_source.getName() self._data = data_source.getData() class Resource(BaseDataResource): """A resource that is just a file. """ def render(self, layouter, **kw): return self._data class FileResource(Resource): """Convenience way to create a Resource from file. """ def __init__(self, path, name=None): Resource.__init__(self, PathSource(path), name) class BasePage(BaseDataResource): """Base class of all pages. """ def __init__(self, data_source, name=None): BaseDataResource.__init__(self, data_source, name) self._name = os.path.splitext(self._name)[0] + '.html' def getData(self): """Returns a dictionary with data to use in the page. """ raise NotImplementedError def render(self, layouter, **kw): kw.update(self.getData()) return layouter.render(**kw) class RstPage(BasePage): def __init__(self, data_source, name=None, encoding='ascii'): BasePage.__init__(self, data_source, name=name) self.encoding = encoding def getData(self): return html_parts(self._data, initial_header_level=2, input_encoding=self.encoding) class FileRstPage(RstPage): """Convenience way to create a RstPage from file. """ def __init__(self, path, name=None, encoding='unicode'): RstPage.__init__(self, PathSource(path), name, encoding=encoding) class SimplePage(BasePage): def __init__(self, name): self._name = name + '.html' def getData(self): return {} class SimpleLayouter: """Simple layouter which replaces {{foo}} in a template with values. """ def __init__(self, template, **kw): self._template = template self._kw = kw def render(self, **kw): kw.update(self._kw) template = self._template for key, value in kw.items(): if type(value) in (str, unicode): template = template.replace('{{%s}}' % key, value) elif type(value) == type([]): l = [] l.append('