def _split_content_with_frontmatter(self, first, source, source_file): """Separate frontmatter from source material.""" max_splits = 1 # With a directive present, there must be two document markers. if first.startswith('%YAML'): max_splits = 2 content = source.split(self.document_marker, max_splits) try: data = yaml.load(content[max_splits - 1]) except ScannerError as ex: raise AbortError( _('There is invalid YAML in the frontmatter: {details}'). format(details=str(ex))) try: source = content[max_splits] except IndexError: raise AbortError( _('A YAML marker was missing in {source}').format( source=source_file)) if 'title' in data: data['title'] = escape(data['title']) return data, source
def make(scaffold, site): """Make a site from the scaffold.""" if scaffold not in BUILTIN_SCAFFOLDS: raise AbortError( _('There is no {scaffold} scaffold.'.format(scaffold=scaffold))) if os.path.exists(site): raise AbortError(_('{site} already exists.'.format(site=site))) os.makedirs(site) scaffold_path = os.path.join(SCAFFOLDS_PATH, scaffold) shutil.copytree(scaffold_path, os.path.join(site, 'source'))
def on_pre_composition(self, director): if not self._config.parser.has_section('open_graph'): raise AbortError( _('An open_graph section is missing in the configuration file.' )) if not self._config.parser.has_option('open_graph', 'default_image'): raise AbortError( _('A default image URL is missing in the configuration file.')) self._resolver = director.resolver self._url_resolver = URLResolver( self._config, self._config.parser.get('open_graph', 'default_image'))
def build(cls, args): """Build a validated site.""" site = cls(args.site) valid, message = site.is_valid() if not valid: raise AbortError(_('Invalid site source: {0}').format(message)) return site
def on_pre_composition(self, director): if not self._config.parser.has_section('twitter'): raise AbortError( _('An twitter section is missing in the configuration file.')) if not self._config.parser.has_option('twitter', 'default_image'): raise AbortError( _('A default image URL is missing in the configuration file.')) if not self._config.parser.has_option('twitter', 'site_username'): raise AbortError( _('A site username is missing in the configuration file.')) self._resolver = director.resolver self._url_resolver = URLResolver( self._config, self._config.parser.get('twitter', 'default_image')) self._site = self._config.parser.get('twitter', 'site_username')
def _is_post(self, frontmatter): """Check if the front matter looks like a blog post.""" is_post = frontmatter.get("blog", False) if type(is_post) != bool: raise AbortError( _("Invalid blog frontmatter (expects True or False): " "{blog_value}").format(blog_value=is_post)) return is_post
def _get_option(self, option): """Get an option out of the blog section.""" try: return self._config.parser.get("blog", option) except configparser.NoOptionError: raise AbortError( _("The blog extension requires the {option} option.").format( option=option))
def _build_template(self, template_path): """Build a template. Abort if unknown type.""" for extension, template_builder in self._builders.items(): if template_path.endswith(extension): return template_builder(template_path) raise AbortError( _('Unknown template type provided for {template}.').format( template=template_path))
def _validate_post(self, source_file, frontmatter): """Validate that the post contains all the required fields.""" required = set(["date", "title"]) fields = set(frontmatter.keys()) missing = required - fields if missing: raise AbortError( _("The blog post, {filename}, " "is missing required fields: {missing_fields}".format( filename=source_file, missing_fields=", ".join(missing))))
def _find_extensions(self, parser): """Check if the site options have extensions to enable.""" for option in parser.options('site'): if option.startswith('with_'): try: extension = option.split('with_', 1)[1] or option enabled = parser.getboolean('site', option) if enabled: self.active_extensions.add(extension) except ValueError: raise AbortError( _('Cannot determine if {extension} is enabled.'). format(extension=extension))
def _validate_post(self, source_file, frontmatter): """Validate that the post contains all the required fields.""" required = set([ 'date', 'title', ]) fields = set(frontmatter.keys()) missing = required - fields if missing: raise AbortError( _('The blog post, {filename}, ' 'is missing required fields: {missing_fields}'.format( filename=source_file, missing_fields=', '.join(missing))))
def build(self, template_path): """Build a Jinja template from the file path.""" # Strip the templates path from the template path to get the relative # name that the ``FileSystemLoader`` wants. template_name = os.path.relpath(template_path, self.templates_path) try: template = self._env.get_template(template_name) template.last_modified = self._get_last_modified(template_name, template_path) return template except jinja2.exceptions.TemplateSyntaxError as e: raise AbortError( _('An error exists in the Jinja template at {template}:' ' {error}').format(template=template_path, error=str(e)))
def on_pre_composition(self, director): """Check that all the required configuration exists.""" if not self._config.parser.has_section("blog"): raise AbortError( _("A blog section is missing in the configuration file.")) # Collect atom feed configuration. for metadata, option in self.required_metadata.items(): self._add_atom_metadata(metadata, option) self.atom_output = self._get_option("atom_output") # Collect HTML listing configuration. if self._config.parser.has_option("blog", "list_template"): self.list_template = self._get_option("list_template") self.list_output = self._get_option("list_output") # Grab the resolver from the director for determining URLs for posts. self._resolver = director.resolver
def _find_site_root_from(self, cwd): """Ascend through the current working directory provided to find something that looks like the root of a handroll site and return that path. Assumes that ``cwd`` is a valid directory path.""" candidate = cwd while True: if self._is_site_root(candidate): return candidate parent = os.path.realpath(os.path.join(candidate, os.pardir)) if candidate == parent: # When the next candidate is equal to the previous one, then # the root of the filesystem has been reached and tested. break candidate = parent raise AbortError( _('A handroll site was not found in {current_directory}' ' or any of its parents.').format(current_directory=cwd))
def _parse_feed(self, source_file): try: with io.open(source_file, "r", encoding="utf-8") as f: metadata = json.loads(f.read()) if metadata.get("entries") is None: raise ValueError(_("Missing entries list.")) entries = metadata["entries"] # AtomFeed expects FeedEntry objects for the entries keyword so # remove it from the metadata and add it after the feed is built. del metadata["entries"] feed = AtomFeed(**metadata) [feed.add(self._make_entry(entry)) for entry in entries] except ValueError as error: raise AbortError( _("Invalid feed {source_file}: {error}").format( source_file=source_file, error=str(error))) return feed
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 domain(self): if self._domain is None: raise AbortError( _('You are missing a domain setting in the site section.')) return self._domain
def _abort_if_missing(self, template_path): if not os.path.exists(template_path): raise AbortError( _('No template found at {template_path}.').format( template_path=template_path))
def __init__(self, path=None): self.sass = spawn.find_executable('sass', path) if self.sass is None: raise AbortError(_('Sass is not installed.'))