mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Merge pull request #262 from justinmayer/feeddomain
Allow for serving feeds from a separate domain.
This commit is contained in:
commit
38b5b94617
6 changed files with 106 additions and 34 deletions
|
|
@ -62,10 +62,13 @@ Setting name (default value) What does it do?
|
||||||
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
|
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
|
||||||
not.
|
not.
|
||||||
`SITENAME` (``'A Pelican Blog'``) Your site name
|
`SITENAME` (``'A Pelican Blog'``) Your site name
|
||||||
`SITEURL` Base URL of your website. Note that this is
|
`SITEURL` Base URL of your website. Not defined by default,
|
||||||
not a way to tell Pelican whether to use relative URLs
|
which means the base URL is assumed to be "/" with a
|
||||||
or static ones. You should instead use the
|
root-relative URL structure. If `SITEURL` is specified
|
||||||
`RELATIVE_URL` setting for that purpose.
|
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
|
`STATIC_PATHS` (``['images']``) The static paths you want to have accessible
|
||||||
on the output path "static". By default,
|
on the output path "static". By default,
|
||||||
Pelican will copy the 'images' folder to the
|
Pelican will copy the 'images' folder to the
|
||||||
|
|
@ -86,10 +89,10 @@ Setting name (default value) What does it do?
|
||||||
URL settings
|
URL settings
|
||||||
------------
|
------------
|
||||||
|
|
||||||
You can customize the URL's and locations where files will be saved. The URL's and
|
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
|
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
|
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
|
'{slug}' for clean URLs. These settings give you the flexibility to place your
|
||||||
articles and pages anywhere you want.
|
articles and pages anywhere you want.
|
||||||
|
|
||||||
Note: If you specify a datetime directive, it will be substituted using the
|
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?
|
Setting name (default value) What does it do?
|
||||||
================================================ =====================================================
|
================================================ =====================================================
|
||||||
`CATEGORY_FEED` ('feeds/%s.atom.xml'[2]_) Where to put the category Atom feeds.
|
`FEED_DOMAIN` (``None``, i.e. base URL is "/") The domain prepended to feed URLs. Since feed URLs
|
||||||
`CATEGORY_FEED_RSS` (``None``, i.e. no RSS) Where to put the category RSS feeds.
|
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` (``'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.
|
`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.
|
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
|
`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
|
`FEED_MAX_ITEMS` Maximum number of items allowed in a feed. Feed item
|
||||||
quantity is unrestricted by default.
|
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
|
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.
|
.. [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
|
Pagination
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ _DEFAULT_CONFIG = {'PATH': None,
|
||||||
'STATIC_PATHS': ['images', ],
|
'STATIC_PATHS': ['images', ],
|
||||||
'THEME_STATIC_PATHS': ['static', ],
|
'THEME_STATIC_PATHS': ['static', ],
|
||||||
'FEED': 'feeds/all.atom.xml',
|
'FEED': 'feeds/all.atom.xml',
|
||||||
|
'FEED_MAIN_URL': 'feeds/all.atom.xml',
|
||||||
'CATEGORY_FEED': 'feeds/%s.atom.xml',
|
'CATEGORY_FEED': 'feeds/%s.atom.xml',
|
||||||
'TRANSLATION_FEED': 'feeds/all-%s.atom.xml',
|
'TRANSLATION_FEED': 'feeds/all-%s.atom.xml',
|
||||||
'FEED_MAX_ITEMS': '',
|
'FEED_MAX_ITEMS': '',
|
||||||
|
|
@ -71,26 +72,45 @@ _DEFAULT_CONFIG = {'PATH': None,
|
||||||
|
|
||||||
|
|
||||||
def read_settings(filename=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.
|
"""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:
|
if filename:
|
||||||
tempdict = {}
|
tempdict = {}
|
||||||
execfile(filename, tempdict)
|
execfile(filename, tempdict)
|
||||||
for key in tempdict:
|
for key in tempdict:
|
||||||
if key.isupper():
|
if key.isupper():
|
||||||
context[key] = tempdict[key]
|
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']:
|
for path in ['PATH', 'OUTPUT_PATH']:
|
||||||
if path in context:
|
if path in settings:
|
||||||
if context[path] is not None and not isabs(context[path]):
|
if settings[path] is not None and not isabs(settings[path]):
|
||||||
context[path] = os.path.abspath(os.path.normpath(
|
settings[path] = os.path.abspath(os.path.normpath(
|
||||||
os.path.join(os.path.dirname(filename), context[path]))
|
os.path.join(os.path.dirname(filename), settings[path]))
|
||||||
)
|
)
|
||||||
|
|
||||||
# if locales is not a list, make it one
|
# if locales is not a list, make it one
|
||||||
locales = context['LOCALE']
|
locales = settings['LOCALE']
|
||||||
|
|
||||||
if isinstance(locales, basestring):
|
if isinstance(locales, basestring):
|
||||||
locales = [locales]
|
locales = [locales]
|
||||||
|
|
@ -108,11 +128,20 @@ def read_settings(filename=None):
|
||||||
else:
|
else:
|
||||||
logger.warn("LOCALE option doesn't contain a correct value")
|
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"
|
logger.warn("No timezone information specified in the settings. Assuming"
|
||||||
" your timezone is UTC for feed generation. Check "
|
" your timezone is UTC for feed generation. Check "
|
||||||
"http://docs.notmyidea.org/alexis/pelican/settings.html#timezone "
|
"http://docs.notmyidea.org/alexis/pelican/settings.html#timezone "
|
||||||
"for more information")
|
"for more information")
|
||||||
|
|
||||||
# set the locale
|
return settings
|
||||||
return context
|
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,6 @@ body {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Headings */
|
/* Headings */
|
||||||
h1 {font-size: 2em }
|
h1 {font-size: 2em }
|
||||||
h2 {font-size: 1.571em} /* 22px */
|
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*='digg.com'] {background-image: url('../images/icons/digg.png');}
|
||||||
.social a[href*='facebook.com'] {background-image: url('../images/icons/facebook.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*='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*='twitter.com'] {background-image: url('../images/icons/twitter.png');}
|
||||||
.social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');}
|
.social a[href*='linkedin.com'] {background-image: url('../images/icons/linkedin.png');}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
<title>{% block title %}{{ SITENAME }}{%endblock%}</title>
|
<title>{% block title %}{{ SITENAME }}{%endblock%}</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/{{ CSS_FILE }}" type="text/css" />
|
<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 %}
|
{% 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 %}
|
{% endif %}
|
||||||
|
|
||||||
<!--[if IE]>
|
<!--[if IE]>
|
||||||
|
|
@ -56,9 +56,9 @@
|
||||||
<div class="social">
|
<div class="social">
|
||||||
<h2>social</h2>
|
<h2>social</h2>
|
||||||
<ul>
|
<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 %}
|
{% 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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% for name, link in SOCIAL %}
|
{% for name, link in SOCIAL %}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
|
||||||
DEFAULT_METADATA = (('yeah', 'it is'),)
|
DEFAULT_METADATA = (('yeah', 'it is'),)
|
||||||
|
|
||||||
# static paths will be copied under the same name
|
# 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
|
# A list of files to copy from the source to the destination
|
||||||
FILES_TO_COPY = (('extra/robots.txt', 'robots.txt'),)
|
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
|
# foobar will not be used, because it's not in caps. All configuration keys
|
||||||
# have to be in caps
|
# have to be in caps
|
||||||
foobar = "barbaz"
|
foobar = "barbaz"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
from os.path import dirname, abspath, join
|
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
|
from .support import unittest
|
||||||
|
|
||||||
|
|
||||||
class TestSettingsFromFile(unittest.TestCase):
|
class TestSettingsConfiguration(unittest.TestCase):
|
||||||
"""Providing a file, it should read it, replace the default values and
|
"""Provided a file, it should read it, replace the default values,
|
||||||
append new values to the settings, if any
|
append new values to the settings (if any), and apply basic settings
|
||||||
|
optimizations.
|
||||||
"""
|
"""
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.PATH = abspath(dirname(__file__))
|
self.PATH = abspath(dirname(__file__))
|
||||||
|
|
@ -31,3 +32,15 @@ class TestSettingsFromFile(unittest.TestCase):
|
||||||
"""providing no file should return the default values."""
|
"""providing no file should return the default values."""
|
||||||
settings = read_settings(None)
|
settings = read_settings(None)
|
||||||
self.assertDictEqual(settings, _DEFAULT_CONFIG)
|
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')
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue