-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #65 from handroll/sitemap-ext
Add a sitemap extension.
- Loading branch information
Showing
9 changed files
with
161 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Copyright (c) 2016, Matt Layman | ||
|
||
import os | ||
|
||
from handroll import logger | ||
from handroll.extensions.base import Extension | ||
from handroll.i18n import _ | ||
|
||
|
||
class SitemapExtension(Extension): | ||
"""Generate a sitemap from the HTML pages of the site.""" | ||
|
||
handle_frontmatter_loaded = True | ||
handle_pre_composition = True | ||
handle_post_composition = True | ||
|
||
def __init__(self, config): | ||
super(SitemapExtension, self).__init__(config) | ||
self.urls = set() | ||
self._composers = None | ||
self._resolver = None | ||
# Assume that the sitemap needs to be generated at startup. | ||
self._dirty = True | ||
|
||
def on_pre_composition(self, director): | ||
self._composers = director.composers | ||
self._resolver = director.resolver | ||
|
||
def on_frontmatter_loaded(self, source_file, frontmatter): | ||
composer = self._composers.select_composer_for(source_file) | ||
if composer.output_extension == '.html': | ||
url = self._resolver.as_url(source_file) | ||
if url not in self.urls: | ||
self.urls.add(url) | ||
self._dirty = True | ||
|
||
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Copyright (c) 2016, Matt Layman | ||
|
||
import os | ||
|
||
from handroll import signals | ||
from handroll.extensions.sitemap import SitemapExtension | ||
from handroll.tests import TestCase | ||
|
||
|
||
class TestSitemapExtention(TestCase): | ||
|
||
def tearDown(self): | ||
super(TestSitemapExtention, self).tearDown() | ||
# Clean up any attached extension instance. | ||
signals.frontmatter_loaded.receivers.clear() | ||
signals.pre_composition.receivers.clear() | ||
signals.post_composition.receivers.clear() | ||
|
||
def _make_one(self, director): | ||
director.config.parser.add_section('sitemap') | ||
extension = SitemapExtension(director.config) | ||
extension.on_pre_composition(director) | ||
return extension | ||
|
||
def test_handles_frontmatter_loaded(self): | ||
extension = SitemapExtension(None) | ||
self.assertTrue(extension.handle_frontmatter_loaded) | ||
|
||
def test_handles_pre_composition(self): | ||
extension = SitemapExtension(None) | ||
self.assertTrue(extension.handle_pre_composition) | ||
|
||
def test_handles_post_composition(self): | ||
extension = SitemapExtension(None) | ||
self.assertTrue(extension.handle_post_composition) | ||
|
||
def test_records_html_url(self): | ||
director = self.factory.make_director() | ||
extension = self._make_one(director) | ||
extension._dirty = False | ||
path = os.path.join(director.site.path, 'path/to/sample.md') | ||
extension.on_frontmatter_loaded(path, {}) | ||
self.assertIn( | ||
'http://www.example.com/path/to/sample.html', extension.urls) | ||
self.assertTrue(extension._dirty) | ||
|
||
def test_ignores_non_html_url(self): | ||
director = self.factory.make_director() | ||
extension = self._make_one(director) | ||
path = os.path.join(director.site.path, 'path/to/sample.png') | ||
extension.on_frontmatter_loaded(path, {}) | ||
self.assertFalse(extension.urls) | ||
|
||
def test_generates_sitemap_output(self): | ||
director = self.factory.make_director() | ||
os.mkdir(director.outdir) | ||
extension = self._make_one(director) | ||
path_a = os.path.join(director.site.path, 'path/to/a.md') | ||
path_b = os.path.join(director.site.path, 'path/to/b.md') | ||
extension.on_frontmatter_loaded(path_b, {}) | ||
extension.on_frontmatter_loaded(path_a, {}) | ||
extension.on_post_composition(director) | ||
content = open(os.path.join(director.outdir, 'sitemap.txt')).read() | ||
self.assertEqual( | ||
'http://www.example.com/path/to/a.html\n' | ||
'http://www.example.com/path/to/b.html\n', | ||
content) | ||
self.assertFalse(extension._dirty) | ||
|
||
def test_not_dirty_when_url_already_recorded(self): | ||
director = self.factory.make_director() | ||
extension = self._make_one(director) | ||
path_a = os.path.join(director.site.path, 'path/to/a.md') | ||
extension.on_frontmatter_loaded(path_a, {}) | ||
extension._dirty = False | ||
extension.on_frontmatter_loaded(path_a, {}) | ||
self.assertFalse(extension._dirty) | ||
|
||
def test_no_sitemap_when_not_dirty(self): | ||
director = self.factory.make_director() | ||
os.mkdir(director.outdir) | ||
extension = self._make_one(director) | ||
extension._dirty = False | ||
extension.on_post_composition(director) | ||
self.assertFalse( | ||
os.path.exists(os.path.join(director.outdir, 'sitemap.txt'))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters