Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
 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)
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
 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)
Ejemplo n.º 7
0
 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)
Ejemplo n.º 8
0
 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
Ejemplo n.º 9
0
    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))
Ejemplo n.º 10
0
 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))
Ejemplo n.º 11
0
    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))
Ejemplo n.º 12
0
 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))
Ejemplo n.º 13
0
    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))
Ejemplo n.º 14
0
    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))
Ejemplo n.º 15
0
    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))
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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))
Ejemplo n.º 18
0
    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)
Ejemplo n.º 19
0
    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)
Ejemplo n.º 20
0
    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)
Ejemplo n.º 21
0
    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)