def serve(site, director): """Run a simple web server that serve the output directory and watches for changes to the site. When something is changed, it should be generated. """ # Override the log level to display some interactive messages with the # user. With the dev server running, there's no sense in being silent. logger.setLevel(logging.INFO) # Start the watchdog. event_handler = SiteHandler(director) observer = Observer() observer.schedule(event_handler, site.path, recursive=True) observer.start() # The simple HTTP server is pretty dumb and does not even take a path to # serve. The only way to serve the right path is to change the directory. outdir = director.outdir os.chdir(outdir) socketserver.TCPServer.allow_reuse_address = True httpd = socketserver.TCPServer(('', PORT), SimpleHTTPRequestHandler) logger.info( _('Serving {outdir} at http://localhost:{port}/.' '\nPress Ctrl-C to quit.').format(outdir=outdir, port=PORT)) try: httpd.serve_forever() except KeyboardInterrupt: logger.info(_('\nBye.')) observer.stop() observer.join()
def _generate_atom_feed(self, director, blog_posts): """Generate the atom feed.""" logger.info(_("Generating Atom XML feed ...")) builder = FeedBuilder(self.atom_metadata) builder.add(blog_posts) output_file = os.path.join(director.outdir, self.atom_output) builder.write_to(output_file)
def _generate_atom_feed(self, director, blog_posts): """Generate the atom feed.""" logger.info(_('Generating Atom XML feed ...')) builder = FeedBuilder(self.atom_metadata) builder.add(blog_posts) output_file = os.path.join(director.outdir, self.atom_output) builder.write_to(output_file)
def _create_output_directories(self, dirnames, output_dirpath): """Create new directories in output.""" for dirname in dirnames: out = os.path.join(output_dirpath, dirname) # The directory may already exist for updates. if not os.path.exists(out): logger.info(_('Creating directory {out} ...').format(out=out)) os.mkdir(out)
def _generate_list_page(self, director, blog_posts): """Generate the list page.""" logger.info(_("Generating blog list page ...")) template = director.catalog.get_template(self.list_template) builder = ListPageBuilder(template) builder.add(blog_posts) output_file = os.path.join(director.outdir, self.list_output) builder.write_to(output_file)
def _generate_list_page(self, director, blog_posts): """Generate the list page.""" logger.info(_('Generating blog list page ...')) template = director.catalog.get_template(self.list_template) builder = ListPageBuilder(template) builder.add(blog_posts) output_file = os.path.join(director.outdir, self.list_output) builder.write_to(output_file)
def on_post_composition(self, director): if not self._dirty: return logger.info(_('Generating sitemap ...')) sitemap_path = os.path.join(director.outdir, 'sitemap.txt') with open(sitemap_path, 'w') as sitemap: for url in sorted(self.urls): sitemap.write(url + '\n') self._dirty = False
def compose(self, catalog, source_file, out_dir): root, ext = os.path.splitext(os.path.basename(source_file)) filename = root + self.output_extension output_file = os.path.join(out_dir, filename) if self._needs_update(source_file, output_file): logger.info(_('Generating Atom XML for {source_file} ...').format( source_file=source_file)) feed = self._parse_feed(source_file) with open(output_file, 'wb') as out: out.write(feed.to_string().encode('utf-8')) out.write(b'<!-- handrolled for excellence -->\n') else: logger.debug(_('Skipping {filename} ... It is up to date.').format( filename=filename))
def compose(self, catalog, source_file, out_dir): filename = os.path.basename(source_file.rstrip('.j2')) output_file = os.path.join(out_dir, filename) if self._needs_update(source_file, output_file): logger.info(_('Generating from template {source_file} ...').format( source_file=source_file)) data, source = self.get_data(source_file) data['config'] = self._config template = jinja2.Template(source) with open(output_file, 'wb') as out: out.write(template.render(data).encode('utf-8')) # Frontmatter loading seems to munch the final line separator. out.write(os.linesep.encode('utf-8')) else: logger.debug(_('Skipping {filename} ... It is up to date.').format( filename=filename))
def compose(self, catalog, source_file, out_dir): root, ext = os.path.splitext(os.path.basename(source_file)) filename = root + self.output_extension output_file = os.path.join(out_dir, filename) if self._needs_update(source_file, output_file): logger.info( _("Generating Atom XML for {source_file} ...").format( source_file=source_file)) feed = self._parse_feed(source_file) with open(output_file, "wb") as out: out.write(feed.to_string().encode("utf-8")) out.write(b"<!-- handrolled for excellence -->\n") else: logger.debug( _("Skipping {filename} ... It is up to date.").format( filename=filename))
def compose(self, catalog, source_file, out_dir): filename = os.path.basename(source_file.rstrip('.j2')) output_file = os.path.join(out_dir, filename) if self._needs_update(source_file, output_file): logger.info( _('Generating from template {source_file} ...').format( source_file=source_file)) data, source = self.get_data(source_file) data['config'] = self._config template = jinja2.Template(source) with open(output_file, 'wb') as out: out.write(template.render(data).encode('utf-8')) # Frontmatter loading seems to munch the final line separator. out.write(os.linesep.encode('utf-8')) else: logger.debug( _('Skipping {filename} ... It is up to date.').format( filename=filename))
def compose(self, catalog, source_file, out_dir): root, ext = os.path.splitext(os.path.basename(source_file)) filename = root + self.output_extension output_file = os.path.join(out_dir, filename) logger.info(_('Generating CSS for {source_file} ...').format( source_file=source_file)) command = self.build_command(source_file, output_file) process = subprocess.Popen( command, stdin=subprocess.PIPE, stdout=subprocess.PIPE) (out, err) = process.communicate() if out: logger.debug(_('Received output from sass:\n{0}'.format(out))) if process.returncode != 0: raise AbortError(_('Sass failed to generate CSS:\n{0}').format( err))
def compose(self, catalog, source_file, out_dir): """Compose an HTML document by generating HTML from the source file, merging it with a template, and write the result to output directory.""" data, source = self.get_data(source_file) template = self.select_template(catalog, data) # Determine the output filename. root, ext = os.path.splitext(os.path.basename(source_file)) filename = root + self.output_extension output_file = os.path.join(out_dir, filename) if self._needs_update(template, source_file, output_file): logger.info(_('Generating HTML for {source_file} ...').format( source_file=source_file)) data['content'] = self._generate_content(source) self._render_to_output(template, data, output_file) else: logger.debug(_('Skipping {filename} ... It is up to date.').format( filename=filename))
def compose(self, catalog, source_file, out_dir): root, ext = os.path.splitext(os.path.basename(source_file)) filename = root + self.output_extension output_file = os.path.join(out_dir, filename) logger.info( _('Generating CSS for {source_file} ...').format( source_file=source_file)) command = self.build_command(source_file, output_file) process = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE) (out, err) = process.communicate() if out: logger.debug(_('Received output from sass:\n{0}'.format(out))) if process.returncode != 0: raise AbortError( _('Sass failed to generate CSS:\n{0}').format(err))
def compose(self, catalog, source_file, out_dir): """Copy a file to the destination if the file does not exist or was modified.""" filename = os.path.basename(source_file) # Do not copy files that are already there unless different. destination = os.path.join(out_dir, filename) if os.path.exists(destination): if filecmp.cmp(source_file, destination): # Files are equal. Do nothing. logger.debug(_('Skipping {filename} ... It is the same as ' '{destination}.').format( filename=filename, destination=destination)) return else: logger.info( _('{filename} differs from {destination} ...').format( filename=filename, destination=destination)) logger.info(_('Copying {filename} to {out_dir} ...').format( filename=filename, out_dir=out_dir)) shutil.copy(source_file, out_dir)
def compose(self, catalog, source_file, out_dir): """Compose an HTML document by generating HTML from the source file, merging it with a template, and write the result to output directory.""" data, source = self.get_data(source_file) template = self.select_template(catalog, data) # Determine the output filename. root, ext = os.path.splitext(os.path.basename(source_file)) filename = root + self.output_extension output_file = os.path.join(out_dir, filename) if self._needs_update(template, source_file, output_file): logger.info( _('Generating HTML for {source_file} ...').format( source_file=source_file)) data['content'] = self._generate_content(source) self._render_to_output(template, data, output_file) else: logger.debug( _('Skipping {filename} ... It is up to date.').format( filename=filename))
def compose(self, catalog, source_file, out_dir): """Copy a file to the destination if the file does not exist or was modified.""" filename = os.path.basename(source_file) # Do not copy files that are already there unless different. destination = os.path.join(out_dir, filename) if os.path.exists(destination): if ( not self._config.force and filecmp.cmp(source_file, destination) ): # Files are equal. Do nothing. logger.debug(_('Skipping {filename} ... It is the same as ' '{destination}.').format( filename=filename, destination=destination)) return else: logger.info( _('{filename} differs from {destination} ...').format( filename=filename, destination=destination)) logger.info(_('Copying {filename} to {out_dir} ...').format( filename=filename, out_dir=out_dir)) shutil.copy(source_file, out_dir)
def _generate_output(self, outdir, timing): if os.path.exists(outdir): logger.info(_('Updating {outdir} ...').format(outdir=outdir)) else: logger.info(_('Creating {outdir} ...').format(outdir=outdir)) os.mkdir(outdir) for dirpath, dirnames, filenames in os.walk(self.site.path): # Prevent work on the output or templates directory. # Skip the template. if dirpath == self.site.path: if self.site.OUTPUT in dirnames: dirnames.remove(self.site.OUTPUT) if template.TEMPLATES_DIR in dirnames: dirnames.remove(template.TEMPLATES_DIR) if template.DEFAULT_TEMPLATE in filenames: filenames.remove(template.DEFAULT_TEMPLATE) self.prune_skip_directories(dirnames) output_dirpath = self._get_output_dirpath(dirpath, outdir) logger.info(_('Populating {dirpath} ...').format( dirpath=output_dirpath)) # Create new directories in output. for dirname in dirnames: out_dir = os.path.join(output_dirpath, dirname) # The directory may already exist for updates. if not os.path.exists(out_dir): logger.info(_('Creating directory {out_dir} ...').format( out_dir=out_dir)) os.mkdir(out_dir) for filename in filenames: filepath = os.path.join(dirpath, filename) self._process_file(filepath, output_dirpath, timing)
def _generate_output(self, outdir): if os.path.exists(outdir): logger.info(_('Updating {outdir} ...').format(outdir=outdir)) else: logger.info(_('Creating {outdir} ...').format(outdir=outdir)) os.mkdir(outdir) self._collect_frontmatter() for dirpath, dirnames, filenames in self.site.walk(): output_dirpath = self._get_output_dirpath(dirpath, outdir) logger.info( _('Populating {dirpath} ...').format(dirpath=output_dirpath)) self._create_output_directories(dirnames, output_dirpath) for filename in filenames: filepath = os.path.join(dirpath, filename) self._process_file(filepath, output_dirpath)
def _generate_output(self, outdir): if os.path.exists(outdir): logger.info(_('Updating {outdir} ...').format(outdir=outdir)) else: logger.info(_('Creating {outdir} ...').format(outdir=outdir)) os.mkdir(outdir) self._collect_frontmatter() for dirpath, dirnames, filenames in self.site.walk(): output_dirpath = self._get_output_dirpath(dirpath, outdir) logger.info(_('Populating {dirpath} ...').format( dirpath=output_dirpath)) self._create_output_directories(dirnames, output_dirpath) for filename in filenames: filepath = os.path.join(dirpath, filename) self._process_file(filepath, output_dirpath)