mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Merge branch 'master' of github.com:ametaireau/pelican into fix-functional-tests
This commit is contained in:
commit
4ce5adb2a0
15 changed files with 338 additions and 123 deletions
11
docs/faq.rst
11
docs/faq.rst
|
|
@ -49,3 +49,14 @@ install it. You can do so by typing::
|
||||||
In case you don't have pip installed, consider installing it via::
|
In case you don't have pip installed, consider installing it via::
|
||||||
|
|
||||||
$ (sudo) easy_install pip
|
$ (sudo) easy_install pip
|
||||||
|
|
||||||
|
How do I assign custom templates on a per page basis?
|
||||||
|
=====================================================
|
||||||
|
|
||||||
|
It's as simple as adding an extra line of metadata to any pages or articles you
|
||||||
|
want to have it's own template.
|
||||||
|
|
||||||
|
:template: template_name
|
||||||
|
|
||||||
|
Then just make sure to have the template installed in to your theme as
|
||||||
|
``template_name.html``.
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
Getting started
|
Getting started
|
||||||
###############
|
###############
|
||||||
|
|
||||||
Installing
|
Installing Pelican
|
||||||
==========
|
==================
|
||||||
|
|
||||||
You're ready? Let's go! You can install Pelican via several different methods.
|
You're ready? Let's go! You can install Pelican via several different methods.
|
||||||
The simplest is via `pip <http://www.pip-installer.org/>`_::
|
The simplest is via `pip <http://www.pip-installer.org/>`_::
|
||||||
|
|
||||||
$ pip install pelican
|
$ pip install pelican
|
||||||
|
|
||||||
If you don't have pip installed, an alternative method is easy_install::
|
If you don't have ``pip`` installed, an alternative method is ``easy_install``::
|
||||||
|
|
||||||
$ easy_install pelican
|
$ easy_install pelican
|
||||||
|
|
||||||
|
|
@ -18,12 +18,13 @@ a virtual environment for Pelican via `virtualenv <http://www.virtualenv.org/>`_
|
||||||
and `virtualenvwrapper <http://www.doughellmann.com/projects/virtualenvwrapper/>`_
|
and `virtualenvwrapper <http://www.doughellmann.com/projects/virtualenvwrapper/>`_
|
||||||
before installing Pelican::
|
before installing Pelican::
|
||||||
|
|
||||||
$ pip install virtualenvwrapper
|
$ sudo pip install --upgrade virtualenv virtualenvwrapper
|
||||||
$ mkvirtualenv pelican
|
$ mkvirtualenv pelican
|
||||||
|
$ pip install pelican
|
||||||
|
|
||||||
Once the virtual environment has been created and activated, Pelican can be
|
Once the virtual environment has been created and activated, Pelican can be
|
||||||
be installed via pip or easy_install as noted above. Alternatively, if you
|
be installed via ``pip`` or ``easy_install`` as noted above. Alternatively, if
|
||||||
have the project source, you can install Pelican using the distutils
|
you have the project source, you can install Pelican using the distutils
|
||||||
method::
|
method::
|
||||||
|
|
||||||
$ cd path-to-Pelican-source
|
$ cd path-to-Pelican-source
|
||||||
|
|
@ -34,6 +35,11 @@ version of Pelican rather than a stable release, use the following command::
|
||||||
|
|
||||||
$ pip install -e git://github.com/ametaireau/pelican#egg=pelican
|
$ pip install -e git://github.com/ametaireau/pelican#egg=pelican
|
||||||
|
|
||||||
|
If you plan on using Markdown as a markup format, you'll need to install the
|
||||||
|
Markdown library as well::
|
||||||
|
|
||||||
|
$ pip install Markdown
|
||||||
|
|
||||||
Upgrading
|
Upgrading
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|
@ -62,6 +68,59 @@ Optionally:
|
||||||
* pygments, for syntax highlighting
|
* pygments, for syntax highlighting
|
||||||
* Markdown, for supporting Markdown as an input format
|
* Markdown, for supporting Markdown as an input format
|
||||||
|
|
||||||
|
Kickstart a blog
|
||||||
|
================
|
||||||
|
|
||||||
|
Following is a brief tutorial for those who want to get started right away.
|
||||||
|
We're going to assume Pelican was installed in a virtual environment via the
|
||||||
|
following steps (if you're not using a virtual environment for Pelican, you can
|
||||||
|
skip to the ``pelican-quickstart`` command)::
|
||||||
|
|
||||||
|
$ sudo pip install --upgrade virtualenv virtualenvwrapper
|
||||||
|
$ mkvirtualenv pelican
|
||||||
|
$ pip install pelican Markdown
|
||||||
|
|
||||||
|
Next we'll create a directory to house our site content and configuration files,
|
||||||
|
which can be located any place you prefer, and associate this new project with
|
||||||
|
the currently-active virtual environment::
|
||||||
|
|
||||||
|
$ mkdir ~/code/yoursitename
|
||||||
|
$ cd ~/code/yoursitename
|
||||||
|
$ setvirtualenvproject
|
||||||
|
|
||||||
|
Now we can run the ``pelican-quickstart`` command, which will ask some questions
|
||||||
|
about your site::
|
||||||
|
|
||||||
|
$ pelican-quickstart
|
||||||
|
|
||||||
|
Once you finish answering all the questions, you can begin adding content to the
|
||||||
|
*content* folder that has been created for you. (See *Writing articles using
|
||||||
|
Pelican* section below for more information about how to format your content.)
|
||||||
|
Once you have some content to generate, you can convert it to HTML via the
|
||||||
|
following command::
|
||||||
|
|
||||||
|
$ make html
|
||||||
|
|
||||||
|
If you'd prefer to have Pelican automatically regenerate your site every time a
|
||||||
|
change is detected (handy when testing locally), use the following command
|
||||||
|
instead::
|
||||||
|
|
||||||
|
$ make regenerate
|
||||||
|
|
||||||
|
To serve the site so it can be previewed in your browser::
|
||||||
|
|
||||||
|
$ make serve
|
||||||
|
|
||||||
|
Visit http://localhost:8000 in your browser to see your site.
|
||||||
|
|
||||||
|
When you're ready to publish your site, you can upload it via the method(s) you
|
||||||
|
chose during the ``pelican-quickstart`` questionnaire. For this example, we'll
|
||||||
|
use rsync over ssh::
|
||||||
|
|
||||||
|
$ make rsync_upload
|
||||||
|
|
||||||
|
That's it! Your site should now be live.
|
||||||
|
|
||||||
Writing articles using Pelican
|
Writing articles using Pelican
|
||||||
==============================
|
==============================
|
||||||
|
|
||||||
|
|
@ -83,7 +142,6 @@ following syntax (give your file the ``.rst`` extension)::
|
||||||
:category: yeah
|
:category: yeah
|
||||||
:author: Alexis Metaireau
|
:author: Alexis Metaireau
|
||||||
|
|
||||||
|
|
||||||
You can also use Markdown syntax (with a file ending in ``.md``).
|
You can also use Markdown syntax (with a file ending in ``.md``).
|
||||||
Markdown generation will not work until you explicitly install the ``Markdown``
|
Markdown generation will not work until you explicitly install the ``Markdown``
|
||||||
package, which can be done via ``pip install Markdown``. Metadata syntax for
|
package, which can be done via ``pip install Markdown``. Metadata syntax for
|
||||||
|
|
@ -105,27 +163,28 @@ example, a file located at ``python/foobar/myfoobar.rst`` will have a category o
|
||||||
Generate your blog
|
Generate your blog
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
To launch Pelican, just use the ``pelican`` command::
|
The ``make`` shortcut commands mentioned in the ``Kickstart a blog`` section
|
||||||
|
are mostly wrappers around the ``pelican`` command that generates the HTML from
|
||||||
|
the content. The ``pelican`` command can also be run directly::
|
||||||
|
|
||||||
$ pelican /path/to/your/content/ [-s path/to/your/settings.py]
|
$ pelican /path/to/your/content/ [-s path/to/your/settings.py]
|
||||||
|
|
||||||
And… that's all! Your weblog will be generated and saved in the ``content/``
|
The above command will generate your weblog and save it in the ``content/``
|
||||||
folder.
|
folder, using the default theme to produce a simple site. The default theme is
|
||||||
|
simple HTML without styling and is provided so folks may use it as a basis for
|
||||||
|
creating their own themes.
|
||||||
|
|
||||||
The above command will use the default theme to produce a simple site. It's not
|
Pelican has other command-line switches available. Have a look at the help to
|
||||||
very sexy, as it's just simple HTML output (without any style).
|
see all the options you can use::
|
||||||
|
|
||||||
You can create your own style if you want. Have a look at the help to see all
|
|
||||||
the options you can use::
|
|
||||||
|
|
||||||
$ pelican --help
|
$ pelican --help
|
||||||
|
|
||||||
Kickstart a blog
|
Auto-reload
|
||||||
----------------
|
-----------
|
||||||
|
|
||||||
You also can use the ``pelican-quickstart`` script to start a new blog in
|
It's possible to tell Pelican to watch for your modifications, instead of
|
||||||
seconds by just answering a few questions. Just run ``pelican-quickstart`` and
|
manually re-running it every time you want to see your changes. To enable this,
|
||||||
you're done! (Added in Pelican 3.0)
|
run the ``pelican`` command with the ``-r`` or ``--autoreload`` option.
|
||||||
|
|
||||||
Pages
|
Pages
|
||||||
-----
|
-----
|
||||||
|
|
@ -209,13 +268,6 @@ For Markdown, format your code blocks thusly::
|
||||||
The specified identifier should be one that appears on the
|
The specified identifier should be one that appears on the
|
||||||
`list of available lexers <http://pygments.org/docs/lexers/>`_.
|
`list of available lexers <http://pygments.org/docs/lexers/>`_.
|
||||||
|
|
||||||
Auto-reload
|
|
||||||
-----------
|
|
||||||
|
|
||||||
It's possible to tell Pelican to watch for your modifications, instead of
|
|
||||||
manually re-running it every time you want to see your changes. To enable this,
|
|
||||||
run the ``pelican`` command with the ``-r`` or ``--autoreload`` option.
|
|
||||||
|
|
||||||
Publishing drafts
|
Publishing drafts
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,18 +63,16 @@ Setting name (default value) What doe
|
||||||
`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions
|
`PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions
|
||||||
of your documents. You will need to install
|
of your documents. You will need to install
|
||||||
`rst2pdf`.
|
`rst2pdf`.
|
||||||
`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or
|
`RELATIVE_URLS` (``True``) Defines whether Pelican should use document-relative URLs or
|
||||||
not.
|
not. If set to ``False``, Pelican will use the SITEURL
|
||||||
|
setting to construct absolute URLs.
|
||||||
`PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`.
|
`PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`.
|
||||||
`SITENAME` (``'A Pelican Blog'``) Your site name
|
`SITENAME` (``'A Pelican Blog'``) Your site name
|
||||||
`SITEURL` Base URL of your website. Not defined by default,
|
`SITEURL` Base URL of your website. Not defined by default,
|
||||||
which means the base URL is assumed to be "/" with a
|
so it is best to specify your SITEURL; if you do not, feeds
|
||||||
root-relative URL structure. If `SITEURL` is specified
|
will not be generated with properly-formed URLs. You should
|
||||||
explicitly, there should be no trailing slash at the end,
|
include ``http://`` and your domain, with no trailing
|
||||||
and URLs will be generated with an absolute URL structure
|
slash at the end. Example: ``SITEURL = 'http://mydomain.com'``
|
||||||
(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
|
||||||
|
|
@ -111,6 +109,15 @@ Setting name (default value) What doe
|
||||||
URL settings
|
URL settings
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
The first thing to understand is that there are currently two supported methods
|
||||||
|
for URL formation: *relative* and *absolute*. Document-relative URLs are useful
|
||||||
|
when testing locally, and absolute URLs are reliable and most useful when
|
||||||
|
publishing. One method of supporting both is to have one Pelican configuration
|
||||||
|
file for local development and another for publishing. To see an example of this
|
||||||
|
type of setup, use the ``pelican-quickstart`` script as described at the top of
|
||||||
|
the :doc:`Getting Started<getting_started>` page, which will produce two separate
|
||||||
|
configuration files for local development and publishing, respectively.
|
||||||
|
|
||||||
You can customize the URLs and locations where files will be saved. The URLs 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 them as
|
your articles in a location such as '{slug}/index.html' and link to them as
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class Page(object):
|
||||||
:param content: the string to parse, containing the original content.
|
:param content: the string to parse, containing the original content.
|
||||||
"""
|
"""
|
||||||
mandatory_properties = ('title',)
|
mandatory_properties = ('title',)
|
||||||
|
default_template = 'page'
|
||||||
|
|
||||||
def __init__(self, content, metadata=None, settings=None,
|
def __init__(self, content, metadata=None, settings=None,
|
||||||
filename=None):
|
filename=None):
|
||||||
|
|
@ -44,6 +45,9 @@ class Page(object):
|
||||||
# also keep track of the metadata attributes available
|
# also keep track of the metadata attributes available
|
||||||
self.metadata = local_metadata
|
self.metadata = local_metadata
|
||||||
|
|
||||||
|
#default template if it's not defined in page
|
||||||
|
self.template = self._get_template()
|
||||||
|
|
||||||
# default author to the one in settings if not defined
|
# default author to the one in settings if not defined
|
||||||
if not hasattr(self, 'author'):
|
if not hasattr(self, 'author'):
|
||||||
if 'AUTHOR' in settings:
|
if 'AUTHOR' in settings:
|
||||||
|
|
@ -153,9 +157,16 @@ class Page(object):
|
||||||
url = property(functools.partial(get_url_setting, key='url'))
|
url = property(functools.partial(get_url_setting, key='url'))
|
||||||
save_as = property(functools.partial(get_url_setting, key='save_as'))
|
save_as = property(functools.partial(get_url_setting, key='save_as'))
|
||||||
|
|
||||||
|
def _get_template(self):
|
||||||
|
if hasattr(self, 'template') and self.template is not None:
|
||||||
|
return self.template
|
||||||
|
else:
|
||||||
|
return self.default_template
|
||||||
|
|
||||||
|
|
||||||
class Article(Page):
|
class Article(Page):
|
||||||
mandatory_properties = ('title', 'date', 'category')
|
mandatory_properties = ('title', 'date', 'category')
|
||||||
|
default_template = 'article'
|
||||||
|
|
||||||
|
|
||||||
class Quote(Page):
|
class Quote(Page):
|
||||||
|
|
|
||||||
|
|
@ -167,11 +167,9 @@ class ArticlesGenerator(Generator):
|
||||||
|
|
||||||
def generate_articles(self, write):
|
def generate_articles(self, write):
|
||||||
"""Generate the articles."""
|
"""Generate the articles."""
|
||||||
article_template = self.get_template('article')
|
|
||||||
for article in chain(self.translations, self.articles):
|
for article in chain(self.translations, self.articles):
|
||||||
write(article.save_as,
|
write(article.save_as, self.get_template(article.template),
|
||||||
article_template, self.context, article=article,
|
self.context, article=article, category=article.category)
|
||||||
category=article.category)
|
|
||||||
|
|
||||||
def generate_direct_templates(self, write):
|
def generate_direct_templates(self, write):
|
||||||
"""Generate direct templates pages"""
|
"""Generate direct templates pages"""
|
||||||
|
|
@ -222,10 +220,10 @@ class ArticlesGenerator(Generator):
|
||||||
|
|
||||||
def generate_drafts(self, write):
|
def generate_drafts(self, write):
|
||||||
"""Generate drafts pages."""
|
"""Generate drafts pages."""
|
||||||
article_template = self.get_template('article')
|
|
||||||
for article in self.drafts:
|
for article in self.drafts:
|
||||||
write('drafts/%s.html' % article.slug, article_template,
|
write('drafts/%s.html' % article.slug,
|
||||||
self.context, article=article, category=article.category)
|
self.get_template(article.template), self.context,
|
||||||
|
article=article, category=article.category)
|
||||||
|
|
||||||
def generate_pages(self, writer):
|
def generate_pages(self, writer):
|
||||||
"""Generate the pages on the disk"""
|
"""Generate the pages on the disk"""
|
||||||
|
|
@ -389,7 +387,6 @@ class PagesGenerator(Generator):
|
||||||
(repr(unicode.encode(page.status, 'utf-8')),
|
(repr(unicode.encode(page.status, 'utf-8')),
|
||||||
repr(f)))
|
repr(f)))
|
||||||
|
|
||||||
|
|
||||||
self.pages, self.translations = process_translations(all_pages)
|
self.pages, self.translations = process_translations(all_pages)
|
||||||
self.hidden_pages, self.hidden_translations = process_translations(hidden_pages)
|
self.hidden_pages, self.hidden_translations = process_translations(hidden_pages)
|
||||||
|
|
||||||
|
|
@ -399,7 +396,7 @@ class PagesGenerator(Generator):
|
||||||
def generate_output(self, writer):
|
def generate_output(self, writer):
|
||||||
for page in chain(self.translations, self.pages,
|
for page in chain(self.translations, self.pages,
|
||||||
self.hidden_translations, self.hidden_pages):
|
self.hidden_translations, self.hidden_pages):
|
||||||
writer.write_file(page.save_as, self.get_template('page'),
|
writer.write_file(page.save_as, self.get_template(page.template),
|
||||||
self.context, page=page,
|
self.context, page=page,
|
||||||
relative_urls=self.settings.get('RELATIVE_URLS'))
|
relative_urls=self.settings.get('RELATIVE_URLS'))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,13 @@ CONF = {
|
||||||
'ftp_host': 'localhost',
|
'ftp_host': 'localhost',
|
||||||
'ftp_user': 'anonymous',
|
'ftp_user': 'anonymous',
|
||||||
'ftp_target_dir': '/',
|
'ftp_target_dir': '/',
|
||||||
'ssh_host': 'locahost',
|
'ssh_host': 'localhost',
|
||||||
|
'ssh_port': 22,
|
||||||
'ssh_user': 'root',
|
'ssh_user': 'root',
|
||||||
'ssh_target_dir': '/var/www',
|
'ssh_target_dir': '/var/www',
|
||||||
'dropbox_dir' : '~/Dropbox/Public/',
|
'dropbox_dir' : '~/Dropbox/Public/',
|
||||||
'default_pagination' : 10,
|
'default_pagination' : 10,
|
||||||
|
'siteurl': '',
|
||||||
'lang': 'en'
|
'lang': 'en'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,7 +90,7 @@ def ask(question, answer=str, default=None, l=None):
|
||||||
r = default
|
r = default
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
print("You must answer `yes' or `no'")
|
print("You must answer 'yes' or 'no'")
|
||||||
return r
|
return r
|
||||||
elif answer == int:
|
elif answer == int:
|
||||||
r = None
|
r = None
|
||||||
|
|
@ -111,12 +113,12 @@ def ask(question, answer=str, default=None, l=None):
|
||||||
print('You must enter an integer')
|
print('You must enter an integer')
|
||||||
return r
|
return r
|
||||||
else:
|
else:
|
||||||
raise NotImplemented('Arguent `answer` must be str, bool or integer')
|
raise NotImplemented('Argument `answer` must be str, bool, or integer')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description="A kickstarter for pelican",
|
description="A kickstarter for Pelican",
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
parser.add_argument('-p', '--path', default=".",
|
parser.add_argument('-p', '--path', default=".",
|
||||||
help="The path to generate the blog into")
|
help="The path to generate the blog into")
|
||||||
|
|
@ -125,7 +127,7 @@ def main():
|
||||||
parser.add_argument('-a', '--author', metavar="author",
|
parser.add_argument('-a', '--author', metavar="author",
|
||||||
help='Set the author name of the website')
|
help='Set the author name of the website')
|
||||||
parser.add_argument('-l', '--lang', metavar="lang",
|
parser.add_argument('-l', '--lang', metavar="lang",
|
||||||
help='Set the default lang of the website')
|
help='Set the default web site language')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
@ -137,36 +139,44 @@ Please answer the following questions so this script can generate the files need
|
||||||
|
|
||||||
'''.format(v=__version__))
|
'''.format(v=__version__))
|
||||||
|
|
||||||
CONF['basedir'] = os.path.abspath(ask('Where do you want to create your new Web site ?', answer=str, default=args.path))
|
project = os.path.join(os.environ['VIRTUAL_ENV'], '.project')
|
||||||
CONF['sitename'] = ask('What will be the title of this Web site ?', answer=str, default=args.title)
|
if os.path.isfile(project):
|
||||||
CONF['author'] = ask('Who will be the author of this Web site ?', answer=str, default=args.author)
|
CONF['basedir'] = open(project, 'r').read().rstrip("\n")
|
||||||
CONF['lang'] = ask('What will be the default language of this Web site ?', str, args.lang or CONF['lang'], 2)
|
print('Using project associated with current virtual environment. Will save to:\n%s\n' % CONF['basedir'])
|
||||||
|
else:
|
||||||
|
CONF['basedir'] = os.path.abspath(ask('Where do you want to create your new web site?', answer=str, default=args.path))
|
||||||
|
|
||||||
CONF['with_pagination'] = ask('Do you want to enable article pagination ?', bool, bool(CONF['default_pagination']))
|
CONF['sitename'] = ask('What will be the title of this web site?', answer=str, default=args.title)
|
||||||
|
CONF['author'] = ask('Who will be the author of this web site?', answer=str, default=args.author)
|
||||||
|
CONF['lang'] = ask('What will be the default language of this web site?', str, args.lang or CONF['lang'], 2)
|
||||||
|
|
||||||
|
if ask('Do you want to specify a URL prefix? e.g., http://example.com ', answer=bool, default=True):
|
||||||
|
CONF['siteurl'] = ask('What is your URL prefix? (see above example; no trailing slash)', str, CONF['siteurl'])
|
||||||
|
|
||||||
|
CONF['with_pagination'] = ask('Do you want to enable article pagination?', bool, bool(CONF['default_pagination']))
|
||||||
|
|
||||||
if CONF['with_pagination']:
|
if CONF['with_pagination']:
|
||||||
CONF['default_pagination'] = ask('So how many articles per page do you want ?', int, CONF['default_pagination'])
|
CONF['default_pagination'] = ask('How many articles per page do you want?', int, CONF['default_pagination'])
|
||||||
else:
|
else:
|
||||||
CONF['default_pagination'] = False
|
CONF['default_pagination'] = False
|
||||||
|
|
||||||
mkfile = ask('Do you want to generate a Makefile to easily manage your website ?', bool, True)
|
mkfile = ask('Do you want to generate a Makefile to easily manage your website?', bool, True)
|
||||||
|
|
||||||
if mkfile:
|
if mkfile:
|
||||||
if ask('Do you want to upload your website using FTP ?', answer=bool, default=False):
|
if ask('Do you want to upload your website using FTP?', answer=bool, default=False):
|
||||||
CONF['ftp_host'] = ask('What is the hostname of your FTP server ?', str, CONF['ftp_host'])
|
CONF['ftp_host'] = ask('What is the hostname of your FTP server?', str, CONF['ftp_host'])
|
||||||
CONF['ftp_user'] = ask('What is your username on this server ?', str, CONF['ftp_user'])
|
CONF['ftp_user'] = ask('What is your username on that server?', str, CONF['ftp_user'])
|
||||||
CONF['ftp_target_dir'] = ask('Where do you want to put your website on this server ?', str, CONF['ftp_target_dir'])
|
CONF['ftp_target_dir'] = ask('Where do you want to put your web site on that server?', str, CONF['ftp_target_dir'])
|
||||||
|
if ask('Do you want to upload your website using SSH?', answer=bool, default=False):
|
||||||
if ask('Do you want to upload your website using SSH ?', answer=bool, default=False):
|
CONF['ssh_host'] = ask('What is the hostname of your SSH server?', str, CONF['ssh_host'])
|
||||||
CONF['ssh_host'] = ask('What is the hostname of your SSH server ?', str, CONF['ssh_host'])
|
CONF['ssh_port'] = ask('What is the port of your SSH server?', int, CONF['ssh_port'])
|
||||||
CONF['ssh_user'] = ask('What is your username on this server ?', str, CONF['ssh_user'])
|
CONF['ssh_user'] = ask('What is your username on that server?', str, CONF['ssh_user'])
|
||||||
CONF['ssh_target_dir'] = ask('Where do you want to put your website on this server ?', str, CONF['ssh_target_dir'])
|
CONF['ssh_target_dir'] = ask('Where do you want to put your web site on that server?', str, CONF['ssh_target_dir'])
|
||||||
|
if ask('Do you want to upload your website using Dropbox?', answer=bool, default=False):
|
||||||
if ask('Do you want to upload your website using Dropbox ?', answer=bool, default=False):
|
CONF['dropbox_dir'] = ask('Where is your Dropbox directory?', str, CONF['dropbox_dir'])
|
||||||
CONF['dropbox_dir'] = ask('Where is your Dropbox directory ?', str, CONF['dropbox_dir'])
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.makedirs(os.path.join(CONF['basedir'], 'src'))
|
os.makedirs(os.path.join(CONF['basedir'], 'content'))
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
print('Error: {0}'.format(e))
|
print('Error: {0}'.format(e))
|
||||||
|
|
||||||
|
|
@ -176,8 +186,17 @@ Please answer the following questions so this script can generate the files need
|
||||||
print('Error: {0}'.format(e))
|
print('Error: {0}'.format(e))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(os.path.join(CONF['basedir'], 'pelican.conf.py'), 'w') as fd:
|
with open(os.path.join(CONF['basedir'], 'pelicanconf.py'), 'w') as fd:
|
||||||
for line in get_template('pelican.conf.py'):
|
for line in get_template('pelicanconf.py'):
|
||||||
|
template = string.Template(line)
|
||||||
|
fd.write(template.safe_substitute(CONF))
|
||||||
|
fd.close()
|
||||||
|
except OSError, e:
|
||||||
|
print('Error: {0}'.format(e))
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(os.path.join(CONF['basedir'], 'publishconf.py'), 'w') as fd:
|
||||||
|
for line in get_template('publishconf.py'):
|
||||||
template = string.Template(line)
|
template = string.Template(line)
|
||||||
fd.write(template.safe_substitute(CONF))
|
fd.write(template.safe_substitute(CONF))
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,17 @@ PELICAN=$pelican
|
||||||
PELICANOPTS=$pelicanopts
|
PELICANOPTS=$pelicanopts
|
||||||
|
|
||||||
BASEDIR=$$(PWD)
|
BASEDIR=$$(PWD)
|
||||||
INPUTDIR=$$(BASEDIR)/src
|
INPUTDIR=$$(BASEDIR)/content
|
||||||
OUTPUTDIR=$$(BASEDIR)/output
|
OUTPUTDIR=$$(BASEDIR)/output
|
||||||
CONFFILE=$$(BASEDIR)/pelican.conf.py
|
CONFFILE=$$(BASEDIR)/pelicanconf.py
|
||||||
|
PUBLISHCONF=$$(BASEDIR)/publishconf.py
|
||||||
|
|
||||||
FTP_HOST=$ftp_host
|
FTP_HOST=$ftp_host
|
||||||
FTP_USER=$ftp_user
|
FTP_USER=$ftp_user
|
||||||
FTP_TARGET_DIR=$ftp_target_dir
|
FTP_TARGET_DIR=$ftp_target_dir
|
||||||
|
|
||||||
SSH_HOST=$ssh_host
|
SSH_HOST=$ssh_host
|
||||||
|
SSH_PORT=$ssh_port
|
||||||
SSH_USER=$ssh_user
|
SSH_USER=$ssh_user
|
||||||
SSH_TARGET_DIR=$ssh_target_dir
|
SSH_TARGET_DIR=$ssh_target_dir
|
||||||
|
|
||||||
|
|
@ -22,10 +24,11 @@ help:
|
||||||
@echo 'Usage: '
|
@echo 'Usage: '
|
||||||
@echo ' make html (re)generate the web site '
|
@echo ' make html (re)generate the web site '
|
||||||
@echo ' make clean remove the generated files '
|
@echo ' make clean remove the generated files '
|
||||||
@echo ' ftp_upload upload the web site using FTP '
|
@echo ' make publish generate using production settings '
|
||||||
@echo ' ssh_upload upload the web site using SSH '
|
@echo ' ftp_upload upload the web site via FTP '
|
||||||
@echo ' dropbox_upload upload the web site using Dropbox '
|
@echo ' ssh_upload upload the web site via SSH '
|
||||||
@echo ' rsync_upload upload the web site using rsync/ssh'
|
@echo ' dropbox_upload upload the web site via Dropbox '
|
||||||
|
@echo ' rsync_upload upload the web site via rsync/ssh '
|
||||||
@echo ' '
|
@echo ' '
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,23 +39,31 @@ $$(OUTPUTDIR)/%.html:
|
||||||
$$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS)
|
$$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr $$(OUTPUTDIR)
|
find $$(OUTPUTDIR) -mindepth 1 -delete
|
||||||
mkdir $$(OUTPUTDIR)
|
|
||||||
|
|
||||||
dropbox_upload: $$(OUTPUTDIR)/index.html
|
regenerate: clean
|
||||||
|
$$(PELICAN) -r $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS)
|
||||||
|
|
||||||
|
serve:
|
||||||
|
cd $$(OUTPUTDIR) && python -m SimpleHTTPServer
|
||||||
|
|
||||||
|
publish:
|
||||||
|
$$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(PUBLISHCONF) $$(PELICANOPTS)
|
||||||
|
|
||||||
|
dropbox_upload: publish
|
||||||
cp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR)
|
cp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR)
|
||||||
|
|
||||||
ssh_upload: $$(OUTPUTDIR)/index.html
|
ssh_upload: publish
|
||||||
scp -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR)
|
scp -P $$(SSH_PORT) -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR)
|
||||||
|
|
||||||
rsync_upload: $$(OUTPUTDIR)/index.html
|
rsync_upload: publish
|
||||||
rsync -e ssh -P -rvz --delete $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
|
rsync -e "ssh -p $(SSH_PORT)" -P -rvz --delete $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR)
|
||||||
|
|
||||||
ftp_upload: $$(OUTPUTDIR)/index.html
|
ftp_upload: publish
|
||||||
lftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUTDIR) $$(FTP_TARGET_DIR) ; quit"
|
lftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUTDIR) $$(FTP_TARGET_DIR) ; quit"
|
||||||
|
|
||||||
github: $$(OUTPUTDIR)/index.html
|
github: publish
|
||||||
ghp-import $$(OUTPUTDIR)
|
ghp-import $$(OUTPUTDIR)
|
||||||
git push origin gh-pages
|
git push origin gh-pages
|
||||||
|
|
||||||
.PHONY: html help clean ftp_upload ssh_upload rsync_upload dropbox_upload github
|
.PHONY: html help clean regenerate serve publish ftp_upload ssh_upload rsync_upload dropbox_upload github
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*- #
|
|
||||||
|
|
||||||
AUTHOR = u"$author"
|
|
||||||
SITENAME = u"$sitename"
|
|
||||||
SITEURL = '/'
|
|
||||||
|
|
||||||
TIMEZONE = 'Europe/Paris'
|
|
||||||
|
|
||||||
DEFAULT_LANG='$lang'
|
|
||||||
|
|
||||||
# Blogroll
|
|
||||||
LINKS = (
|
|
||||||
('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'),
|
|
||||||
('Python.org', 'http://python.org'),
|
|
||||||
('Jinja2', 'http://jinja.pocoo.org'),
|
|
||||||
('You can modify those links in your config file', '#')
|
|
||||||
)
|
|
||||||
|
|
||||||
# Social widget
|
|
||||||
SOCIAL = (
|
|
||||||
('You can add links in your config file', '#'),
|
|
||||||
)
|
|
||||||
|
|
||||||
DEFAULT_PAGINATION = $default_pagination
|
|
||||||
22
pelican/tools/templates/pelicanconf.py.in
Normal file
22
pelican/tools/templates/pelicanconf.py.in
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*- #
|
||||||
|
|
||||||
|
AUTHOR = u"$author"
|
||||||
|
SITENAME = u"$sitename"
|
||||||
|
SITEURL = ''
|
||||||
|
|
||||||
|
TIMEZONE = 'Europe/Paris'
|
||||||
|
|
||||||
|
DEFAULT_LANG = '$lang'
|
||||||
|
|
||||||
|
# Blogroll
|
||||||
|
LINKS = (('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'),
|
||||||
|
('Python.org', 'http://python.org'),
|
||||||
|
('Jinja2', 'http://jinja.pocoo.org'),
|
||||||
|
('You can modify those links in your config file', '#'),)
|
||||||
|
|
||||||
|
# Social widget
|
||||||
|
SOCIAL = (('You can add links in your config file', '#'),
|
||||||
|
('Another social link', '#'),)
|
||||||
|
|
||||||
|
DEFAULT_PAGINATION = $default_pagination
|
||||||
16
pelican/tools/templates/publishconf.py.in
Normal file
16
pelican/tools/templates/publishconf.py.in
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*- #
|
||||||
|
|
||||||
|
from pelicanconf import *
|
||||||
|
|
||||||
|
SITEURL = '$siteurl'
|
||||||
|
|
||||||
|
DELETE_OUTPUT_DIRECTORY = True
|
||||||
|
|
||||||
|
# Following items are often useful when publishing
|
||||||
|
|
||||||
|
# Uncomment following line for absolute URLs in production:
|
||||||
|
#RELATIVE_URLS = False
|
||||||
|
|
||||||
|
#DISQUS_SITENAME = ""
|
||||||
|
#GOOGLE_ANALYTICS = ""
|
||||||
11
tests/TestPages/hidden_page_with_template.rst
Normal file
11
tests/TestPages/hidden_page_with_template.rst
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
This is a test hidden page with a custom template
|
||||||
|
#################################################
|
||||||
|
|
||||||
|
:status: hidden
|
||||||
|
:template: custom
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
|
|
||||||
|
This page is hidden
|
||||||
|
|
||||||
|
This page has a custom template to be called when rendered
|
||||||
8
tests/TestPages/page_with_template.rst
Normal file
8
tests/TestPages/page_with_template.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
This is a test page with a preset template
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
:template: custom
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
|
|
||||||
|
This article has a custom template to be called when rendered
|
||||||
8
tests/content/article_with_template.rst
Normal file
8
tests/content/article_with_template.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
Article with template
|
||||||
|
#####################
|
||||||
|
|
||||||
|
:template: custom
|
||||||
|
|
||||||
|
This article has a custom template to be called when rendered
|
||||||
|
|
||||||
|
This is some content. With some stuff to "typogrify".
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
from .support import unittest
|
from .support import unittest
|
||||||
|
|
||||||
from pelican.contents import Page
|
from pelican.contents import Page, Article
|
||||||
from pelican.settings import _DEFAULT_CONFIG
|
from pelican.settings import _DEFAULT_CONFIG
|
||||||
from pelican.utils import truncate_html_words
|
from pelican.utils import truncate_html_words
|
||||||
|
|
||||||
|
|
@ -135,6 +135,17 @@ class TestPage(unittest.TestCase):
|
||||||
# will simply skip this test.
|
# will simply skip this test.
|
||||||
unittest.skip("There is no locale %s in this system." % locale)
|
unittest.skip("There is no locale %s in this system." % locale)
|
||||||
|
|
||||||
|
def test_template(self):
|
||||||
|
"""
|
||||||
|
Pages default to page, metadata overwrites
|
||||||
|
"""
|
||||||
|
default_page = Page(**self.page_kwargs)
|
||||||
|
self.assertEqual('page', default_page.template)
|
||||||
|
page_kwargs = self._copy_page_kwargs()
|
||||||
|
page_kwargs['metadata']['template'] = 'custom'
|
||||||
|
custom_page = Page(**page_kwargs)
|
||||||
|
self.assertEqual('custom', custom_page.template)
|
||||||
|
|
||||||
def _copy_page_kwargs(self):
|
def _copy_page_kwargs(self):
|
||||||
# make a deep copy of page_kwargs
|
# make a deep copy of page_kwargs
|
||||||
page_kwargs = dict([(key, self.page_kwargs[key]) for key in
|
page_kwargs = dict([(key, self.page_kwargs[key]) for key in
|
||||||
|
|
@ -146,3 +157,15 @@ class TestPage(unittest.TestCase):
|
||||||
for subkey in page_kwargs[key]])
|
for subkey in page_kwargs[key]])
|
||||||
|
|
||||||
return page_kwargs
|
return page_kwargs
|
||||||
|
|
||||||
|
class TestArticle(TestPage):
|
||||||
|
def test_template(self):
|
||||||
|
"""
|
||||||
|
Articles default to article, metadata overwrites
|
||||||
|
"""
|
||||||
|
default_article = Article(**self.page_kwargs)
|
||||||
|
self.assertEqual('article', default_article.template)
|
||||||
|
article_kwargs = self._copy_page_kwargs()
|
||||||
|
article_kwargs['metadata']['template'] = 'custom'
|
||||||
|
custom_article = Article(**article_kwargs)
|
||||||
|
self.assertEqual('custom', custom_article.template)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,37 @@ CUR_DIR = os.path.dirname(__file__)
|
||||||
|
|
||||||
class TestArticlesGenerator(unittest.TestCase):
|
class TestArticlesGenerator(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestArticlesGenerator, self).setUp()
|
||||||
|
self.generator = None
|
||||||
|
|
||||||
|
def get_populated_generator(self):
|
||||||
|
"""
|
||||||
|
We only need to pull all the test articles once, but read from it
|
||||||
|
for each test.
|
||||||
|
"""
|
||||||
|
if self.generator is None:
|
||||||
|
settings = _DEFAULT_CONFIG.copy()
|
||||||
|
settings['ARTICLE_DIR'] = 'content'
|
||||||
|
settings['DEFAULT_CATEGORY'] = 'Default'
|
||||||
|
self.generator = ArticlesGenerator(settings.copy(), settings,
|
||||||
|
CUR_DIR, _DEFAULT_CONFIG['THEME'], None,
|
||||||
|
_DEFAULT_CONFIG['MARKUP'])
|
||||||
|
self.generator.generate_context()
|
||||||
|
return self.generator
|
||||||
|
|
||||||
|
def distill_articles(self, articles):
|
||||||
|
distilled = []
|
||||||
|
for page in articles:
|
||||||
|
distilled.append([
|
||||||
|
page.title,
|
||||||
|
page.status,
|
||||||
|
page.category.name,
|
||||||
|
page.template
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return distilled
|
||||||
|
|
||||||
def test_generate_feeds(self):
|
def test_generate_feeds(self):
|
||||||
|
|
||||||
generator = ArticlesGenerator(None, {'FEED': _DEFAULT_CONFIG['FEED']},
|
generator = ArticlesGenerator(None, {'FEED': _DEFAULT_CONFIG['FEED']},
|
||||||
|
|
@ -95,21 +126,32 @@ class TestArticlesGenerator(unittest.TestCase):
|
||||||
generator.generate_direct_templates(write)
|
generator.generate_direct_templates(write)
|
||||||
write.assert_called_count == 0
|
write.assert_called_count == 0
|
||||||
|
|
||||||
|
def test_per_article_template(self):
|
||||||
|
"""
|
||||||
|
Custom template articles get the field but standard/unset are None
|
||||||
|
"""
|
||||||
|
generator = self.get_populated_generator()
|
||||||
|
articles = self.distill_articles(generator.articles)
|
||||||
|
custom_template = ['Article with template', 'published', 'Default', 'custom']
|
||||||
|
standard_template = ['This is a super article !', 'published', 'Yeah', 'article']
|
||||||
|
self.assertIn(custom_template, articles)
|
||||||
|
self.assertIn(standard_template, articles)
|
||||||
|
|
||||||
class TestPageGenerator(unittest.TestCase):
|
class TestPageGenerator(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Every time you want to test for a new field;
|
Every time you want to test for a new field;
|
||||||
Make sure the test pages in "TestPages" have all the fields
|
Make sure the test pages in "TestPages" have all the fields
|
||||||
Add it to distilled in distill_pages_for_test
|
Add it to distilled in distill_pages
|
||||||
Then update the assertItemsEqual in test_generate_context to match expected
|
Then update the assertItemsEqual in test_generate_context to match expected
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def distill_pages_for_test(self, pages):
|
def distill_pages(self, pages):
|
||||||
distilled = []
|
distilled = []
|
||||||
for page in pages:
|
for page in pages:
|
||||||
distilled.append([
|
distilled.append([
|
||||||
page.title,
|
page.title,
|
||||||
page.status
|
page.status,
|
||||||
|
page.template
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
return distilled
|
return distilled
|
||||||
|
|
@ -122,16 +164,18 @@ class TestPageGenerator(unittest.TestCase):
|
||||||
_DEFAULT_CONFIG['THEME'], None,
|
_DEFAULT_CONFIG['THEME'], None,
|
||||||
_DEFAULT_CONFIG['MARKUP'])
|
_DEFAULT_CONFIG['MARKUP'])
|
||||||
generator.generate_context()
|
generator.generate_context()
|
||||||
pages = self.distill_pages_for_test(generator.pages)
|
pages = self.distill_pages(generator.pages)
|
||||||
hidden_pages = self.distill_pages_for_test(generator.hidden_pages)
|
hidden_pages = self.distill_pages(generator.hidden_pages)
|
||||||
|
|
||||||
pages_expected = [
|
pages_expected = [
|
||||||
[u'This is a test page', 'published'],
|
[u'This is a test page', 'published', 'page'],
|
||||||
[u'This is a markdown test page', 'published']
|
[u'This is a markdown test page', 'published', 'page'],
|
||||||
|
[u'This is a test page with a preset template', 'published', 'custom']
|
||||||
]
|
]
|
||||||
hidden_pages_expected = [
|
hidden_pages_expected = [
|
||||||
[u'This is a test hidden page', 'hidden'],
|
[u'This is a test hidden page', 'hidden', 'page'],
|
||||||
[u'This is a markdown test hidden page', 'hidden']
|
[u'This is a markdown test hidden page', 'hidden', 'page'],
|
||||||
|
[u'This is a test hidden page with a custom template', 'hidden', 'custom']
|
||||||
]
|
]
|
||||||
|
|
||||||
self.assertItemsEqual(pages_expected,pages)
|
self.assertItemsEqual(pages_expected,pages)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue