Merge pull request #262 from justinmayer/feeddomain

Allow for serving feeds from a separate domain.
This commit is contained in:
Alexis Metaireau 2012-03-22 08:58:09 -07:00
commit 38b5b94617
6 changed files with 106 additions and 34 deletions

View file

@ -62,10 +62,13 @@ Setting name (default value) What does it do?
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
not.
`SITENAME` (``'A Pelican Blog'``) Your site name
`SITEURL` Base URL of your website. Note that this is
not a way to tell Pelican whether to use relative URLs
or static ones. You should instead use the
`RELATIVE_URL` setting for that purpose.
`SITEURL` Base URL of your website. Not defined by default,
which means the base URL is assumed to be "/" with a
root-relative URL structure. If `SITEURL` is specified
explicitly, URLs will be generated with an absolute
URL structure (including the domain). If you want to
use relative URLs instead of root-relative or absolute
URLs, you should instead use the `RELATIVE_URL` setting.
`STATIC_PATHS` (``['images']``) The static paths you want to have accessible
on the output path "static". By default,
Pelican will copy the 'images' folder to the
@ -86,10 +89,10 @@ Setting name (default value) What does it do?
URL settings
------------
You can customize the URL's and locations where files will be saved. The URL's and
SAVE_AS variables use python's format strings. These variables allow you to place
your articles in a location such as '{slug}/index.html' and link to then as
'{slug}' for clean urls. These settings give you the flexibility to place your
You can customize the URLs and locations where files will be saved. The URLs and
SAVE_AS variables use Python's format strings. These variables allow you to place
your articles in a location such as '{slug}/index.html' and link to them as
'{slug}' for clean URLs. These settings give you the flexibility to place your
articles and pages anywhere you want.
Note: If you specify a datetime directive, it will be substituted using the
@ -216,15 +219,26 @@ the ``TAG_FEED`` and ``TAG_FEED_RSS`` settings:
================================================ =====================================================
Setting name (default value) What does it do?
================================================ =====================================================
`CATEGORY_FEED` ('feeds/%s.atom.xml'[2]_) Where to put the category Atom feeds.
`CATEGORY_FEED_RSS` (``None``, i.e. no RSS) Where to put the category RSS feeds.
`FEED_DOMAIN` (``None``, i.e. base URL is "/") The domain prepended to feed URLs. Since feed URLs
should always be absolute, it is highly recommended
to define this (e.g., "http://feeds.example.com"). If
you have already explicitly defined SITEURL (see
above) and want to use the same domain for your
feeds, you can just set: `FEED_DOMAIN = SITEURL`
`FEED` (``'feeds/all.atom.xml'``) Relative URL to output the Atom feed.
`FEED_RSS` (``None``, i.e. no RSS) Relative URL to output the RSS feed.
`TAG_FEED` (``None``, ie no tag feed) Relative URL to output the tag Atom feed. It should
`CATEGORY_FEED` ('feeds/%s.atom.xml'[2]_) Where to put the category Atom feeds.
`CATEGORY_FEED_RSS` (``None``, i.e. no RSS) Where to put the category RSS feeds.
`TAG_FEED` (``None``, i.e. no tag feed) Relative URL to output the tag Atom feed. It should
be defined using a "%s" match in the tag name.
`TAG_FEED_RSS` (``None``, ie no RSS tag feed) Relative URL to output the tag RSS feed
`FEED_MAX_ITEMS` Maximum number of items allowed in a feed. Feed item
quantity is unrestricted by default.
`FEED_MAIN_URL` (``'feeds/all.atom.xml'``) URL appended to domain for the main Atom feed and
used to populate its `<link>` in the base template.
Useful when you want the feed link to differ from the
filesystem path, such as when using web server
aliases/rewrites or FeedBurner (see below).
================================================ =====================================================
If you don't want to generate some of these feeds, set ``None`` to the
@ -232,6 +246,25 @@ variables above.
.. [2] %s is the name of the category.
FeedBurner
----------
If you want to use FeedBurner for your primary Atom feed, there are two
primary fields to configure in the `FeedBurner
<http://feedburner.google.com>`_ interface: "Original Feed" and "Feed Address".
If using the default Pelican `FEED` attribute and assuming your feeds
are served from the `www.example.com` domain, you would enter
`http://www.example.com/feeds/all.atom.xml` in the "Original Feed" field in
FeedBurner.
For the "Feed Address" field in the FeedBurner interface, you may choose
whatever suffix you prefer. In your Pelican settings, assign this suffix to
the `FEED_MAIN_URL` setting. So if your FeedBurner feed address is set to
`http://feeds.feedburner.com/myblogfeed`, in your Pelican settings you would
set: `FEED_MAIN_URL = "myblogfeed"`. Then set the `FEED_DOMAIN` setting to
`http://feeds.feedburner.com`, or `http://feeds.example.com` if you are using
a CNAME on your own domain (i.e., FeedBurner's "MyBrand" feature).
Pagination
==========

View file

@ -22,6 +22,7 @@ _DEFAULT_CONFIG = {'PATH': None,
'STATIC_PATHS': ['images', ],
'THEME_STATIC_PATHS': ['static', ],
'FEED': 'feeds/all.atom.xml',
'FEED_MAIN_URL': 'feeds/all.atom.xml',
'CATEGORY_FEED': 'feeds/%s.atom.xml',
'TRANSLATION_FEED': 'feeds/all-%s.atom.xml',
'FEED_MAX_ITEMS': '',
@ -71,26 +72,45 @@ _DEFAULT_CONFIG = {'PATH': None,
def read_settings(filename=None):
if filename:
local_settings = get_settings_from_file(filename)
else:
local_settings = _DEFAULT_CONFIG
configured_settings = configure_settings(local_settings, None, filename)
return configured_settings
def get_settings_from_file(filename, default_settings=None):
"""Load a Python file into a dictionary.
"""
context = _DEFAULT_CONFIG.copy()
if default_settings == None:
default_settings = _DEFAULT_CONFIG
context = default_settings.copy()
if filename:
tempdict = {}
execfile(filename, tempdict)
for key in tempdict:
if key.isupper():
context[key] = tempdict[key]
return context
# Make the paths relative to the settings file
def configure_settings(settings, default_settings=None, filename=None):
"""Provide optimizations, error checking, and warnings for loaded settings"""
if default_settings is None:
default_settings = _DEFAULT_CONFIG
# Make the paths relative to the settings file
if filename:
for path in ['PATH', 'OUTPUT_PATH']:
if path in context:
if context[path] is not None and not isabs(context[path]):
context[path] = os.path.abspath(os.path.normpath(
os.path.join(os.path.dirname(filename), context[path]))
if path in settings:
if settings[path] is not None and not isabs(settings[path]):
settings[path] = os.path.abspath(os.path.normpath(
os.path.join(os.path.dirname(filename), settings[path]))
)
# if locales is not a list, make it one
locales = context['LOCALE']
locales = settings['LOCALE']
if isinstance(locales, basestring):
locales = [locales]
@ -108,11 +128,20 @@ def read_settings(filename=None):
else:
logger.warn("LOCALE option doesn't contain a correct value")
if not 'TIMEZONE' in context:
# If SITEURL is defined but FEED_DOMAIN isn't, set FEED_DOMAIN = SITEURL
if ('SITEURL' in settings) and (not 'FEED_DOMAIN' in settings):
settings['FEED_DOMAIN'] = settings['SITEURL']
# Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined
if (('FEED' in settings) or ('FEED_RSS' in settings)) and (not 'FEED_DOMAIN' in settings):
logger.warn("Since feed URLs should always be absolute, you should specify "
"FEED_DOMAIN in your settings. (e.g., 'FEED_DOMAIN = "
"http://www.example.com')")
if not 'TIMEZONE' in settings:
logger.warn("No timezone information specified in the settings. Assuming"
" your timezone is UTC for feed generation. Check "
"http://docs.notmyidea.org/alexis/pelican/settings.html#timezone "
"for more information")
# set the locale
return context
return settings

View file

@ -26,8 +26,6 @@ body {
text-align: left;
}
/* Headings */
h1 {font-size: 2em }
h2 {font-size: 1.571em} /* 22px */
@ -304,7 +302,7 @@ img.left, figure.left {float: right; margin: 0 0 2em 2em;}
.social a[href*='digg.com'] {background-image: url('../images/icons/digg.png');}
.social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.png');}
.social a[href*='last.fm'], .social a[href*='lastfm.'] {background-image: url('../images/icons/lastfm.png');}
.social a[href*='atom.xml'] {background-image: url('../images/icons/rss.png');}
.social a[type$='atom+xml'], .social a[type$='rss+xml'] {background-image: url('../images/icons/rss.png');}
.social a[href*='twitter.com'] {background-image: url('../images/icons/twitter.png');}
.social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');}

View file

@ -4,9 +4,9 @@
<title>{% block title %}{{ SITENAME }}{%endblock%}</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/{{ CSS_FILE }}" type="text/css" />
<link href="{{ SITEURL }}/{{ FEED }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} ATOM Feed" />
<link href="{{ FEED_DOMAIN }}/{{ FEED_MAIN_URL }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} Atom Feed" />
{% if FEED_RSS %}
<link href="{{ SITEURL }}/{{ FEED_RSS }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} RSS Feed" />
<link href="{{ FEED_DOMAIN }}/{{ FEED_RSS }}" type="application/rss+xml" rel="alternate" title="{{ SITENAME }} RSS Feed" />
{% endif %}
<!--[if IE]>
@ -56,9 +56,9 @@
<div class="social">
<h2>social</h2>
<ul>
<li><a href="{{ SITEURL }}/{{ FEED }}" rel="alternate">atom feed</a></li>
<li><a href="{{ FEED_DOMAIN }}/{{ FEED_MAIN_URL }}" type="application/atom+xml" rel="alternate">atom feed</a></li>
{% if FEED_RSS %}
<li><a href="{{ SITEURL }}/{{ FEED_RSS }}" rel="alternate">rss feed</a></li>
<li><a href="{{ FEED_DOMAIN }}/{{ FEED_RSS }}" type="application/rss+xml" rel="alternate">rss feed</a></li>
{% endif %}
{% for name, link in SOCIAL %}

View file

@ -29,7 +29,7 @@ SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
DEFAULT_METADATA = (('yeah', 'it is'),)
# static paths will be copied under the same name
STATIC_PATHS = ["pictures",]
STATIC_PATHS = ["pictures", ]
# A list of files to copy from the source to the destination
FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),)
@ -37,4 +37,3 @@ FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),)
# foobar will not be used, because it's not in caps. All configuration keys
# have to be in caps
foobar = "barbaz"

View file

@ -1,12 +1,13 @@
from os.path import dirname, abspath, join
from pelican.settings import read_settings, _DEFAULT_CONFIG
from pelican.settings import read_settings, configure_settings, _DEFAULT_CONFIG
from .support import unittest
class TestSettingsFromFile(unittest.TestCase):
"""Providing a file, it should read it, replace the default values and
append new values to the settings, if any
class TestSettingsConfiguration(unittest.TestCase):
"""Provided a file, it should read it, replace the default values,
append new values to the settings (if any), and apply basic settings
optimizations.
"""
def setUp(self):
self.PATH = abspath(dirname(__file__))
@ -31,3 +32,15 @@ class TestSettingsFromFile(unittest.TestCase):
"""providing no file should return the default values."""
settings = read_settings(None)
self.assertDictEqual(settings, _DEFAULT_CONFIG)
def test_configure_settings(self):
"""Manipulations to settings should be applied correctly."""
# FEED_DOMAIN, if undefined, should default to SITEURL
settings = {'SITEURL': 'http://blog.notmyidea.org', 'LOCALE': ''}
configure_settings(settings)
self.assertEqual(settings['FEED_DOMAIN'], 'http://blog.notmyidea.org')
settings = {'FEED_DOMAIN': 'http://feeds.example.com', 'LOCALE': ''}
configure_settings(settings)
self.assertEqual(settings['FEED_DOMAIN'], 'http://feeds.example.com')