forked from github/pelican
Compare commits
1 commit
main
...
multiple-a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0550c6ef29 |
349 changed files with 22225 additions and 5136 deletions
|
|
@ -1,15 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
|
|
||||||
[*.py]
|
|
||||||
max_line_length = 88
|
|
||||||
|
|
||||||
[*.{yml,yaml}]
|
|
||||||
indent_size = 2
|
|
||||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
16
.gitignore
vendored
16
.gitignore
vendored
|
|
@ -1 +1,15 @@
|
||||||
node_modules/
|
*.egg-info
|
||||||
|
.*.swp
|
||||||
|
.*.swo
|
||||||
|
*.pyc
|
||||||
|
.DS_Store
|
||||||
|
docs/_build
|
||||||
|
docs/fr/_build
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
tags
|
||||||
|
.tox
|
||||||
|
.coverage
|
||||||
|
htmlcov
|
||||||
|
six-*.egg/
|
||||||
|
*.orig
|
||||||
|
|
|
||||||
9
.hgignore
Normal file
9
.hgignore
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
syntax: glob
|
||||||
|
output/*
|
||||||
|
*.pyc
|
||||||
|
MANIFEST
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
docs/_build
|
||||||
|
Paste-*
|
||||||
|
*.egg-info
|
||||||
29
.hgtags
Normal file
29
.hgtags
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
7acafbf7e47b1287525026ad8b4f1efe443d5403 1.2
|
||||||
|
7acafbf7e47b1287525026ad8b4f1efe443d5403 1.2
|
||||||
|
ae850ab0fd62a98a98da7ce74ac794319c6a5066 1.2
|
||||||
|
54a0309f79d6c5b54d8e1e3b5e3f744856b68a73 1.1
|
||||||
|
8f5e0eb037768351eb08840e588a4364266a69b3 1.1.1
|
||||||
|
bb986ed591734ca469f726753cbc48ebbfce0dcc 1.2.1
|
||||||
|
8a3dad99cbfa6bb5d0ef073213d0d86e0b4c5dba 1.2.2
|
||||||
|
4a20105a242ab154f6202aa6651979bfbb4cf95e 1.2.3
|
||||||
|
803aa0976cca3dd737777c640722988b1f3769fe 1.2.4
|
||||||
|
703c4511105fd9c8b85afda951a294c194e7cf3e 1.2.5
|
||||||
|
6e46a40aaa850a979f5d09dd95d02791ec7ab0ef 2.0
|
||||||
|
bf14d1a5c1fae9475447698f0f9b8d35c551f732 2.1
|
||||||
|
da86343ebd543e5865050e47ecb0937755528d13 2.1.1
|
||||||
|
760187f048bb23979402f950ecb5d3c5493995b1 2.2
|
||||||
|
20aa16fe4daa3b70f6c063f170edc916b49837ed 2.3
|
||||||
|
f9c1d94081504f21f5b2ba147a38099e45db1769 2.4
|
||||||
|
e65199a0b2706d2fb48f7a3c015e869716e0bec1 2.4.1
|
||||||
|
89dbd7b6f114508eae62fc821326f4797dfc8b23 2.4.2
|
||||||
|
979b4473af56a191a278c83058bc9c8fa1fde30e 2.4.3
|
||||||
|
26a444fbb78becae358afa0a5b47587db8739b21 2.4.4
|
||||||
|
3542b65fd1963ae7065b6a3bc912fbb6c150e98c 2.4.5
|
||||||
|
87745dfdd51b96bf18eaaf6c402effa902c1b856 2.5.0
|
||||||
|
294a2830a393d5a97671dc211dbdb5254a15e604 2.5.1
|
||||||
|
294a2830a393d5a97671dc211dbdb5254a15e604 2.5.1
|
||||||
|
92b31e41134cb2c1a156ce623338cf634d2ebc3e 2.5.1
|
||||||
|
7d728f8e771cbbc802ce81e424e08a8eecbd48dc 2.5.2
|
||||||
|
7d728f8e771cbbc802ce81e424e08a8eecbd48dc 2.5.2
|
||||||
|
6d368a1739a4ce48d2d04b00db04fa538e2bf90a 2.5.2
|
||||||
|
1f9dd44b546425216b1fa35fd88d3d532da8916b 2.5.3
|
||||||
24
.mailmap
Normal file
24
.mailmap
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
Alexis Métaireau <alexis@notmyidea.org>
|
||||||
|
Alexis Métaireau <alexis@notmyidea.org> <alexis, notmyidea, org>
|
||||||
|
Alexis Métaireau <alexis@notmyidea.org> <ametaireau@gmail.com>
|
||||||
|
Axel Haustant <noirbizarre@gmail.com> <axel.haustant.ext@mappy.com>
|
||||||
|
Axel Haustant <noirbizarre@gmail.com> <axel.haustant@valtech.fr>
|
||||||
|
Dave Mankoff <mankyd@gmail.com>
|
||||||
|
Feth Arezki <feth@tuttu.info>
|
||||||
|
Guillaume <guillaume@lame.homelinux.com>
|
||||||
|
Guillaume <guillaume@lame.homelinux.com> <guillaume@mint.(none)>
|
||||||
|
Guillaume B <guitreize@gmail.com>
|
||||||
|
Guillermo López <guilan70@hotmail.com>
|
||||||
|
Guillermo López <guilan70@hotmail.com> <guillermo.lopez@outlook.com>
|
||||||
|
Jomel Imperio <jimperio@gmail.com>
|
||||||
|
Justin Mayer <entrop@gmail.com>
|
||||||
|
Justin Mayer <entrop@gmail.com> <entroP@gmail.com>
|
||||||
|
Marco Milanesi <kpanic@gnufunk.org> <marcom@openquake.org>
|
||||||
|
Massimo Santini <santini@dsi.unimi.it> <santini@spillane.docenti.dsi.unimi.it>
|
||||||
|
Rémy HUBSCHER <hubscher.remy@gmail.com> <remy.hubscher@ionyse.com>
|
||||||
|
Simon Conseil <contact@saimon.org>
|
||||||
|
Simon Liedtke <liedtke.simon@googlemail.com>
|
||||||
|
Skami18 <skami@skami-laptop.dyndns.org>
|
||||||
|
Stuart Colville <muffinresearchlabs@gmail.com> <muffinresearch@gmail.com>
|
||||||
|
Stéphane Bunel <stephane@lutetium.(none)>
|
||||||
|
tBunnyMan <WagThatTail@Me.com>
|
||||||
14
.travis.yml
Normal file
14
.travis.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
language: python
|
||||||
|
python:
|
||||||
|
- "2.7"
|
||||||
|
- "3.3"
|
||||||
|
before_install:
|
||||||
|
- sudo apt-get update -qq
|
||||||
|
- sudo apt-get install -qq --no-install-recommends asciidoc
|
||||||
|
- sudo locale-gen fr_FR.UTF-8 tr_TR.UTF-8
|
||||||
|
install:
|
||||||
|
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then ln -s /usr/share/asciidoc/asciidocapi.py ~/virtualenv/python2.7/lib/python2.7/site-packages/; fi
|
||||||
|
- pip install mock
|
||||||
|
- pip install .
|
||||||
|
- pip install Markdown
|
||||||
|
script: python -m unittest discover
|
||||||
40
CONTRIBUTING.rst
Normal file
40
CONTRIBUTING.rst
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
Contribution submission guidelines
|
||||||
|
==================================
|
||||||
|
|
||||||
|
* Consider whether your new feature might be better suited as a plugin_. Folks
|
||||||
|
are usually available in the `#pelican IRC channel`_ if help is needed to
|
||||||
|
make that determination.
|
||||||
|
* `Create a new git branch`_ specific to your change (as opposed to making
|
||||||
|
your commits in the master branch).
|
||||||
|
* **Don't put multiple fixes/features in the same branch / pull request.**
|
||||||
|
For example, if you're hacking on a new feature and find a bugfix that
|
||||||
|
doesn't *require* your new feature, **make a new distinct branch and pull
|
||||||
|
request** for the bugfix.
|
||||||
|
* Adhere to PEP8 coding standards whenever possible.
|
||||||
|
* Check for unnecessary whitespace via ``git diff --check`` before committing.
|
||||||
|
* **Add docs and tests for your changes**.
|
||||||
|
* `Run all the tests`_ **on both Python 2.7 and 3.3** to ensure nothing was
|
||||||
|
accidentally broken.
|
||||||
|
* First line of your commit message should start with present-tense verb, be 50
|
||||||
|
characters or less, and include the relevant issue number(s) if applicable.
|
||||||
|
*Example:* ``Ensure proper PLUGIN_PATH behavior. Refs #428.`` If the commit
|
||||||
|
*completely fixes* an existing bug report, please use ``Fixes #585`` or ``Fix
|
||||||
|
#585`` syntax (so the relevant issue is automatically closed upon PR merge).
|
||||||
|
* After the first line of the commit message, add a blank line and then a more
|
||||||
|
detailed explanation (when relevant).
|
||||||
|
* If you have previously filed a GitHub issue and want to contribute code that
|
||||||
|
addresses that issue, **please use** ``hub pull-request`` instead of using
|
||||||
|
GitHub's web UI to submit the pull request. This isn't an absolute
|
||||||
|
requirement, but makes the maintainers' lives much easier! Specifically:
|
||||||
|
`install hub <https://github.com/defunkt/hub/#installation>`_ and then run
|
||||||
|
`hub pull-request <https://github.com/defunkt/hub/#git-pull-request>`_ to
|
||||||
|
turn your GitHub issue into a pull request containing your code.
|
||||||
|
|
||||||
|
Check out our `Git Tips`_ page or ask on the `#pelican IRC channel`_ if you
|
||||||
|
need assistance or have any questions about these guidelines.
|
||||||
|
|
||||||
|
.. _`plugin`: http://docs.getpelican.com/en/latest/plugins.html
|
||||||
|
.. _`#pelican IRC channel`: http://webchat.freenode.net/?channels=pelican&uio=d4
|
||||||
|
.. _`Create a new git branch`: https://github.com/getpelican/pelican/wiki/Git-Tips#making-your-changes
|
||||||
|
.. _`Run all the tests`: http://docs.getpelican.com/en/latest/contribute.html#running-the-test-suite
|
||||||
|
.. _`Git Tips`: https://github.com/getpelican/pelican/wiki/Git-Tips
|
||||||
673
LICENSE
673
LICENSE
|
|
@ -1,20 +1,661 @@
|
||||||
MIT License
|
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 19 November 2007
|
||||||
|
|
||||||
Copyright (c) 2024 Oliver Ladner
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Preamble
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
The GNU Affero General Public License is a free, copyleft license for
|
||||||
copies or substantial portions of the Software.
|
software and other kinds of works, specifically designed to ensure
|
||||||
|
cooperation with the community in the case of network server software.
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
The licenses for most software and other practical works are designed
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
to take away your freedom to share and change the works. By contrast,
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
our General Public Licenses are intended to guarantee your freedom to
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
share and change all versions of a program--to make sure it remains free
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
software for all its users.
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
Developers that use our General Public Licenses protect your rights
|
||||||
|
with two steps: (1) assert copyright on the software, and (2) offer
|
||||||
|
you this License which gives you legal permission to copy, distribute
|
||||||
|
and/or modify the software.
|
||||||
|
|
||||||
|
A secondary benefit of defending all users' freedom is that
|
||||||
|
improvements made in alternate versions of the program, if they
|
||||||
|
receive widespread use, become available for other developers to
|
||||||
|
incorporate. Many developers of free software are heartened and
|
||||||
|
encouraged by the resulting cooperation. However, in the case of
|
||||||
|
software used on network servers, this result may fail to come about.
|
||||||
|
The GNU General Public License permits making a modified version and
|
||||||
|
letting the public access it on a server without ever releasing its
|
||||||
|
source code to the public.
|
||||||
|
|
||||||
|
The GNU Affero General Public License is designed specifically to
|
||||||
|
ensure that, in such cases, the modified source code becomes available
|
||||||
|
to the community. It requires the operator of a network server to
|
||||||
|
provide the source code of the modified version running there to the
|
||||||
|
users of that server. Therefore, public use of a modified version, on
|
||||||
|
a publicly accessible server, gives the public access to the source
|
||||||
|
code of the modified version.
|
||||||
|
|
||||||
|
An older license, called the Affero General Public License and
|
||||||
|
published by Affero, was designed to accomplish similar goals. This is
|
||||||
|
a different license, not a version of the Affero GPL, but Affero has
|
||||||
|
released a new version of the Affero GPL which permits relicensing under
|
||||||
|
this license.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, if you modify the
|
||||||
|
Program, your modified version must prominently offer all users
|
||||||
|
interacting with it remotely through a computer network (if your version
|
||||||
|
supports such interaction) an opportunity to receive the Corresponding
|
||||||
|
Source of your version by providing access to the Corresponding Source
|
||||||
|
from a network server at no charge, through some standard or customary
|
||||||
|
means of facilitating copying of software. This Corresponding Source
|
||||||
|
shall include the Corresponding Source for any work covered by version 3
|
||||||
|
of the GNU General Public License that is incorporated pursuant to the
|
||||||
|
following paragraph.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the work with which it is combined will remain governed by version
|
||||||
|
3 of the GNU General Public License.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU Affero General Public License from time to time. Such new versions
|
||||||
|
will be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU Affero General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU Affero General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU Affero General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If your software can interact with users remotely through a computer
|
||||||
|
network, you should also make sure that it provides a way for users to
|
||||||
|
get its source. For example, if your program is a web application, its
|
||||||
|
interface could display a "Source" link that leads users to an archive
|
||||||
|
of the code. There are many ways you could offer source, and different
|
||||||
|
solutions will be better for different programs; see section 13 for the
|
||||||
|
specific requirements.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
|
||||||
3
MANIFEST.in
Normal file
3
MANIFEST.in
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
include *.rst
|
||||||
|
recursive-include pelican *.html *.css *png *.in *.rst *.md *.mkd *.xml *.py
|
||||||
|
include LICENSE THANKS docs/changelog.rst
|
||||||
43
README.md
43
README.md
|
|
@ -1,43 +0,0 @@
|
||||||
# lugh Pelican theme
|
|
||||||
|
|
||||||
This theme is based on the [simple theme](https://github.com/getpelican/pelican/tree/main/pelican/themes/simple/templates).
|
|
||||||
It's heavily customized to what I need here, so no efforts have been made to
|
|
||||||
keep it useful for others. Amongst other things, I:
|
|
||||||
|
|
||||||
- removed translations
|
|
||||||
- changed the structure (HTML `<footer>` etc.)
|
|
||||||
|
|
||||||
## Docs
|
|
||||||
|
|
||||||
- [Pelican: how to create your own theme](https://docs.getpelican.com/en/stable/themes.html)
|
|
||||||
- [Tailwind CSS quick start](https://tailwindcss.com/docs/installation)
|
|
||||||
|
|
||||||
## Doing
|
|
||||||
|
|
||||||
### Prepare Pelican development server config
|
|
||||||
|
|
||||||
Adapt Pelican's `publishconf.py` for local development.
|
|
||||||
E.g. `RELATIVE_URLS = False`
|
|
||||||
|
|
||||||
### Install Tailwind CSS Typography plugin
|
|
||||||
|
|
||||||
Typography enables sane defaults for longer texts. In this case, we use it for
|
|
||||||
the body content only, which is always Markdown. Typography is a bit of a beast
|
|
||||||
to configure/align to standard Tailwind.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npm install -D @tailwindcss/typography
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run the Tailwind build process
|
|
||||||
|
|
||||||
```shell
|
|
||||||
npx tailwindcss -i static/css/in.css -o static/css/out.css --watch
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run Pelican dev server
|
|
||||||
|
|
||||||
```shell
|
|
||||||
conda activate pelican
|
|
||||||
./devserver.sh
|
|
||||||
```
|
|
||||||
68
README.rst
Normal file
68
README.rst
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
Pelican
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. image:: https://secure.travis-ci.org/getpelican/pelican.png?branch=master
|
||||||
|
:target: http://travis-ci.org/getpelican/pelican
|
||||||
|
:alt: Travis-ci: continuous integration status.
|
||||||
|
|
||||||
|
Pelican is a static site generator, written in Python_.
|
||||||
|
|
||||||
|
* Write your weblog entries directly with your editor of choice (vim!)
|
||||||
|
in reStructuredText_ or Markdown_
|
||||||
|
* Includes a simple CLI tool to (re)generate the weblog
|
||||||
|
* Easy to interface with DVCSes and web hooks
|
||||||
|
* Completely static output is easy to host anywhere
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
Pelican currently supports:
|
||||||
|
|
||||||
|
* Blog articles and pages
|
||||||
|
* Comments, via an external service (Disqus). (Please note that while
|
||||||
|
useful, Disqus is an external service, and thus the comment data will be
|
||||||
|
somewhat outside of your control and potentially subject to data loss.)
|
||||||
|
* Theming support (themes are created using Jinja2_ templates)
|
||||||
|
* PDF generation of the articles/pages (optional)
|
||||||
|
* Publication of articles in multiple languages
|
||||||
|
* Atom/RSS feeds
|
||||||
|
* Code syntax highlighting
|
||||||
|
* Import from WordPress, Dotclear, or RSS feeds
|
||||||
|
* Integration with external tools: Twitter, Google Analytics, etc. (optional)
|
||||||
|
|
||||||
|
Have a look at the `Pelican documentation`_ for more information.
|
||||||
|
|
||||||
|
Why the name "Pelican"?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
"Pelican" is an anagram for *calepin*, which means "notebook" in French. ;)
|
||||||
|
|
||||||
|
Source code
|
||||||
|
-----------
|
||||||
|
|
||||||
|
You can access the source code at: https://github.com/getpelican/pelican
|
||||||
|
|
||||||
|
If you feel hackish, have a look at the explanation of `Pelican's internals`_.
|
||||||
|
|
||||||
|
Feedback / Contact us
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
If you want to see new features in Pelican, don't hesitate to offer
|
||||||
|
suggestions, clone the repository, etc. There are many ways to contribute_.
|
||||||
|
That's open source, dude!
|
||||||
|
|
||||||
|
Send a message to "authors at getpelican dot com" with any requests/feedback! You
|
||||||
|
can also join the team at `#pelican on Freenode`_ (or if you don't have an IRC
|
||||||
|
client handy, use the webchat_ for quick feedback.
|
||||||
|
|
||||||
|
.. Links
|
||||||
|
|
||||||
|
.. _Python: http://www.python.org/
|
||||||
|
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
||||||
|
.. _Markdown: http://daringfireball.net/projects/markdown/
|
||||||
|
.. _Jinja2: http://jinja.pocoo.org/
|
||||||
|
.. _`Pelican documentation`: http://docs.getpelican.com/latest/
|
||||||
|
.. _`Pelican's internals`: http://docs.getpelican.com/en/latest/internals.html
|
||||||
|
.. _`#pelican on Freenode`: irc://irc.freenode.net/pelican
|
||||||
|
.. _webchat: http://webchat.freenode.net/?channels=pelican&uio=d4
|
||||||
|
.. _contribute: http://docs.getpelican.com/en/latest/contribute.html
|
||||||
157
THANKS
Normal file
157
THANKS
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
Pelican is a project originally created by Alexis Métaireau
|
||||||
|
<http://notmyidea.org/>, but there are a large number of people that have
|
||||||
|
contributed or implemented key features over time. We do our best to keep this
|
||||||
|
list up-to-date, but you can also have a look at the nice contributor graphs
|
||||||
|
produced by GitHub: https://github.com/getpelican/pelican/graphs/contributors
|
||||||
|
|
||||||
|
If you want to contibute, check the documentation section about how to do so:
|
||||||
|
<http://docs.getpelican.com/en/latest/contribute.html>
|
||||||
|
|
||||||
|
Aaron Kavlie
|
||||||
|
Abhishek L
|
||||||
|
Albrecht Mühlenschulte
|
||||||
|
Aldiantoro Nugroho
|
||||||
|
Alen Mujezinovic
|
||||||
|
Alessandro Martin
|
||||||
|
Alexander Artemenko
|
||||||
|
Alexandre RODIERE
|
||||||
|
Alexis Daboville
|
||||||
|
Alexis Métaireau
|
||||||
|
Allan Whatmough
|
||||||
|
Andrea Crotti
|
||||||
|
Andrew Laski
|
||||||
|
Andrew Spiers
|
||||||
|
Arnaud BOS
|
||||||
|
asselinpaul
|
||||||
|
Axel Haustant
|
||||||
|
Benoît HERVIER
|
||||||
|
Borgar
|
||||||
|
Brandon W Maister
|
||||||
|
Brendan Wholihan
|
||||||
|
Brian C. Lane
|
||||||
|
Brian Hsu
|
||||||
|
Brian St. Pierre
|
||||||
|
Bruno Binet
|
||||||
|
BunnyMan
|
||||||
|
Chenguang Wang
|
||||||
|
Chris Elston
|
||||||
|
Chris McDonald (Wraithan)
|
||||||
|
Chris Streeter
|
||||||
|
Christophe Chauvet
|
||||||
|
Clint Howarth
|
||||||
|
Colin Dunklau
|
||||||
|
Dafydd Crosby
|
||||||
|
Dana Woodman
|
||||||
|
Dave King
|
||||||
|
Dave Mankoff
|
||||||
|
David Beitey
|
||||||
|
David Marble
|
||||||
|
Deniz Turgut (Avaris)
|
||||||
|
derdon
|
||||||
|
Dirkjan Ochtman
|
||||||
|
Dirk Makowski
|
||||||
|
draftcode
|
||||||
|
Edward Delaporte
|
||||||
|
Emily Strickland
|
||||||
|
epatters
|
||||||
|
Eric Case
|
||||||
|
Erik Hetzner
|
||||||
|
FELD Boris
|
||||||
|
Feth Arezki
|
||||||
|
Florian Jacob
|
||||||
|
Florian Preinstorfer
|
||||||
|
Félix Delval
|
||||||
|
Freeculture
|
||||||
|
George V. Reilly
|
||||||
|
Guillaume
|
||||||
|
Guillaume B
|
||||||
|
Guillermo López
|
||||||
|
guillermooo
|
||||||
|
Ian Cordasco
|
||||||
|
Igor Kalnitsky
|
||||||
|
Irfan Ahmad
|
||||||
|
Iuri de Silvio
|
||||||
|
Ivan Dyedov
|
||||||
|
James King
|
||||||
|
James Rowe
|
||||||
|
jawher
|
||||||
|
Jered Boxman
|
||||||
|
Jerome
|
||||||
|
Jiachen Yang
|
||||||
|
Jochen Breuer
|
||||||
|
joe di castro
|
||||||
|
John Kristensen
|
||||||
|
John Mastro
|
||||||
|
Jökull Sólberg Auðunsson
|
||||||
|
Jomel Imperio
|
||||||
|
Joseph Reagle
|
||||||
|
Joshua Adelman
|
||||||
|
Julian Berman
|
||||||
|
Justin Mayer
|
||||||
|
Kyle Fuller
|
||||||
|
Laureline Guerin
|
||||||
|
Leonard Huang
|
||||||
|
Leroy Jiang
|
||||||
|
Marcel Hellkamp
|
||||||
|
Marco Milanesi
|
||||||
|
Marcus Fredriksson
|
||||||
|
Mario Rodas
|
||||||
|
Mark Caudill
|
||||||
|
Martin Brochhaus
|
||||||
|
Massimo Santini
|
||||||
|
Matt Bowcock
|
||||||
|
Matt Layman
|
||||||
|
Meir Kriheli
|
||||||
|
Michael Guntsche
|
||||||
|
Michael Reneer
|
||||||
|
Michael Yanovich
|
||||||
|
Mike Yumatov
|
||||||
|
Mikhail Korobov
|
||||||
|
m-r-r
|
||||||
|
mviera
|
||||||
|
Nico Di Rocco
|
||||||
|
Nicolas Duhamel
|
||||||
|
Nicolas Perriault
|
||||||
|
Nicolas Steinmetz
|
||||||
|
Paul Asselin
|
||||||
|
Pavel Puchkin
|
||||||
|
Perry Roper
|
||||||
|
Peter Desmet
|
||||||
|
Philippe Pepiot
|
||||||
|
Rachid Belaid
|
||||||
|
Randall Degges
|
||||||
|
Ranjhith Kalisamy
|
||||||
|
Remi Rampin
|
||||||
|
Rémy HUBSCHER
|
||||||
|
renhbo
|
||||||
|
Richard Duivenvoorde
|
||||||
|
Rogdham
|
||||||
|
Roman Skvazh
|
||||||
|
Ronny Pfannschmidt
|
||||||
|
Rory McCann
|
||||||
|
Rıdvan Örsvuran
|
||||||
|
saghul
|
||||||
|
sam
|
||||||
|
Samrat Man Singh
|
||||||
|
Simon Conseil
|
||||||
|
Simon Liedtke
|
||||||
|
Skami18
|
||||||
|
solsTiCe d'Hiver
|
||||||
|
Steve Schwarz
|
||||||
|
Stéphane Bunel
|
||||||
|
Stéphane Raimbault
|
||||||
|
Stuart Colville
|
||||||
|
Talha Mansoor
|
||||||
|
Tarek Ziade
|
||||||
|
Thanos Lefteris
|
||||||
|
Thomas Thurman
|
||||||
|
Tobias
|
||||||
|
Tomi Pieviläinen
|
||||||
|
Trae Blain
|
||||||
|
Tshepang Lekhonkhobe
|
||||||
|
Valentin-Costel Hăloiu
|
||||||
|
Vlad Niculae
|
||||||
|
William Light
|
||||||
|
Wladislaw Merezhko
|
||||||
|
W. Trevor King
|
||||||
|
Zoresvit
|
||||||
8
dev_requirements.txt
Normal file
8
dev_requirements.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Tests
|
||||||
|
mock
|
||||||
|
|
||||||
|
# Optional Packages
|
||||||
|
Markdown
|
||||||
|
BeautifulSoup4
|
||||||
|
lxml
|
||||||
|
typogrify
|
||||||
130
docs/Makefile
Normal file
130
docs/Makefile
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
# Makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
PAPER =
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# Internal variables.
|
||||||
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
|
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
|
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " html to make standalone HTML files"
|
||||||
|
@echo " dirhtml to make HTML files named index.html in directories"
|
||||||
|
@echo " singlehtml to make a single large HTML file"
|
||||||
|
@echo " pickle to make pickle files"
|
||||||
|
@echo " json to make JSON files"
|
||||||
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
|
@echo " qthelp to make HTML files and a qthelp project"
|
||||||
|
@echo " devhelp to make HTML files and a Devhelp project"
|
||||||
|
@echo " epub to make an epub"
|
||||||
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||||
|
@echo " text to make text files"
|
||||||
|
@echo " man to make manual pages"
|
||||||
|
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||||
|
@echo " linkcheck to check all external links for integrity"
|
||||||
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
-rm -rf $(BUILDDIR)/*
|
||||||
|
|
||||||
|
html:
|
||||||
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||||
|
|
||||||
|
dirhtml:
|
||||||
|
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||||
|
|
||||||
|
singlehtml:
|
||||||
|
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||||
|
|
||||||
|
pickle:
|
||||||
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the pickle files."
|
||||||
|
|
||||||
|
json:
|
||||||
|
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the JSON files."
|
||||||
|
|
||||||
|
htmlhelp:
|
||||||
|
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||||
|
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||||
|
|
||||||
|
qthelp:
|
||||||
|
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||||
|
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||||
|
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Raclette.qhcp"
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Raclette.qhc"
|
||||||
|
|
||||||
|
devhelp:
|
||||||
|
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished."
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# mkdir -p $$HOME/.local/share/devhelp/Raclette"
|
||||||
|
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Raclette"
|
||||||
|
@echo "# devhelp"
|
||||||
|
|
||||||
|
epub:
|
||||||
|
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||||
|
|
||||||
|
latex:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||||
|
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||||
|
"(use \`make latexpdf' here to do that automatically)."
|
||||||
|
|
||||||
|
latexpdf:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo "Running LaTeX files through pdflatex..."
|
||||||
|
make -C $(BUILDDIR)/latex all-pdf
|
||||||
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
text:
|
||||||
|
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||||
|
|
||||||
|
man:
|
||||||
|
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||||
|
|
||||||
|
changes:
|
||||||
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||||
|
@echo
|
||||||
|
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||||
|
|
||||||
|
linkcheck:
|
||||||
|
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||||
|
@echo
|
||||||
|
@echo "Link check complete; look for any errors in the above output " \
|
||||||
|
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||||
|
|
||||||
|
doctest:
|
||||||
|
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||||
|
@echo "Testing of doctests in the sources finished, look at the " \
|
||||||
|
"results in $(BUILDDIR)/doctest/output.txt."
|
||||||
BIN
docs/_static/overall.png
vendored
Normal file
BIN
docs/_static/overall.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/_static/pelican.gif
vendored
Normal file
BIN
docs/_static/pelican.gif
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/_static/pelican.png
vendored
Normal file
BIN
docs/_static/pelican.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
BIN
docs/_static/theme-basic.zip
vendored
Normal file
BIN
docs/_static/theme-basic.zip
vendored
Normal file
Binary file not shown.
BIN
docs/_static/uml.jpg
vendored
Normal file
BIN
docs/_static/uml.jpg
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
3
docs/_themes/.gitignore
vendored
Normal file
3
docs/_themes/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
.DS_Store
|
||||||
22
docs/_themes/pelican/layout.html
vendored
Normal file
22
docs/_themes/pelican/layout.html
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{% extends "basic/layout.html" %}
|
||||||
|
{% block header %}
|
||||||
|
{{ super() }}
|
||||||
|
{% if pagename == 'index' %}
|
||||||
|
<div class=indexwrapper>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block footer %}
|
||||||
|
{% if pagename == 'index' %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{# do not display relbars #}
|
||||||
|
{% block relbar1 %}{% endblock %}
|
||||||
|
{% block relbar2 %}
|
||||||
|
{% if theme_github_fork %}
|
||||||
|
<a href="http://github.com/{{ theme_github_fork }}"><img style="position: fixed; top: 0; right: 0; border: 0;"
|
||||||
|
src="http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub" /></a>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block sidebar1 %}{% endblock %}
|
||||||
|
{% block sidebar2 %}{% endblock %}
|
||||||
254
docs/_themes/pelican/static/pelican.css_t
vendored
Normal file
254
docs/_themes/pelican/static/pelican.css_t
vendored
Normal file
|
|
@ -0,0 +1,254 @@
|
||||||
|
/*
|
||||||
|
* pelican.css_t
|
||||||
|
* ~~~~~~~~~~~~
|
||||||
|
*
|
||||||
|
* Sphinx stylesheet -- pelican theme, based on the nature theme
|
||||||
|
*
|
||||||
|
* :copyright: Copyright 2011 by Alexis Metaireau.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@import url("basic.css");
|
||||||
|
|
||||||
|
/* -- page layout ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 100%;
|
||||||
|
background-color: white;
|
||||||
|
color: #555;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.documentwrapper {
|
||||||
|
width: 70%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.bodywrapper {
|
||||||
|
margin: 0 0 0 230px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border: 1px solid #B1B4B6;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.document {
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #3E4349;
|
||||||
|
padding: 0 30px 30px 30px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer {
|
||||||
|
color: #555;
|
||||||
|
width: 100%;
|
||||||
|
padding: 13px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 75%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.footer a {
|
||||||
|
color: #444;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related {
|
||||||
|
background-color: #6BA81E;
|
||||||
|
line-height: 32px;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0px 1px 0 #444;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.related a {
|
||||||
|
color: #E2F3CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar {
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebarwrapper{
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h3,
|
||||||
|
div.sphinxsidebar h4 {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
color: #222;
|
||||||
|
font-size: 1.2em;
|
||||||
|
font-weight: normal;
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px 10px;
|
||||||
|
background-color: #ddd;
|
||||||
|
text-shadow: 1px 1px 0 white
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h4{
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar h3 a {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
div.sphinxsidebar p {
|
||||||
|
color: #888;
|
||||||
|
padding: 5px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar p.topless {
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar ul {
|
||||||
|
margin: 10px 20px;
|
||||||
|
padding: 0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar a {
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input {
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.sphinxsidebar input[type=text]{
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -- body styles ----------------------------------------------------------- */
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #005B81;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #E32E00;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body h1,
|
||||||
|
div.body h2,
|
||||||
|
div.body h3,
|
||||||
|
div.body h4,
|
||||||
|
div.body h5,
|
||||||
|
div.body h6 {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-weight: normal;
|
||||||
|
color: #212224;
|
||||||
|
margin: 30px 0px 10px 0px;
|
||||||
|
padding: 5px 0 5px 10px;
|
||||||
|
text-shadow: 0px 1px 0 white
|
||||||
|
}
|
||||||
|
|
||||||
|
{% if theme_index_logo %}
|
||||||
|
div.indexwrapper h1 {
|
||||||
|
text-indent: -999999px;
|
||||||
|
background: url({{ theme_index_logo }}) no-repeat center center;
|
||||||
|
height: {{ theme_index_logo_height }};
|
||||||
|
}
|
||||||
|
{% endif %}
|
||||||
|
div.body h1 {
|
||||||
|
border-top: 20px solid white;
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 250%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
|
||||||
|
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
|
||||||
|
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
|
||||||
|
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
|
||||||
|
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
|
||||||
|
|
||||||
|
a.headerlink {
|
||||||
|
color: #c60f0f;
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding: 0 4px 0 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.headerlink:hover {
|
||||||
|
background-color: #c60f0f;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body p, div.body dd, div.body li {
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.admonition p.admonition-title + p {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.highlight{
|
||||||
|
background-color: #111;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.note {
|
||||||
|
background-color: #eee;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.seealso {
|
||||||
|
background-color: #ffc;
|
||||||
|
border: 1px solid #ff6;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.topic {
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.warning {
|
||||||
|
background-color: #ffe4e4;
|
||||||
|
border: 1px solid #f66;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.admonition-title {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.admonition-title:after {
|
||||||
|
content: ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #111;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 1.2em;
|
||||||
|
border: 1px solid #C6C9CB;
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin: 1.5em 0 1.5em 0;
|
||||||
|
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
|
||||||
|
-moz-box-shadow: 1px 1px 1px #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt {
|
||||||
|
background-color: #ecf0f3;
|
||||||
|
color: #222;
|
||||||
|
/* padding: 1px 2px; */
|
||||||
|
font-size: 1.1em;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewcode-back {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.viewcode-block:target {
|
||||||
|
background-color: #f4debf;
|
||||||
|
border-top: 1px solid #ac9;
|
||||||
|
border-bottom: 1px solid #ac9;
|
||||||
|
}
|
||||||
10
docs/_themes/pelican/theme.conf
vendored
Normal file
10
docs/_themes/pelican/theme.conf
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
[theme]
|
||||||
|
inherit = basic
|
||||||
|
stylesheet = pelican.css
|
||||||
|
nosidebar = true
|
||||||
|
pygments_style = fruity
|
||||||
|
|
||||||
|
[options]
|
||||||
|
index_logo_height = 120px
|
||||||
|
index_logo =
|
||||||
|
github_fork =
|
||||||
190
docs/changelog.rst
Normal file
190
docs/changelog.rst
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
Release history
|
||||||
|
###############
|
||||||
|
|
||||||
|
3.3 (XXXX-XX-XX)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Rename signals for better consistency (some plugins may need to be updated)
|
||||||
|
* Move metadata extraction from generators to readers; metadata extraction no
|
||||||
|
longer article-specific
|
||||||
|
* Deprecate ``FILES_TO_COPY`` in favor of ``STATIC_PATHS`` and
|
||||||
|
``EXTRA_PATH_METADATA``
|
||||||
|
|
||||||
|
3.2.1 and 3.2.2
|
||||||
|
===============
|
||||||
|
|
||||||
|
* Facilitate inclusion in FreeBSD Ports Collection
|
||||||
|
|
||||||
|
3.2 (2013-04-24)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Support for Python 3!
|
||||||
|
* Override page save-to location from meta-data (enables using a static page as
|
||||||
|
the site's home page, for example)
|
||||||
|
* Time period archives (per-year, per-month, and per-day archives of posts)
|
||||||
|
* Posterous blog import
|
||||||
|
* Improve WordPress blog import
|
||||||
|
* Migrate plugins to separate repository
|
||||||
|
* Improve HTML parser
|
||||||
|
* Provide ability to show or hide categories from menu using
|
||||||
|
``DISPLAY_CATEGORIES_ON_MENU`` option
|
||||||
|
* Auto-regeneration can be told to ignore files via ``IGNORE_FILES`` setting
|
||||||
|
* Improve post-generation feedback to user
|
||||||
|
* For multilingual posts, use meta-data to designate which is the original
|
||||||
|
and which is the translation
|
||||||
|
* Add ``.mdown`` to list of supported Markdown file extensions
|
||||||
|
* Document-relative URL generation (``RELATIVE_URLS``) is now off by default
|
||||||
|
|
||||||
|
3.1 (2012-12-04)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Importer now stores slugs within files by default. This can be disabled with
|
||||||
|
the ``--disable-slugs`` option.
|
||||||
|
* Improve handling of links to intra-site resources
|
||||||
|
* Ensure WordPress import adds paragraphs for all types of line endings
|
||||||
|
in post content
|
||||||
|
* Decode HTML entities within WordPress post titles on import
|
||||||
|
* Improve appearance of LinkedIn icon in default theme
|
||||||
|
* Add GitHub and Google+ social icons support in default theme
|
||||||
|
* Optimize social icons
|
||||||
|
* Add ``FEED_ALL_ATOM`` and ``FEED_ALL_RSS`` to generate feeds containing all posts regardless of their language
|
||||||
|
* Split ``TRANSLATION_FEED`` into ``TRANSLATION_FEED_ATOM`` and ``TRANSLATION_FEED_RSS``
|
||||||
|
* Different feeds can now be enabled/disabled individually
|
||||||
|
* Allow for blank author: if ``AUTHOR`` setting is not set, author won't
|
||||||
|
default to ``${USER}`` anymore, and a post won't contain any author
|
||||||
|
information if the post author is empty
|
||||||
|
* Move LESS and Webassets support from Pelican core to plugin
|
||||||
|
* The ``DEFAULT_DATE`` setting now defaults to ``None``, which means that
|
||||||
|
articles won't be generated unless date metadata is specified
|
||||||
|
* Add ``FILENAME_METADATA`` setting to support metadata extraction from filename
|
||||||
|
* Add ``gzip_cache`` plugin to compress common text files into a ``.gz``
|
||||||
|
file within the same directory as the original file, preventing the server
|
||||||
|
(e.g. Nginx) from having to compress files during an HTTP call
|
||||||
|
* Add support for AsciiDoc-formatted content
|
||||||
|
* Add ``USE_FOLDER_AS_CATEGORY`` setting so that feature can be toggled on/off
|
||||||
|
* Support arbitrary Jinja template files
|
||||||
|
* Restore basic functional tests
|
||||||
|
* New signals: ``generator_init``, ``get_generators``, and
|
||||||
|
``article_generate_preread``
|
||||||
|
|
||||||
|
3.0 (2012-08-08)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Refactored the way URLs are handled
|
||||||
|
* Improved the English documentation
|
||||||
|
* Fixed packaging using ``setuptools`` entrypoints
|
||||||
|
* Added ``typogrify`` support
|
||||||
|
* Added a way to disable feed generation
|
||||||
|
* Added support for ``DIRECT_TEMPLATES``
|
||||||
|
* Allow multiple extensions for content files
|
||||||
|
* Added LESS support
|
||||||
|
* Improved the import script
|
||||||
|
* Added functional tests
|
||||||
|
* Rsync support in the generated Makefile
|
||||||
|
* Improved feed support (easily pluggable with Feedburner for instance)
|
||||||
|
* Added support for ``abbr`` in reST
|
||||||
|
* Fixed a bunch of bugs :-)
|
||||||
|
|
||||||
|
2.8 (2012-02-28)
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Dotclear importer
|
||||||
|
* Allow the usage of Markdown extensions
|
||||||
|
* Themes are now easily extensible
|
||||||
|
* Don't output pagination information if there is only one page
|
||||||
|
* Add a page per author, with all their articles
|
||||||
|
* Improved the test suite
|
||||||
|
* Made the themes easier to extend
|
||||||
|
* Removed Skribit support
|
||||||
|
* Added a ``pelican-quickstart`` script
|
||||||
|
* Fixed timezone-related issues
|
||||||
|
* Added some scripts for Windows support
|
||||||
|
* Date can be specified in seconds
|
||||||
|
* Never fail when generating posts (skip and continue)
|
||||||
|
* Allow the use of future dates
|
||||||
|
* Support having different timezones per language
|
||||||
|
* Enhanced the documentation
|
||||||
|
|
||||||
|
2.7 (2011-06-11)
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Use ``logging`` rather than echoing to stdout
|
||||||
|
* Support custom Jinja filters
|
||||||
|
* Compatibility with Python 2.5
|
||||||
|
* Added a theme manager
|
||||||
|
* Packaged for Debian
|
||||||
|
* Added draft support
|
||||||
|
|
||||||
|
2.6 (2011-03-08)
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Changes in the output directory structure
|
||||||
|
* Makes templates easier to work with / create
|
||||||
|
* Added RSS support (was Atom-only)
|
||||||
|
* Added tag support for the feeds
|
||||||
|
* Enhance the documentation
|
||||||
|
* Added another theme (brownstone)
|
||||||
|
* Added translations
|
||||||
|
* Added a way to use cleaner URLs with a rewrite url module (or equivalent)
|
||||||
|
* Added a tag cloud
|
||||||
|
* Added an autoreloading feature: the blog is automatically regenerated each time a modification is detected
|
||||||
|
* Translate the documentation into French
|
||||||
|
* Import a blog from an RSS feed
|
||||||
|
* Pagination support
|
||||||
|
* Added Skribit support
|
||||||
|
|
||||||
|
2.5 (2010-11-20)
|
||||||
|
==================
|
||||||
|
|
||||||
|
* Import from Wordpress
|
||||||
|
* Added some new themes (martyalchin / wide-notmyidea)
|
||||||
|
* First bug report!
|
||||||
|
* Linkedin support
|
||||||
|
* Added a FAQ
|
||||||
|
* Google Analytics support
|
||||||
|
* Twitter support
|
||||||
|
* Use relative URLs, not static ones
|
||||||
|
|
||||||
|
2.4 (2010-11-06)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Minor themes changes
|
||||||
|
* Add Disqus support (so we have comments)
|
||||||
|
* Another code refactoring
|
||||||
|
* Added config settings about pages
|
||||||
|
* Blog entries can also be generated in PDF
|
||||||
|
|
||||||
|
2.3 (2010-10-31)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Markdown support
|
||||||
|
|
||||||
|
2.2 (2010-10-30)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Prettify output
|
||||||
|
* Manages static pages as well
|
||||||
|
|
||||||
|
2.1 (2010-10-30)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Make notmyidea the default theme
|
||||||
|
|
||||||
|
2.0 (2010-10-30)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Refactoring to be more extensible
|
||||||
|
* Change into the setting variables
|
||||||
|
|
||||||
|
1.2 (2010-09-28)
|
||||||
|
================
|
||||||
|
|
||||||
|
* Added a debug option
|
||||||
|
* Added per-category feeds
|
||||||
|
* Use filesystem to get dates if no metadata is provided
|
||||||
|
* Add Pygments support
|
||||||
|
|
||||||
|
1.1 (2010-08-19)
|
||||||
|
================
|
||||||
|
|
||||||
|
* First working version
|
||||||
50
docs/conf.py
Normal file
50
docs/conf.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
sys.path.append(os.path.abspath(os.pardir))
|
||||||
|
|
||||||
|
from pelican import __version__, __major__
|
||||||
|
|
||||||
|
# -- General configuration -----------------------------------------------------
|
||||||
|
templates_path = ['_templates']
|
||||||
|
extensions = ['sphinx.ext.autodoc',]
|
||||||
|
source_suffix = '.rst'
|
||||||
|
master_doc = 'index'
|
||||||
|
project = 'Pelican'
|
||||||
|
copyright = '2010, Alexis Metaireau and contributors'
|
||||||
|
exclude_patterns = ['_build']
|
||||||
|
version = __version__
|
||||||
|
release = __major__
|
||||||
|
|
||||||
|
# -- Options for HTML output ---------------------------------------------------
|
||||||
|
|
||||||
|
html_theme_path = ['_themes']
|
||||||
|
html_theme = 'pelican'
|
||||||
|
|
||||||
|
html_theme_options = {
|
||||||
|
'nosidebar': True,
|
||||||
|
'index_logo': 'pelican.png',
|
||||||
|
'github_fork': 'getpelican/pelican',
|
||||||
|
}
|
||||||
|
|
||||||
|
html_static_path = ['_static']
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = 'Pelicandoc'
|
||||||
|
|
||||||
|
# -- Options for LaTeX output --------------------------------------------------
|
||||||
|
latex_documents = [
|
||||||
|
('index', 'Pelican.tex', 'Pelican Documentation',
|
||||||
|
'Alexis Métaireau', 'manual'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# -- Options for manual page output --------------------------------------------
|
||||||
|
man_pages = [
|
||||||
|
('index', 'pelican', 'pelican documentation',
|
||||||
|
['Alexis Métaireau'], 1),
|
||||||
|
('pelican-themes', 'pelican-themes', 'A theme manager for Pelican',
|
||||||
|
['Mickaël Raybaud'], 1),
|
||||||
|
('themes', 'pelican-theming', 'How to create themes for Pelican',
|
||||||
|
['The Pelican contributors'], 1)
|
||||||
|
]
|
||||||
144
docs/contribute.rst
Normal file
144
docs/contribute.rst
Normal file
|
|
@ -0,0 +1,144 @@
|
||||||
|
How to contribute
|
||||||
|
#################
|
||||||
|
|
||||||
|
There are many ways to contribute to Pelican. You can improve the
|
||||||
|
documentation, add missing features, and fix bugs (or just report them). You
|
||||||
|
can also help out by reviewing and commenting on
|
||||||
|
`existing issues <https://github.com/getpelican/pelican/issues>`_.
|
||||||
|
|
||||||
|
Don't hesitate to fork Pelican and submit a pull request on GitHub. When doing
|
||||||
|
so, please adhere to the following guidelines.
|
||||||
|
|
||||||
|
.. include:: ../CONTRIBUTING.rst
|
||||||
|
|
||||||
|
Setting up the development environment
|
||||||
|
======================================
|
||||||
|
|
||||||
|
While there are many ways to set up one's development environment, following
|
||||||
|
is a method that uses `virtualenv <http://www.virtualenv.org/>`_. If you don't
|
||||||
|
have ``virtualenv`` installed, you can install it via::
|
||||||
|
|
||||||
|
$ pip install virtualenv
|
||||||
|
|
||||||
|
Virtual environments allow you to work on Python projects which are isolated
|
||||||
|
from one another so you can use different packages (and package versions) with
|
||||||
|
different projects.
|
||||||
|
|
||||||
|
To create and activate a virtual environment, use the following syntax::
|
||||||
|
|
||||||
|
$ virtualenv ~/virtualenvs/pelican
|
||||||
|
$ cd ~/virtualenvs/pelican
|
||||||
|
$ . bin/activate
|
||||||
|
|
||||||
|
To clone the Pelican source::
|
||||||
|
|
||||||
|
$ git clone https://github.com/getpelican/pelican.git src/pelican
|
||||||
|
|
||||||
|
To install the development dependencies::
|
||||||
|
|
||||||
|
$ cd src/pelican
|
||||||
|
$ pip install -r dev_requirements.txt
|
||||||
|
|
||||||
|
To install Pelican and its dependencies::
|
||||||
|
|
||||||
|
$ python setup.py develop
|
||||||
|
|
||||||
|
Or using ``pip``::
|
||||||
|
|
||||||
|
$ pip install -e .
|
||||||
|
|
||||||
|
Coding standards
|
||||||
|
================
|
||||||
|
|
||||||
|
Try to respect what is described in the `PEP8 specification
|
||||||
|
<http://www.python.org/dev/peps/pep-0008/>`_ when making contributions. This
|
||||||
|
can be eased via the `pep8 <http://pypi.python.org/pypi/pep8>`_ or `flake8
|
||||||
|
<http://pypi.python.org/pypi/flake8/>`_ tools, the latter of which in
|
||||||
|
particular will give you some useful hints about ways in which the
|
||||||
|
code/formatting can be improved.
|
||||||
|
|
||||||
|
Building the docs
|
||||||
|
=================
|
||||||
|
|
||||||
|
If you make changes to the documentation, you should preview your changes
|
||||||
|
before committing them::
|
||||||
|
|
||||||
|
$ pip install sphinx
|
||||||
|
$ cd src/pelican/docs
|
||||||
|
$ make html
|
||||||
|
|
||||||
|
Open ``_build/html/index.html`` in your browser to preview the documentation.
|
||||||
|
|
||||||
|
Running the test suite
|
||||||
|
======================
|
||||||
|
|
||||||
|
Each time you add a feature, there are two things to do regarding tests:
|
||||||
|
check that the existing tests pass, and add tests for the new feature
|
||||||
|
or bugfix.
|
||||||
|
|
||||||
|
The tests live in ``pelican/tests`` and you can run them using the
|
||||||
|
"discover" feature of ``unittest``::
|
||||||
|
|
||||||
|
$ python -m unittest discover
|
||||||
|
|
||||||
|
After making your changes and running the tests, you may see a test failure
|
||||||
|
mentioning that "some generated files differ from the expected functional tests
|
||||||
|
output." If you have made changes that affect the HTML output generated by
|
||||||
|
Pelican, and the changes to that output are expected and deemed correct given
|
||||||
|
the nature of your changes, then you should update the output used by the
|
||||||
|
functional tests. To do so, you can use the following two commands::
|
||||||
|
|
||||||
|
$ pelican -o pelican/tests/output/custom/ -s samples/pelican.conf.py \
|
||||||
|
samples/content/
|
||||||
|
$ pelican -o pelican/tests/output/basic/ samples/content/
|
||||||
|
|
||||||
|
Testing on Python 2 and 3
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Testing on Python 3 currently requires some extra steps: installing
|
||||||
|
Python 3-compatible versions of dependent packages and plugins.
|
||||||
|
|
||||||
|
Tox_ is a useful tool to run tests on both versions. It will install the
|
||||||
|
Python 3-compatible version of dependent packages.
|
||||||
|
|
||||||
|
.. _Tox: http://testrun.org/tox/latest/
|
||||||
|
|
||||||
|
Python 3 development tips
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Here are some tips that may be useful when doing some code for both Python 2.7
|
||||||
|
and Python 3 at the same time:
|
||||||
|
|
||||||
|
- Assume every string and literal is unicode (import unicode_literals):
|
||||||
|
|
||||||
|
- Do not use prefix ``u'``.
|
||||||
|
- Do not encode/decode strings in the middle of sth. Follow the code to the
|
||||||
|
source (or target) of a string and encode/decode at the first/last possible
|
||||||
|
point.
|
||||||
|
- In other words, write your functions to expect and to return unicode.
|
||||||
|
- Encode/decode strings if e.g. the source is a Python function that is known
|
||||||
|
to handle this badly, e.g. strftime() in Python 2.
|
||||||
|
|
||||||
|
- Use new syntax: print function, "except ... *as* e" (not comma) etc.
|
||||||
|
- Refactor method calls like ``dict.iteritems()``, ``xrange()`` etc. in a way
|
||||||
|
that runs without code change in both Python versions.
|
||||||
|
- Do not use magic method ``__unicode()__`` in new classes. Use only ``__str()__``
|
||||||
|
and decorate the class with ``@python_2_unicode_compatible``.
|
||||||
|
- Do not start int literals with a zero. This is a syntax error in Py3k.
|
||||||
|
- Unfortunately I did not find an octal notation that is valid in both
|
||||||
|
Pythons. Use decimal instead.
|
||||||
|
- use six, e.g.:
|
||||||
|
|
||||||
|
- ``isinstance(.., basestring) -> isinstance(.., six.string_types)``
|
||||||
|
- ``isinstance(.., unicode) -> isinstance(.., six.text_type)``
|
||||||
|
|
||||||
|
- ``setlocale()`` in Python 2 bails when we give the locale name as unicode,
|
||||||
|
and since we are using ``from __future__ import unicode_literals``, we do
|
||||||
|
that everywhere! As a workaround, I enclosed the localename with ``str()``;
|
||||||
|
in Python 2 this casts the name to a byte string, in Python 3 this should do
|
||||||
|
nothing, because the locale name already had been unicode.
|
||||||
|
|
||||||
|
- Kept range() almost everywhere as-is (2to3 suggests list(range())), just
|
||||||
|
changed it where I felt necessary.
|
||||||
|
|
||||||
|
- Changed xrange() back to range(), so it is valid in both Python versions.
|
||||||
189
docs/faq.rst
Normal file
189
docs/faq.rst
Normal file
|
|
@ -0,0 +1,189 @@
|
||||||
|
Frequently Asked Questions (FAQ)
|
||||||
|
################################
|
||||||
|
|
||||||
|
Here are some frequently asked questions about Pelican.
|
||||||
|
|
||||||
|
What's the best way to communicate a problem, question, or suggestion?
|
||||||
|
======================================================================
|
||||||
|
|
||||||
|
If you have a problem, question, or suggestion, please start by striking up a
|
||||||
|
conversation on `#pelican on Freenode <irc://irc.freenode.net/pelican>`_.
|
||||||
|
Those who don't have an IRC client handy can jump in immediately via
|
||||||
|
`IRC webchat <http://webchat.freenode.net/?channels=pelican&uio=d4>`_. Because
|
||||||
|
of differing time zones, you may not get an immediate response to your
|
||||||
|
question, but please be patient and stay logged into IRC — someone will almost
|
||||||
|
always respond if you wait long enough (it may take a few hours).
|
||||||
|
|
||||||
|
If you're unable to resolve your issue or if you have a feature request, please
|
||||||
|
refer to the `issue tracker <https://github.com/getpelican/pelican/issues>`_.
|
||||||
|
|
||||||
|
How can I help?
|
||||||
|
================
|
||||||
|
|
||||||
|
There are several ways to help out. First, you can report any Pelican
|
||||||
|
suggestions or problems you might have via IRC or the `issue tracker
|
||||||
|
<https://github.com/getpelican/pelican/issues>`_. If submitting an issue
|
||||||
|
report, please check the existing issue list first in order to avoid submitting
|
||||||
|
a duplicate issue.
|
||||||
|
|
||||||
|
If you want to contribute, please fork `the git repository
|
||||||
|
<https://github.com/getpelican/pelican/>`_, create a new feature branch, make
|
||||||
|
your changes, and issue a pull request. Someone will review your changes as
|
||||||
|
soon as possible. Please refer to the :doc:`How to Contribute <contribute>`
|
||||||
|
section for more details.
|
||||||
|
|
||||||
|
You can also contribute by creating themes and improving the documentation.
|
||||||
|
|
||||||
|
Is it mandatory to have a configuration file?
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
Configuration files are optional and are just an easy way to configure Pelican.
|
||||||
|
For basic operations, it's possible to specify options while invoking Pelican
|
||||||
|
via the command line. See ``pelican --help`` for more information.
|
||||||
|
|
||||||
|
I'm creating my own theme. How do I use Pygments for syntax highlighting?
|
||||||
|
=========================================================================
|
||||||
|
|
||||||
|
Pygments adds some classes to the generated content. These classes are used by
|
||||||
|
themes to style code syntax highlighting via CSS. Specifically, you can
|
||||||
|
customize the appearance of your syntax highlighting via the ``.highlight pre``
|
||||||
|
class in your theme's CSS file. To see how various styles can be used to render
|
||||||
|
Django code, for example, use the style selector drop-down at top-right on the
|
||||||
|
`Pygments project demo site <http://pygments.org/demo/15101/>`_.
|
||||||
|
|
||||||
|
You can use the following example commands to generate a starting CSS file from
|
||||||
|
a Pygments built-in style (in this case, "monokai") and then copy the generated
|
||||||
|
CSS file to your new theme::
|
||||||
|
|
||||||
|
pygmentize -S monokai -f html -a .highlight > pygment.css
|
||||||
|
cp pygment.css path/to/theme/static/css/
|
||||||
|
|
||||||
|
Don't forget to import your ``pygment.css`` file from your main CSS file.
|
||||||
|
|
||||||
|
How do I create my own theme?
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Please refer to :ref:`theming-pelican`.
|
||||||
|
|
||||||
|
I want to use Markdown, but I got an error.
|
||||||
|
===========================================
|
||||||
|
|
||||||
|
Markdown is not a hard dependency for Pelican, so you will need to explicitly
|
||||||
|
install it. You can do so by typing the following command, prepending ``sudo``
|
||||||
|
if permissions require it::
|
||||||
|
|
||||||
|
pip install markdown
|
||||||
|
|
||||||
|
If you don't have ``pip`` installed, consider installing it via::
|
||||||
|
|
||||||
|
easy_install pip
|
||||||
|
|
||||||
|
Can I use arbitrary metadata in my templates?
|
||||||
|
==============================================
|
||||||
|
|
||||||
|
Yes. For example, to include a modified date in a Markdown post, one could
|
||||||
|
include the following at the top of the article::
|
||||||
|
|
||||||
|
Modified: 2012-08-08
|
||||||
|
|
||||||
|
For reStructuredText, this metadata should of course be prefixed with a colon::
|
||||||
|
|
||||||
|
:Modified: 2012-08-08
|
||||||
|
|
||||||
|
This metadata can then be accessed in the template::
|
||||||
|
|
||||||
|
{% if article.modified %}
|
||||||
|
Last modified: {{ article.modified }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
How do I assign custom templates on a per-page basis?
|
||||||
|
=====================================================
|
||||||
|
|
||||||
|
It's as simple as adding an extra line of metadata to any page or article that
|
||||||
|
you want to have its own template. For example, this is how it would be handled
|
||||||
|
for content in reST format::
|
||||||
|
|
||||||
|
:template: template_name
|
||||||
|
|
||||||
|
For content in Markdown format::
|
||||||
|
|
||||||
|
Template: template_name
|
||||||
|
|
||||||
|
Then just make sure your theme contains the relevant template file (e.g.
|
||||||
|
``template_name.html``).
|
||||||
|
|
||||||
|
How can I override the generated URL of a specific page or article?
|
||||||
|
===================================================================
|
||||||
|
|
||||||
|
Include ``url`` and ``save_as`` metadata in any pages or articles that you want
|
||||||
|
to override the generated URL. Here is an example page in reST format::
|
||||||
|
|
||||||
|
Override url/save_as page
|
||||||
|
#########################
|
||||||
|
|
||||||
|
:url: override/url/
|
||||||
|
:save_as: override/url/index.html
|
||||||
|
|
||||||
|
With this metadata, the page will be written to ``override/url/index.html``
|
||||||
|
and Pelican will use url ``override/url/`` to link to this page.
|
||||||
|
|
||||||
|
How can I use a static page as my home page?
|
||||||
|
============================================
|
||||||
|
|
||||||
|
The override feature mentioned above can be used to specify a static page as
|
||||||
|
your home page. The following Markdown example could be stored in
|
||||||
|
``content/pages/home.md``::
|
||||||
|
|
||||||
|
Title: Welcome to My Site
|
||||||
|
URL:
|
||||||
|
save_as: index.html
|
||||||
|
|
||||||
|
Thank you for visiting. Welcome!
|
||||||
|
|
||||||
|
What if I want to disable feed generation?
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
To disable feed generation, all feed settings should be set to ``None``.
|
||||||
|
All but three feed settings already default to ``None``, so if you want to
|
||||||
|
disable all feed generation, you only need to specify the following settings::
|
||||||
|
|
||||||
|
FEED_ALL_ATOM = None
|
||||||
|
CATEGORY_FEED_ATOM = None
|
||||||
|
TRANSLATION_FEED_ATOM = None
|
||||||
|
|
||||||
|
Please note that ``None`` and ``''`` are not the same thing. The word ``None``
|
||||||
|
should not be surrounded by quotes.
|
||||||
|
|
||||||
|
I'm getting a warning about feeds generated without SITEURL being set properly
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
`RSS and Atom feeds require all URL links to be absolute
|
||||||
|
<http://validator.w3.org/feed/docs/rss2.html#comments>`_.
|
||||||
|
In order to properly generate links in Pelican you will need to set ``SITEURL``
|
||||||
|
to the full path of your site.
|
||||||
|
|
||||||
|
Feeds are still generated when this warning is displayed, but links within may
|
||||||
|
be malformed and thus the feed may not validate.
|
||||||
|
|
||||||
|
My feeds are broken since I upgraded to Pelican 3.x
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
Starting in 3.0, some of the FEED setting names were changed to more explicitly
|
||||||
|
refer to the Atom feeds they inherently represent (much like the FEED_RSS
|
||||||
|
setting names). Here is an exact list of the renamed settings::
|
||||||
|
|
||||||
|
FEED -> FEED_ATOM
|
||||||
|
TAG_FEED -> TAG_FEED_ATOM
|
||||||
|
CATEGORY_FEED -> CATEGORY_FEED_ATOM
|
||||||
|
|
||||||
|
Starting in 3.1, the new feed ``FEED_ALL_ATOM`` has been introduced: this
|
||||||
|
feed will aggregate all posts regardless of their language. This setting
|
||||||
|
generates ``'feeds/all.atom.xml'`` by default and ``FEED_ATOM`` now defaults to
|
||||||
|
``None``. The following feed setting has also been renamed::
|
||||||
|
|
||||||
|
TRANSLATION_FEED -> TRANSLATION_FEED_ATOM
|
||||||
|
|
||||||
|
Older themes that referenced the old setting names may not link properly.
|
||||||
|
In order to rectify this, please update your theme for compatibility by changing
|
||||||
|
the relevant values in your template files. For an example of complete feed
|
||||||
|
headers and usage please check out the ``simple`` theme.
|
||||||
20
docs/fr/astuces.rst
Normal file
20
docs/fr/astuces.rst
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
Trucs et astuces pour Pelican
|
||||||
|
#############################
|
||||||
|
|
||||||
|
Personnaliser l'url d'un article pour Pelican
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
Par défaut, quand vous créez un article ayant pour titre *Mon article pour Pelican*,
|
||||||
|
l'url par défaut devient *mon-article-pour-pelican.html*. Cependant, il est possible
|
||||||
|
de modifier cela en utilisant la technique utilisée pour les traductions d'article,
|
||||||
|
c'est à dire le paramètre *:slug:* ::
|
||||||
|
|
||||||
|
Mon article pour Pelican
|
||||||
|
########################
|
||||||
|
|
||||||
|
:date: 2011-01-31 11:05
|
||||||
|
:slug: super-article-pour-pelican
|
||||||
|
|
||||||
|
bla, bla, bla …
|
||||||
|
|
||||||
|
En prenant cet exemple ci dessus, votre url deviendra *super-article-pour-pelican.html*
|
||||||
58
docs/fr/bases.rst
Normal file
58
docs/fr/bases.rst
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
Les bases de Pelican
|
||||||
|
####################
|
||||||
|
|
||||||
|
Créer son premier article
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Pour créer notre premier article, nous allons éditer un fichier, par exemple premier_article.rst ::
|
||||||
|
|
||||||
|
Premier article pour Pelican
|
||||||
|
############################
|
||||||
|
:author: Guillaume
|
||||||
|
:date: 2011-01-08 10:20
|
||||||
|
:category: GNU-Linux
|
||||||
|
:tags: tutoriel, git
|
||||||
|
Ceci est un tutoriel pour configurer git.
|
||||||
|
Bla, bla, bla ....
|
||||||
|
|
||||||
|
Maintenant que ce fichier est créé, on va lancer la création du blog ::
|
||||||
|
|
||||||
|
pelican .
|
||||||
|
|
||||||
|
Vous aller obtenir une sortie comme celle ci — $PATH représente le dossier où vous
|
||||||
|
avez créé votre article ::
|
||||||
|
|
||||||
|
[ok] writing $PATH/output/feeds/all.atom.xml
|
||||||
|
[ok] writing $PATH/output/feeds/GNU/Linux.atom.xml
|
||||||
|
[ok] writing $PATH/output/feeds/all-en.atom.xml
|
||||||
|
[ok] writing $PATH/output/premier-article-pour-pelican.html
|
||||||
|
[ok] writing $PATH/output/index.html
|
||||||
|
[ok] writing $PATH/output/tags.html
|
||||||
|
[ok] writing $PATH/output/categories.html
|
||||||
|
[ok] writing $PATH/output/archives.html
|
||||||
|
[ok] writing $PATH/output/tag/tutoriel.html
|
||||||
|
[ok] writing $PATH/output/tag/git.html
|
||||||
|
[ok] writing $PATH/output/category/GNU-Linux.html
|
||||||
|
|
||||||
|
|
||||||
|
Première analyse
|
||||||
|
================
|
||||||
|
|
||||||
|
Nous allons décortiquer un peu tout ça ensemble.
|
||||||
|
|
||||||
|
* Un dossier output/ a été créé pour y mettre le fichiers xml et html du blog.
|
||||||
|
* Dans le dossier feeds/, nous retrouvons les différents flux de syndication.
|
||||||
|
* Le fichier de l’article et la page principale du blog a été généré.
|
||||||
|
* Le répertoire tag/ propose une page par tag.
|
||||||
|
* La page correspondant à la catégorie est générée dans le répertoire category/
|
||||||
|
|
||||||
|
Si vous ouvrez le fichier index.html — ou un autre — avec votre navigateur, vous
|
||||||
|
remarquerez que :
|
||||||
|
|
||||||
|
* Le thème utilisé par défaut est notmyidea
|
||||||
|
* Le nom du blog est A Pelican Blog.
|
||||||
|
|
||||||
|
Bien évidemment, il y a des paramètres de base que l’on peut modifier pour mettre
|
||||||
|
un peu tout ça à sa sauce. C’est ce que nous allons voir au travers du fichier de configuration.
|
||||||
|
|
||||||
|
|
||||||
165
docs/fr/configuration.rst
Normal file
165
docs/fr/configuration.rst
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
Fichier de configuration
|
||||||
|
************************
|
||||||
|
|
||||||
|
On va créer un fichier de configuration que l’on va appeler **settings.py**. On peut
|
||||||
|
utiliser Pelican sans faire ce fichier, mais il faudrait à chaque fois passer les paramètres
|
||||||
|
en ligne de commande. Et comme il va nous servir à faire d’autres choses bien utile,
|
||||||
|
autant l’appréhender de suite. Cependant, nous n’allons voir que la base pour l’instant.
|
||||||
|
|
||||||
|
Paramètres de base
|
||||||
|
==================
|
||||||
|
|
||||||
|
AUTHOR :
|
||||||
|
Désigne l’auteur par défaut ;
|
||||||
|
|
||||||
|
DEFAULT_CATEGORY :
|
||||||
|
La catégorie par défaut des articles. Si ce paramètre n’est
|
||||||
|
pas documenté, il prendra la valeur misc — pour miscellaneous (divers en français) ;
|
||||||
|
|
||||||
|
SITENAME :
|
||||||
|
Le nom de votre site ;
|
||||||
|
|
||||||
|
OUTPUT_PATH :
|
||||||
|
Le répertoire de sortie du blog.
|
||||||
|
|
||||||
|
Quand je dis qu’on va faire simple, on fait simple !
|
||||||
|
Passons donc à ce quoi doit ressembler le fichier de configuration ::
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
AUTHOR = "Guillaume"
|
||||||
|
DEFAULT_CATEGORY = "GNU-Linux"
|
||||||
|
SITENAME = "Free Culture"
|
||||||
|
|
||||||
|
|
||||||
|
Si vous avez un serveur comme Apache de configuré pour votre machine, vous
|
||||||
|
pouvez paramétrer le répertoire de sortie vers **/var/www/blog** par exemple ::
|
||||||
|
|
||||||
|
OUTPUT_PATH = "/var/www/blog"
|
||||||
|
|
||||||
|
Une remarque importante. Si vous avez besoin de passer un caractère accentué, il
|
||||||
|
faut le préciser que la chaine est en unicode en faisant par exemple
|
||||||
|
*AUTHOR = u"Guillaume LAMÉ"*
|
||||||
|
|
||||||
|
Pour bien vérifier que les paramètres sont bien pris en compte, nous allons enlever les lignes *:author: Guillaume* et *:category: GNU-Linux* de notre fichier
|
||||||
|
**premier_article.rst** et regénérer le blog.
|
||||||
|
|
||||||
|
Rafraichissez votre page, ce devrait être bon.
|
||||||
|
|
||||||
|
Nous allons maintenant passer en revue les différents paramètres de Pelican. Je les
|
||||||
|
ai regroupé par thème. Cependant, c’est surtout un listing avant de rentrer dans les
|
||||||
|
détails au prochain chapitre.
|
||||||
|
|
||||||
|
Flux de syndication
|
||||||
|
===================
|
||||||
|
|
||||||
|
CATEGORY_FEED_ATOM :
|
||||||
|
Chemin d’écriture des flux Atom liés aux catégories ;
|
||||||
|
|
||||||
|
CATEGORY_FEED_RSS :
|
||||||
|
Idem pour les flux rss (Optionnel);
|
||||||
|
|
||||||
|
FEED_ATOM :
|
||||||
|
Chemin du flux Atom global;
|
||||||
|
|
||||||
|
FEED_RSS :
|
||||||
|
Chemin du flux Rss global (Optionnel);
|
||||||
|
|
||||||
|
FEED_ALL_ATOM :
|
||||||
|
Chemin du flux Atom global qui inclut la totalité des posts, indépendamment de la langue;
|
||||||
|
|
||||||
|
FEED_ALL_RSS :
|
||||||
|
Chemin du flux Rss global qui inclut la totalité des posts, indépendamment de la langue (Optionnel);
|
||||||
|
|
||||||
|
TAG_FEED_ATOM :
|
||||||
|
Chemin des flux Atom pour les tags (Optionnel);
|
||||||
|
|
||||||
|
TAG_FEED_RSS :
|
||||||
|
Chemin des flux Rss pour les tags (Optionnel).
|
||||||
|
|
||||||
|
|
||||||
|
Traductions
|
||||||
|
===========
|
||||||
|
|
||||||
|
DEFAULT_LANG :
|
||||||
|
Le langage par défaut à utiliser. «*en*» par défaut ;
|
||||||
|
|
||||||
|
TRANSLATION_FEED_ATOM :
|
||||||
|
Chemin du flux Atom pour les traductions.
|
||||||
|
|
||||||
|
TRANSLATION_FEED_RSS :
|
||||||
|
Chemin du flux RSS pour les traductions.
|
||||||
|
|
||||||
|
|
||||||
|
Thèmes
|
||||||
|
======
|
||||||
|
|
||||||
|
CSS_FILE :
|
||||||
|
Fichier css à utiliser si celui-ci est différent du fichier par défaut (*main.css*) ;
|
||||||
|
|
||||||
|
DISPLAY_PAGES_ON_MENU :
|
||||||
|
Affiche ou non les pages statiques sur le menu du thème ;
|
||||||
|
|
||||||
|
DISQUS_SITENAME :
|
||||||
|
Indiquer le nom du site spécifié sur Disqus ;
|
||||||
|
|
||||||
|
GITHUB_URL :
|
||||||
|
Indiquez votre url Github ;
|
||||||
|
|
||||||
|
GOOGLE_ANALYTICS :
|
||||||
|
'UA-XXXX-YYYY' pour activer Google analytics ;
|
||||||
|
|
||||||
|
GOSQUARED_SITENAME :
|
||||||
|
'XXX-YYYYYY-X' pour activer GoSquared ;
|
||||||
|
|
||||||
|
JINJA_EXTENSIONS :
|
||||||
|
Liste d'extension Jinja2 que vous souhaitez utiliser ;
|
||||||
|
|
||||||
|
LINKS :
|
||||||
|
Une liste de tuples (Titre, url) pour afficher la liste de lien ;
|
||||||
|
|
||||||
|
PDF_PROCESSOR :
|
||||||
|
Génère ou non les articles et pages au format pdf ;
|
||||||
|
|
||||||
|
NEWEST_FIRST_ARCHIVES :
|
||||||
|
Met les articles plus récent en tête de l'archive ;
|
||||||
|
|
||||||
|
SOCIAL :
|
||||||
|
Une liste de tuples (Titre, url) pour afficher la liste de lien dans la section "Social" ;
|
||||||
|
|
||||||
|
STATIC_THEME_PATHS :
|
||||||
|
Répertoire du thème que vous souhaitez importer dans l'arborescence finale ;
|
||||||
|
|
||||||
|
THEME :
|
||||||
|
Thème à utiliser:
|
||||||
|
|
||||||
|
TWITTER_USERNAME :
|
||||||
|
Permet d'afficher un bouton permettant le tweet des articles.
|
||||||
|
|
||||||
|
Pelican est fournit avec :doc:`pelican-themes`, un script permettant de gérer les thèmes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Paramètres divers
|
||||||
|
=================
|
||||||
|
|
||||||
|
DEFAULT_DATE:
|
||||||
|
Date par défaut à utiliser si l'information de date n'est pas spécifiée
|
||||||
|
dans les metadonnées de l'article.
|
||||||
|
Si 'fs', Pelican se basera sur le *mtime* du fichier.
|
||||||
|
Si c'est un tuple, il sera passé au constructeur datetime.datetime pour
|
||||||
|
générer l'objet datetime utilisé par défaut.
|
||||||
|
|
||||||
|
KEEP_OUTPUT DIRECTORY :
|
||||||
|
Ne génère que les fichiers modifiés et n'efface pas le repertoire de sortie ;
|
||||||
|
|
||||||
|
MARKUP :
|
||||||
|
Langage de balisage à utiliser ;
|
||||||
|
|
||||||
|
PATH :
|
||||||
|
Répertoire à suivre pour les fichiers inclus ;
|
||||||
|
|
||||||
|
SITEURL :
|
||||||
|
URL de base de votre site ;
|
||||||
|
|
||||||
|
STATIC_PATHS :
|
||||||
|
Les chemins statiques que vous voulez avoir accès sur le chemin de sortie "statique" ;
|
||||||
18
docs/fr/conventions.rst
Normal file
18
docs/fr/conventions.rst
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
Conventions
|
||||||
|
###########
|
||||||
|
|
||||||
|
Environnement de test
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Les exemples sont basées sur une distribution Debian. Pour les autres distributions,
|
||||||
|
il y aura des ajustements à faire, notamment pour l’installation de Pelican. Les
|
||||||
|
noms des paquets peuvent changer.
|
||||||
|
|
||||||
|
Conventions typographiques
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Un petit rappel concernant les codes sources.
|
||||||
|
|
||||||
|
* $ correspond à une ligne à exécuter en tant qu’utilisateur courant du systême ;
|
||||||
|
* # correspond à une ligne à exécuter en tant que root ;
|
||||||
|
* **settings.py** : Les noms des répertoires et fichiers sont en gras.
|
||||||
40
docs/fr/faq.rst
Normal file
40
docs/fr/faq.rst
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
Foire aux questions (FAQ)
|
||||||
|
#########################
|
||||||
|
|
||||||
|
Voici un résumé des questions fréquemment posées pour pelican.
|
||||||
|
|
||||||
|
Est-il obligatoire d'avoir un fichier de configuration ?
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
Non. Les fichiers de configuration sont juste un moyen facile de configurer
|
||||||
|
pelican. Pour les opérations de base, il est possible de spécifier des
|
||||||
|
options
|
||||||
|
en invoquant pelican avec la ligne de commande (voir pelican --help pour
|
||||||
|
plus
|
||||||
|
d'informations à ce sujet)
|
||||||
|
|
||||||
|
Je crée mon propre thème, comment utiliser pygments?
|
||||||
|
====================================================
|
||||||
|
|
||||||
|
Pygment ajoute quelques classes au contenu généré, de sorte qua colorisation
|
||||||
|
de votre thème se fait grâce à un fichier css. Vous pouvez jeter un oeil à
|
||||||
|
celui proposé par`sur le site du projet <http://pygments.org/demo/15101/>`_
|
||||||
|
|
||||||
|
Comment puis-je créer mon propre thèm
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
Vueillez vous référer à :ref:`theming-pelican-fr`.
|
||||||
|
|
||||||
|
Comment puis-je aider?
|
||||||
|
======================
|
||||||
|
|
||||||
|
Vous avez plusieurs options pour aider. Tout d'abord, vous pouvez utiliser
|
||||||
|
le
|
||||||
|
pélican, et signaler toute idée ou problème que vous avez sur le bugtracker
|
||||||
|
.
|
||||||
|
|
||||||
|
Si vous voulez contribuer, jeter un oeil au dépôt git , ajoutez vos
|
||||||
|
modifications et faites une demande, je les regarderai dès que possible
|
||||||
|
|
||||||
|
Vous pouvez aussi contribuer en créant des thèmes, et/ou compléter la
|
||||||
|
documentation.
|
||||||
57
docs/fr/index.rst
Normal file
57
docs/fr/index.rst
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
Pelican
|
||||||
|
#######
|
||||||
|
|
||||||
|
Pelican est un generateur de blog simple codé en python
|
||||||
|
|
||||||
|
* Écrivez vos articles directement dans votre éditeur favori (vim !) et
|
||||||
|
directement en syntaxe reStructuredText ou Markdown ;
|
||||||
|
* Un outil simple en ligne de conmmande pour (re)générer le blog ;
|
||||||
|
* Sortie complètement statique, facile pour l'héberger n'importe où ;
|
||||||
|
|
||||||
|
Fonctionnalités
|
||||||
|
===============
|
||||||
|
|
||||||
|
Pelican supporte actuellement :
|
||||||
|
|
||||||
|
* des articles de blog ;
|
||||||
|
* des pages statiques ;
|
||||||
|
* les commentaires via un service externe (`disqus <http://disqus.com>`_)
|
||||||
|
Notez qu'étant bien un service externe assez pratique, vous ne gérez pas
|
||||||
|
vous même les commentaires. Ce qui pourrait occasionner une perte de vos données;
|
||||||
|
* support de template (les templates sont crées avec `jinja2 <http://jinjna.pocoo.org>`_) ;
|
||||||
|
* génération optionnelle de vos pages et articles en pdf.
|
||||||
|
|
||||||
|
Pourquoi le nom "Pelican" ?
|
||||||
|
============================
|
||||||
|
|
||||||
|
Vous n'avez pas remarqué ? "Pelican" est un anagramme pour "Calepin" ;)
|
||||||
|
|
||||||
|
Code source
|
||||||
|
===========
|
||||||
|
|
||||||
|
Vous pouvez accéder au code source via git à l'adresse
|
||||||
|
http://github.com/getpelican/pelican/
|
||||||
|
|
||||||
|
Feedback !
|
||||||
|
==========
|
||||||
|
|
||||||
|
Si vous voulez de nouvelles fonctionnalitées pour Pelican, n'hésitez pas à nous le dire,
|
||||||
|
à cloner le dépôt, etc … C'est open source !!!
|
||||||
|
|
||||||
|
Contactez Alexis à "alexis at notmyidea dot org" pour quelques requêtes ou retour d'expérience que ce soi !
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
conventions
|
||||||
|
installation
|
||||||
|
bases
|
||||||
|
configuration
|
||||||
|
themes
|
||||||
|
parametres_article
|
||||||
|
astuces
|
||||||
|
faq
|
||||||
|
pelican-themes
|
||||||
67
docs/fr/installation.rst
Normal file
67
docs/fr/installation.rst
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
Installation et mise à jour de Pelican
|
||||||
|
######################################
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Il y a deux façons d’installer Pelican sur son système. La première est via l’utilitaire
|
||||||
|
pip, l’autre façon est de télécharger Pelican via Github. Ici nous allons voir les deux
|
||||||
|
façons de procéder.
|
||||||
|
|
||||||
|
Via pip
|
||||||
|
-------
|
||||||
|
|
||||||
|
Pour installer Pelican via pip, vous aurez besoin du paquet python-pip. puis installez Pelican ::
|
||||||
|
|
||||||
|
# apt-get install python-pip
|
||||||
|
# pip install pelican
|
||||||
|
|
||||||
|
|
||||||
|
Via Github
|
||||||
|
----------
|
||||||
|
|
||||||
|
Pour installer Pelican en reprenant le code via Github, nous aurons besoin du paquet
|
||||||
|
git-core pour récupérez les sources de Pelican. Puis nous procédons à l’installation ::
|
||||||
|
|
||||||
|
# apt-get install git-core
|
||||||
|
$ git clone https://github.com/getpelican/pelican.git
|
||||||
|
$ cd pelican
|
||||||
|
# python setup.py install
|
||||||
|
|
||||||
|
Mises à jour
|
||||||
|
============
|
||||||
|
|
||||||
|
Via pip
|
||||||
|
-------
|
||||||
|
|
||||||
|
Rien de bien compliqué pour mettre à jour via pip ::
|
||||||
|
|
||||||
|
$ cd votreRepertoireSource
|
||||||
|
$ pip install --upgrade pelican
|
||||||
|
|
||||||
|
|
||||||
|
Via Github
|
||||||
|
----------
|
||||||
|
|
||||||
|
C'est un peu plus long avec Github par contre ::
|
||||||
|
|
||||||
|
$ cd votreRepertoireSource
|
||||||
|
$ git pull origin master
|
||||||
|
$ cd pelican
|
||||||
|
# python setup.py install
|
||||||
|
|
||||||
|
Vous aurez un message d’erreur si le module setuptools de python n’est pas installé.
|
||||||
|
La manipulation est la suivante ::
|
||||||
|
|
||||||
|
# apt-get install python-setuptools
|
||||||
|
|
||||||
|
Alors, quelle méthode choisir ?
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Vous avez le choix entre deux méthodes, mais aussi entre deux concepts. La méthode
|
||||||
|
de Github est la version de développement, où les modifications arrivent assez
|
||||||
|
fréquemment sans être testées à fond. La version de pip est une version arrêtée avec un
|
||||||
|
numéro de version dans laquelle vous aurez moins de bug. N’oubliez cependant pas
|
||||||
|
que le projet est très jeune et manque donc de maturité. Si vous aimez avoir les toutes
|
||||||
|
dernières versions utilisez Github, sinon penchez vous sur pip.
|
||||||
|
|
||||||
106
docs/fr/parametres_article.rst
Normal file
106
docs/fr/parametres_article.rst
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
Les paramètres des articles dans Pelican
|
||||||
|
########################################
|
||||||
|
|
||||||
|
Les catégories
|
||||||
|
==============
|
||||||
|
|
||||||
|
Nous avons vu que pour affecter un article à une catégorie, nous avions le paramètre *:category:*.
|
||||||
|
Il y a cependant plus simple, affecter un répertoire à une catégorie.
|
||||||
|
|
||||||
|
Dans le répertoire ou vous avez vos articles, créez le repertoire **GNU-Linux** et déplacez y le fichier
|
||||||
|
**premier_article.rst**. Bien évidemment nous ne verront pas la différence, car jusqu'ici *GNU-Linux*
|
||||||
|
est notre catégorie par défaut.
|
||||||
|
|
||||||
|
Nous allons faire un autre exemple d'article avec la catégorie Pelican. Créez le répertoire **Pelican**
|
||||||
|
et collez cette exemple d'article ::
|
||||||
|
|
||||||
|
Préparation de la documentation
|
||||||
|
###############################
|
||||||
|
|
||||||
|
:date: 2011-01-27 15:28
|
||||||
|
:tags: documentation
|
||||||
|
|
||||||
|
Il y a quand même pas mal de boulot pour faire une documentation !
|
||||||
|
|
||||||
|
Et lancez la compilation du blog. Vous voyez que la catégorie est affectée automatiquement.
|
||||||
|
|
||||||
|
Les tags
|
||||||
|
========
|
||||||
|
|
||||||
|
Pour les tags, il n'y a rien de compliqué. il suffit de mettre le(s) tags séparés si besoin d'une virgule. ::
|
||||||
|
|
||||||
|
Préparation de la documentation
|
||||||
|
###############################
|
||||||
|
|
||||||
|
:date: 2011-01-27 15:28
|
||||||
|
:tags: documentation, pelican
|
||||||
|
|
||||||
|
Par contre, par soucis de clarté au niveau des url je vous conseille de mettre les expression de plusieurs
|
||||||
|
mots séparées par des tirets ::
|
||||||
|
|
||||||
|
:tags: mise-a-jour
|
||||||
|
|
||||||
|
et non ::
|
||||||
|
|
||||||
|
:tags: mise a jour
|
||||||
|
|
||||||
|
|
||||||
|
Les auteurs
|
||||||
|
===========
|
||||||
|
|
||||||
|
Par défaut, vous pouvez indiqué votre nom en tant qu'auteur dans le fichier de configuration.
|
||||||
|
S'il y a plusieurs auteurs pour le site, vous pouvez le définir manuellement dans
|
||||||
|
l'article avec la méta-donnée ::
|
||||||
|
|
||||||
|
:author: Guillaume
|
||||||
|
|
||||||
|
La date
|
||||||
|
=======
|
||||||
|
|
||||||
|
La date se met au format anglophone : **YYYY-MM-DD hh:mm** ::
|
||||||
|
|
||||||
|
:date: 2011-01-31 14:12
|
||||||
|
|
||||||
|
|
||||||
|
Les traductions
|
||||||
|
===============
|
||||||
|
|
||||||
|
Pelican permet de générer un blog multilingue assez facilement. Pour cela nous devons :
|
||||||
|
|
||||||
|
* Définir la langue de base du blog ;
|
||||||
|
* Donner une référence à l'article initial ;
|
||||||
|
* Définir la langue du fichier traduit et y reporter la référence.
|
||||||
|
|
||||||
|
Pour définir la langue de base nous allons modifier le fichier **settings.py** et y rajouter la ligne suivante ::
|
||||||
|
|
||||||
|
DEFAULT_LANG = "fr"
|
||||||
|
|
||||||
|
Puis ajouter la référence dans notre article d'origine qui deviendra ::
|
||||||
|
|
||||||
|
Préparation de la documentation
|
||||||
|
###############################
|
||||||
|
|
||||||
|
:date: 2011-01-27 15:28
|
||||||
|
:tags: documentation
|
||||||
|
:slug: preparation-de-la-documentation
|
||||||
|
|
||||||
|
Il y a quand même pas mal de boulot pour faire une documentation !
|
||||||
|
|
||||||
|
Nous n'avons plus qu'à créer l'article en anglais ::
|
||||||
|
|
||||||
|
Start of documentation
|
||||||
|
######################
|
||||||
|
|
||||||
|
:slug: preparation-de-la-documention
|
||||||
|
:lang: en
|
||||||
|
|
||||||
|
There are still a lot of work to documentation !
|
||||||
|
|
||||||
|
**Il est important de comprendre que la valeur de :slug: deviendra votre url. Ne mettez donc pas un diminutif pour
|
||||||
|
identifier l'article**
|
||||||
|
|
||||||
|
Rien de plus à savoir pour traduire efficacement des articles.
|
||||||
|
|
||||||
|
|
||||||
|
Maintenant que vous avez toutes les clés en main pour créer un article, nous allons passer à la personnalisation
|
||||||
|
du fichier de configuration.
|
||||||
172
docs/fr/pelican-themes.rst
Normal file
172
docs/fr/pelican-themes.rst
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
pelican-themes
|
||||||
|
##############
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
|
||||||
|
``pelican-themes`` est un outil en lignes de commandes pour gérer les thèmes de Pelican.
|
||||||
|
|
||||||
|
|
||||||
|
Utilisation:
|
||||||
|
""""""""""""
|
||||||
|
|
||||||
|
| pelican-themes [-h] [-l] [-i *chemin d'un thème* [*chemin d'un thème* ...]]
|
||||||
|
| [-r *nom d'un thème* [*nom d'un thème* ...]]
|
||||||
|
| [-s *chemin d'un thème* [*chemin d'un thème* ...]] [-v] [--version]
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
""""""""""
|
||||||
|
|
||||||
|
|
||||||
|
-h, --help Afficher l'aide et quitter
|
||||||
|
|
||||||
|
-l, --list Montrer les thèmes installés
|
||||||
|
|
||||||
|
-i chemin, --install chemin Chemin(s) d'accès d'un ou plusieurs thème à installer
|
||||||
|
|
||||||
|
-r nom, --remove nom Noms d'un ou plusieurs thèmes à installer
|
||||||
|
|
||||||
|
-s chemin, --symlink chemin Fonctionne de la même façon que l'option ``--install``, mais crée un lien symbolique au lieu d'effectuer une copie du thème vers le répertoire des thèmes.
|
||||||
|
Utile pour le développement de thèmes.
|
||||||
|
|
||||||
|
-v, --verbose Sortie détaillée
|
||||||
|
|
||||||
|
--version Affiche la version du script et quitte
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Exemples
|
||||||
|
========
|
||||||
|
|
||||||
|
|
||||||
|
Lister les thèmes installés
|
||||||
|
"""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
``pelican-themes`` peut afficher les thèmes disponibles.
|
||||||
|
|
||||||
|
Pour cela, vous pouvez utiliser l'option ``-l`` ou ``--list``, comme ceci:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ pelican-themes -l
|
||||||
|
notmyidea
|
||||||
|
two-column@
|
||||||
|
simple
|
||||||
|
$ pelican-themes --list
|
||||||
|
notmyidea
|
||||||
|
two-column@
|
||||||
|
simple
|
||||||
|
|
||||||
|
Dans cet exemple, nous voyons qu'il y a trois thèmes d'installés: ``notmyidea``, ``simple`` and ``two-column``.
|
||||||
|
|
||||||
|
``two-column`` est suivi d'un ``@`` par ce que c'est un lien symbolique (voir `Créer des liens symboliques`_).
|
||||||
|
|
||||||
|
Notez que vous pouvez combiner l'option ``--list`` avec l'option ``--verbose``, pour afficher plus de détails:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ pelican-themes -v -l
|
||||||
|
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/notmyidea
|
||||||
|
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/two-column (symbolic link to `/home/skami/Dev/Python/pelican-themes/two-column')
|
||||||
|
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/simple
|
||||||
|
|
||||||
|
|
||||||
|
Installer des thèmes
|
||||||
|
""""""""""""""""""""
|
||||||
|
|
||||||
|
Vous pouvez installer un ou plusieurs thèmes en utilisant l'option ``-i`` ou ``--install``.
|
||||||
|
|
||||||
|
Cette option prends en argument le(s) chemin(s) d'accès du ou des thème(s) que vous voulez installer, et peut se combiner avec l'option ``--verbose``:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms --verbose
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms\
|
||||||
|
~/Dev/Python/pelican-themes/martyalchin \
|
||||||
|
--verbose
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes -vi ~/Dev/Python/pelican-themes/two-column
|
||||||
|
|
||||||
|
|
||||||
|
Supprimer des thèmes
|
||||||
|
""""""""""""""""""""
|
||||||
|
|
||||||
|
``pelican-themes`` peut aussi supprimer des thèmes précédemment installés grâce à l'option ``-r`` ou ``--remove``.
|
||||||
|
|
||||||
|
Cette option prends en argument le ou les nom(s) des thèmes que vous voulez installer, et peux se combiner avec l'option ``--verbose``:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --remove two-column
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes -r martyachin notmyidea-cmd -v
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Créer des liens symboliques
|
||||||
|
"""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
|
||||||
|
L'option ``-s`` ou ``--symlink`` de ``pelican-themes`` permet de lier symboliquement un thème.
|
||||||
|
|
||||||
|
Cette option s'utilise exactement comme l'option ``--install``:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --symlink ~/Dev/Python/pelican-themes/two-column
|
||||||
|
|
||||||
|
Dans l'exemple ci dessus, un lien symbolique pointant vers le thème ``two-column`` a été installé dans le répertoire des thèmes de Pelican, toute modification sur le thème ``two-column`` prendra donc effet immédiatement.
|
||||||
|
|
||||||
|
Cela peut être pratique pour le développement de thèmes
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ sudo pelican-themes -s ~/Dev/Python/pelican-themes/two-column
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
$ firefox /tmp/out/index.html
|
||||||
|
$ vim ~/Dev/Pelican/pelican-themes/two-coumn/static/css/main.css
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
$ cp /tmp/bg.png ~/Dev/Pelican/pelican-themes/two-coumn/static/img/bg.png
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
$ vim ~/Dev/Pelican/pelican-themes/two-coumn/templates/index.html
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
|
||||||
|
|
||||||
|
Notez que cette fonctionnalité nécessite d'avoir un système d'exploitation et un système de fichiers supportant les liens symboliques, elle n'est donc pas disponible sous Micro$oft®©™ Fenêtre®©™.
|
||||||
|
|
||||||
|
Faire plusieurs choses à la fois
|
||||||
|
""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
|
||||||
|
Les options ``--install``, ``--remove`` et ``--symlink`` peuvent être employées en même temps, ce qui permets de réaliser plusieurs opérations en même temps:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --remove notmyidea-cms two-column \
|
||||||
|
--install ~/Dev/Python/pelican-themes/notmyidea-cms-fr \
|
||||||
|
--symlink ~/Dev/Python/pelican-themes/two-column \
|
||||||
|
--verbose
|
||||||
|
|
||||||
|
Dans cette exemple, le thème ``notmyidea-cms`` sera remplacé par le thème ``notmyidea-cms-fr`` et le thème ``two-column`` sera lié symboliquement...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
À voir également
|
||||||
|
================
|
||||||
|
|
||||||
|
- http://docs.notmyidea.org/alexis/pelican/
|
||||||
|
- ``/usr/share/doc/pelican/`` si vous avez installé Pelican par le `dépôt APT <http://skami18.github.com/pelican-packages/>`_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
171
docs/fr/themes.rst
Normal file
171
docs/fr/themes.rst
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
.. _theming-pelican:
|
||||||
|
|
||||||
|
Cette page est une traduction de la documentation originale, en anglais et
|
||||||
|
disponible `ici <../themes.html>`_.
|
||||||
|
|
||||||
|
Comment créer des thèmes pour Pelican
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
Pelican utlise le très bon moteur de template `jinja2 <http://jinja.pocoo.org>`_
|
||||||
|
pour produire de l'HTML. La syntaxe de jinja2 est vraiment très simple. Si vous
|
||||||
|
voulez créer votre propre thème, soyez libre de prendre inspiration sur le theme
|
||||||
|
"simple" qui est disponible `ici
|
||||||
|
<https://github.com/getpelican/pelican/tree/master/pelican/themes/simple/templates>`_
|
||||||
|
|
||||||
|
Structure
|
||||||
|
=========
|
||||||
|
|
||||||
|
Pour réaliser votre propre thème vous devez respecter la structure suivante ::
|
||||||
|
|
||||||
|
├── static
|
||||||
|
│ ├── css
|
||||||
|
│ └── images
|
||||||
|
└── templates
|
||||||
|
├── archives.html // pour afficher les archives
|
||||||
|
├── article.html // généré pour chaque article
|
||||||
|
├── categories.html // doit lister toutes les catégories
|
||||||
|
├── category.html // généré pour chaque catégorie
|
||||||
|
├── index.html // la page d'index, affiche tous les articles
|
||||||
|
├── page.html // généré pour chaque page
|
||||||
|
├── tag.html // généré pour chaque tag
|
||||||
|
└── tags.html // doit lister tous les tags. Peut être un nuage de tag.
|
||||||
|
|
||||||
|
|
||||||
|
* `static` contient tout le contenu statique. Il sera copié dans le dossier
|
||||||
|
`theme/static`. J'ai mis un dossier css et un image, mais ce sont juste des
|
||||||
|
exemples. Mettez ce dont vous avez besoin ici.
|
||||||
|
|
||||||
|
* `templates` contient tous les templates qui vont être utiliser pour générer les
|
||||||
|
pages. J'ai juste mis les templates obligatoires ici, vous pouvez définir les
|
||||||
|
vôtres si cela vous aide à vous organiser pendant que vous réaliser le thème.
|
||||||
|
Vous pouvez par exemple utiliser les directives {% include %} et {% extends %}
|
||||||
|
de jinja2.
|
||||||
|
|
||||||
|
Templates et variables
|
||||||
|
======================
|
||||||
|
|
||||||
|
Cela utilise une syntaxe simple, que vous pouvez insérer dans vos pages HTML.
|
||||||
|
Ce document décrit les templates qui doivent exister dans un thème, et quelles
|
||||||
|
variables seront passées à chaque template, au moment de le générer.
|
||||||
|
|
||||||
|
Tous les templates recevront les variables définies dans votre fichier de
|
||||||
|
configuration, si elles sont en capitales. Vous pouvez y accéder directement.
|
||||||
|
|
||||||
|
Variables communes
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Toutes ces variables seront passées à chaque template.
|
||||||
|
|
||||||
|
============= ===================================================
|
||||||
|
Variable Description
|
||||||
|
============= ===================================================
|
||||||
|
articles C'est la liste des articles, ordonnée décroissante
|
||||||
|
par date. Tous les éléments de la liste sont des
|
||||||
|
objets `Article`, vous pouvez donc accéder à leurs
|
||||||
|
propriétés (exemple : title, summary, author, etc).
|
||||||
|
dates La même liste d'articles, ordonnée croissante par
|
||||||
|
date.
|
||||||
|
tags Un dictionnaire contenant tous les tags (clés), et
|
||||||
|
la liste des articles correspondants à chacun
|
||||||
|
d'entre eux (valeur).
|
||||||
|
categories Un dictionnaire contenant toutes les catégories
|
||||||
|
(clés), et la liste des articles correspondants à
|
||||||
|
chacune d'entre elles (valeur).
|
||||||
|
pages La liste des pages.
|
||||||
|
============= ===================================================
|
||||||
|
|
||||||
|
index.html
|
||||||
|
----------
|
||||||
|
|
||||||
|
La page d'accueil de votre blog, sera générée dans output/index.html.
|
||||||
|
|
||||||
|
Si la pagination est activée, les pages suivantes seront à l'adresse
|
||||||
|
output/index`n`.html.
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
articles_paginator Un objet paginator de la liste d'articles.
|
||||||
|
articles_page La page actuelle d'articles.
|
||||||
|
dates_paginator Un objet paginator de la liste d'articles, ordonné
|
||||||
|
par date croissante.
|
||||||
|
dates_pages La page actuelle d'articles, ordonnée par date
|
||||||
|
croissante.
|
||||||
|
page_name 'index'.
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
|
category.html
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Ce template sera généré pour chaque catégorie existante, et se retrouvera
|
||||||
|
finalement à output/category/`nom de la catégorie`.html.
|
||||||
|
|
||||||
|
Si la pagination est activée, les pages suivantes seront disponibles à
|
||||||
|
l'adresse output/category/`nom de la catégorie``n`.html.
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
category La catégorie qui est en train d'être générée.
|
||||||
|
articles Les articles dans cette catégorie.
|
||||||
|
dates Les articles dans cette catégorie, ordonnés par
|
||||||
|
date croissante.
|
||||||
|
articles_paginator Un objet paginator de la liste d'articles.
|
||||||
|
articles_page La page actuelle d'articles.
|
||||||
|
dates_paginator Un objet paginator de la liste d'articles, ordonné
|
||||||
|
par date croissante.
|
||||||
|
dates_pages La page actuelle d'articles, ordonnée par date
|
||||||
|
croissante.
|
||||||
|
page_name 'category/`nom de la catégorie`'.
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
|
article.html
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Ce template sera généré pour chaque article. Les fichiers .html seront
|
||||||
|
disponibles à output/`nom de l'article`.html.
|
||||||
|
|
||||||
|
============= ===================================================
|
||||||
|
Variable Description
|
||||||
|
============= ===================================================
|
||||||
|
article L'objet article à afficher.
|
||||||
|
category Le nom de la catégorie de l'article actuel.
|
||||||
|
============= ===================================================
|
||||||
|
|
||||||
|
page.html
|
||||||
|
---------
|
||||||
|
|
||||||
|
Pour chaque page ce template sera généré à l'adresse
|
||||||
|
output/`nom de la page`.html
|
||||||
|
|
||||||
|
============= ===================================================
|
||||||
|
Variable Description
|
||||||
|
============= ===================================================
|
||||||
|
page L'objet page à afficher. Vous pouvez accéder à son
|
||||||
|
titre (title), slug, et son contenu (content).
|
||||||
|
============= ===================================================
|
||||||
|
|
||||||
|
tag.html
|
||||||
|
--------
|
||||||
|
|
||||||
|
Ce template sera généré pour chaque tag. Cela créera des fichiers .html à
|
||||||
|
l'adresse output/tag/`nom du tag`.html.
|
||||||
|
|
||||||
|
Si la pagination est activée, les pages suivantes seront disponibles à
|
||||||
|
l'adresse output/tag/`nom du tag``n`.html
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
tag Nom du tag à afficher.
|
||||||
|
articles Une liste des articles contenant ce tag.
|
||||||
|
dates Une liste des articles contenant ce tag, ordonnée
|
||||||
|
par date croissante.
|
||||||
|
articles_paginator Un objet paginator de la liste d'articles.
|
||||||
|
articles_page La page actuelle d'articles.
|
||||||
|
dates_paginator Un objet paginator de la liste d'articles, ordonné
|
||||||
|
par date croissante.
|
||||||
|
dates_pages La page actuelle d'articles, ordonnée par date
|
||||||
|
croissante.
|
||||||
|
page_name 'tag/`nom du tag`'.
|
||||||
|
=================== ===================================================
|
||||||
486
docs/getting_started.rst
Normal file
486
docs/getting_started.rst
Normal file
|
|
@ -0,0 +1,486 @@
|
||||||
|
Getting started
|
||||||
|
###############
|
||||||
|
|
||||||
|
Installing Pelican
|
||||||
|
==================
|
||||||
|
|
||||||
|
Pelican currently runs best on Python 2.7.x; earlier versions of Python are
|
||||||
|
not supported. There is provisional support for Python 3.3, although there may
|
||||||
|
be rough edges, particularly with regards to optional 3rd-party components.
|
||||||
|
|
||||||
|
You can install Pelican via several different methods. The simplest is via
|
||||||
|
`pip <http://www.pip-installer.org/>`_::
|
||||||
|
|
||||||
|
$ pip install pelican
|
||||||
|
|
||||||
|
If you don't have ``pip`` installed, an alternative method is
|
||||||
|
``easy_install``::
|
||||||
|
|
||||||
|
$ easy_install pelican
|
||||||
|
|
||||||
|
(Keep in mind that operating systems will often require you to prefix the above
|
||||||
|
commands with ``sudo`` in order to install Pelican system-wide.)
|
||||||
|
|
||||||
|
While the above is the simplest method, the recommended approach is to create
|
||||||
|
a virtual environment for Pelican via virtualenv_ before installing Pelican.
|
||||||
|
Assuming you have virtualenv_ installed, you can then open a new terminal
|
||||||
|
session and create a new virtual environment for Pelican::
|
||||||
|
|
||||||
|
$ virtualenv ~/virtualenvs/pelican
|
||||||
|
$ cd ~/virtualenvs/pelican
|
||||||
|
$ . bin/activate
|
||||||
|
|
||||||
|
Once the virtual environment has been created and activated, Pelican can be
|
||||||
|
be installed via ``pip install pelican`` as noted above. Alternatively, if
|
||||||
|
you have the project source, you can install Pelican using the distutils
|
||||||
|
method::
|
||||||
|
|
||||||
|
$ cd path-to-Pelican-source
|
||||||
|
$ python setup.py install
|
||||||
|
|
||||||
|
If you have Git installed and prefer to install the latest bleeding-edge
|
||||||
|
version of Pelican rather than a stable release, use the following command::
|
||||||
|
|
||||||
|
$ pip install -e git://github.com/getpelican/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
|
||||||
|
|
||||||
|
If you want to use AsciiDoc you need to install it from `source
|
||||||
|
<http://www.methods.co.nz/asciidoc/INSTALL.html>`_ or use your operating
|
||||||
|
system's package manager.
|
||||||
|
|
||||||
|
Basic usage
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Once Pelican is installed, you can use it to convert your Markdown or reST
|
||||||
|
content into HTML via the ``pelican`` command, specifying the path to your
|
||||||
|
content and (optionally) the path to your settings file::
|
||||||
|
|
||||||
|
$ pelican /path/to/your/content/ [-s path/to/your/settings.py]
|
||||||
|
|
||||||
|
The above command will generate your site and save it in the ``output/``
|
||||||
|
folder, using the default theme to produce a simple site. The default theme
|
||||||
|
consists of very simple HTML without styling and is provided so folks may use
|
||||||
|
it as a basis for creating their own themes.
|
||||||
|
|
||||||
|
You can also 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.
|
||||||
|
|
||||||
|
Pelican has other command-line switches available. Have a look at the help to
|
||||||
|
see all the options you can use::
|
||||||
|
|
||||||
|
$ pelican --help
|
||||||
|
|
||||||
|
Continue reading below for more detail, and check out the Pelican wiki's
|
||||||
|
`Tutorials <https://github.com/getpelican/pelican/wiki/Tutorials>`_ page for
|
||||||
|
links to community-published tutorials.
|
||||||
|
|
||||||
|
Viewing the generated files
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
The files generated by Pelican are static files, so you don't actually need
|
||||||
|
anything special to view them. You can either use your browser to open the
|
||||||
|
files on your disk::
|
||||||
|
|
||||||
|
firefox output/index.html
|
||||||
|
|
||||||
|
Or run a simple web server using Python::
|
||||||
|
|
||||||
|
cd output && python -m SimpleHTTPServer
|
||||||
|
|
||||||
|
Upgrading
|
||||||
|
---------
|
||||||
|
|
||||||
|
If you installed a stable Pelican release via ``pip`` or ``easy_install`` and
|
||||||
|
wish to upgrade to the latest stable release, you can do so by adding
|
||||||
|
``--upgrade`` to the relevant command. For pip, that would be::
|
||||||
|
|
||||||
|
$ pip install --upgrade pelican
|
||||||
|
|
||||||
|
If you installed Pelican via distutils or the bleeding-edge method, simply
|
||||||
|
perform the same step to install the most recent version.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
When Pelican is installed, the following dependent Python packages should be
|
||||||
|
automatically installed without any action on your part:
|
||||||
|
|
||||||
|
* `feedgenerator <http://pypi.python.org/pypi/feedgenerator>`_, to generate the
|
||||||
|
Atom feeds
|
||||||
|
* `jinja2 <http://pypi.python.org/pypi/Jinja2>`_, for templating support
|
||||||
|
* `pygments <http://pypi.python.org/pypi/Pygments>`_, for syntax highlighting
|
||||||
|
* `docutils <http://pypi.python.org/pypi/docutils>`_, for supporting
|
||||||
|
reStructuredText as an input format
|
||||||
|
* `pytz <http://pypi.python.org/pypi/pytz>`_, for timezone definitions
|
||||||
|
* `blinker <http://pypi.python.org/pypi/blinker>`_, an object-to-object and
|
||||||
|
broadcast signaling system
|
||||||
|
* `unidecode <http://pypi.python.org/pypi/Unidecode>`_, for ASCII
|
||||||
|
transliterations of Unicode text
|
||||||
|
* `six <http://pypi.python.org/pypi/six>`_, for Python 2 and 3 compatibility
|
||||||
|
utilities
|
||||||
|
* `MarkupSafe <http://pypi.python.org/pypi/MarkupSafe>`_, for a markup safe
|
||||||
|
string implementation
|
||||||
|
|
||||||
|
If you want the following optional packages, you will need to install them
|
||||||
|
manually via ``pip``:
|
||||||
|
|
||||||
|
* `markdown <http://pypi.python.org/pypi/Markdown>`_, for supporting Markdown as
|
||||||
|
an input format
|
||||||
|
* `typogrify <http://pypi.python.org/pypi/typogrify>`_, for typographical
|
||||||
|
enhancements
|
||||||
|
|
||||||
|
Kickstart your site
|
||||||
|
===================
|
||||||
|
|
||||||
|
Once Pelican has been installed, you can create a skeleton project via the
|
||||||
|
``pelican-quickstart`` command, which begins by asking some questions about
|
||||||
|
your site::
|
||||||
|
|
||||||
|
$ pelican-quickstart
|
||||||
|
|
||||||
|
Once you finish answering all the questions, your project will consist of the
|
||||||
|
following hierarchy (except for "pages", which you can optionally add yourself
|
||||||
|
if you plan to create non-chronological content)::
|
||||||
|
|
||||||
|
yourproject/
|
||||||
|
├── content
|
||||||
|
│ └── (pages)
|
||||||
|
├── output
|
||||||
|
├── develop_server.sh
|
||||||
|
├── Makefile
|
||||||
|
├── pelicanconf.py # Main settings file
|
||||||
|
└── publishconf.py # Settings to use when ready to publish
|
||||||
|
|
||||||
|
The next step is to begin to 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 written some content to generate, you can use the ``pelican``
|
||||||
|
command to generate your site, which will be placed in the output folder.
|
||||||
|
Alternatively, you can use automation tools that "wrap" the ``pelican`` command
|
||||||
|
to simplify the process of generating, previewing, and uploading your site. One
|
||||||
|
such tool is the ``Makefile`` that's automatically created for you when you use
|
||||||
|
``pelican-quickstart`` to create a skeleton project. To use ``make`` to
|
||||||
|
generate your site, run::
|
||||||
|
|
||||||
|
$ make html
|
||||||
|
|
||||||
|
If you'd prefer to have Pelican automatically regenerate your site every time a
|
||||||
|
change is detected (which is handy when testing locally), use the following
|
||||||
|
command instead::
|
||||||
|
|
||||||
|
$ make regenerate
|
||||||
|
|
||||||
|
To serve the generated site so it can be previewed in your browser at
|
||||||
|
http://localhost:8000::
|
||||||
|
|
||||||
|
$ make serve
|
||||||
|
|
||||||
|
Normally you would need to run ``make regenerate`` and ``make serve`` in two
|
||||||
|
separate terminal sessions, but you can run both at once via::
|
||||||
|
|
||||||
|
$ make devserver
|
||||||
|
|
||||||
|
The above command will simultaneously run Pelican in regeneration mode as well
|
||||||
|
as serve the output at http://localhost:8000. Once you are done testing your
|
||||||
|
changes, you should stop the development server via::
|
||||||
|
|
||||||
|
$ ./develop_server.sh stop
|
||||||
|
|
||||||
|
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 content using Pelican
|
||||||
|
=============================
|
||||||
|
|
||||||
|
Articles and pages
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Pelican considers "articles" to be chronological content, such as posts on a
|
||||||
|
blog, and thus associated with a date.
|
||||||
|
|
||||||
|
The idea behind "pages" is that they are usually not temporal in nature and are
|
||||||
|
used for content that does not change very often (e.g., "About" or "Contact"
|
||||||
|
pages).
|
||||||
|
|
||||||
|
.. _internal_metadata:
|
||||||
|
|
||||||
|
File metadata
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Pelican tries to be smart enough to get the information it needs from the
|
||||||
|
file system (for instance, about the category of your articles), but some
|
||||||
|
information you need to provide in the form of metadata inside your files.
|
||||||
|
|
||||||
|
If you are writing your content in reStructuredText format, you can provide
|
||||||
|
this metadata in text files via the following syntax (give your file the
|
||||||
|
``.rst`` extension)::
|
||||||
|
|
||||||
|
My super title
|
||||||
|
##############
|
||||||
|
|
||||||
|
:date: 2010-10-03 10:20
|
||||||
|
:tags: thats, awesome
|
||||||
|
:category: yeah
|
||||||
|
:slug: my-super-post
|
||||||
|
:author: Alexis Metaireau
|
||||||
|
:summary: Short version for index and feeds
|
||||||
|
|
||||||
|
Pelican implements an extension to reStructuredText to enable support for the
|
||||||
|
``abbr`` HTML tag. To use it, write something like this in your post::
|
||||||
|
|
||||||
|
This will be turned into :abbr:`HTML (HyperText Markup Language)`.
|
||||||
|
|
||||||
|
You can also use Markdown syntax (with a file ending in ``.md``,
|
||||||
|
``.markdown``, ``.mkd``, or ``.mdown``). Markdown generation requires that you
|
||||||
|
first explicitly install the ``Markdown`` package, which can be done via ``pip
|
||||||
|
install Markdown``. Metadata syntax for Markdown posts should follow this
|
||||||
|
pattern::
|
||||||
|
|
||||||
|
Title: My super title
|
||||||
|
Date: 2010-12-03 10:20
|
||||||
|
Category: Python
|
||||||
|
Tags: pelican, publishing
|
||||||
|
Slug: my-super-post
|
||||||
|
Author: Alexis Metaireau
|
||||||
|
Summary: Short version for index and feeds
|
||||||
|
|
||||||
|
This is the content of my super blog post.
|
||||||
|
|
||||||
|
Pelican can also process HTML files ending in ``.html`` and ``.htm``. Pelican
|
||||||
|
interprets the HTML in a very straightforward manner, reading metadata from
|
||||||
|
``meta`` tags, the title from the ``title`` tag, and the body out from the
|
||||||
|
``body`` tag::
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>My super title</title>
|
||||||
|
<meta name="tags" contents="thats, awesome" />
|
||||||
|
<meta name="date" contents="2012-07-09 22:28" />
|
||||||
|
<meta name="category" contents="yeah" />
|
||||||
|
<meta name="author" contents="Alexis Métaireau" />
|
||||||
|
<meta name="summary" contents="Short version for index and feeds" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
This is the content of my super blog post.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
With HTML, there is one simple exception to the standard metadata: ``tags`` can
|
||||||
|
be specified either via the ``tags`` metadata, as is standard in Pelican, or
|
||||||
|
via the ``keywords`` metadata, as is standard in HTML. The two can be used
|
||||||
|
interchangeably.
|
||||||
|
|
||||||
|
Note that, aside from the title, none of this article metadata is mandatory:
|
||||||
|
if the date is not specified and ``DEFAULT_DATE`` is set to ``fs``, Pelican
|
||||||
|
will rely on the file's "mtime" timestamp, and the category can be determined
|
||||||
|
by the directory in which the file resides. For example, a file located at
|
||||||
|
``python/foobar/myfoobar.rst`` will have a category of ``foobar``. If you would
|
||||||
|
like to organize your files in other ways where the name of the subfolder would
|
||||||
|
not be a good category name, you can set the setting ``USE_FOLDER_AS_CATEGORY``
|
||||||
|
to ``False``. When parsing dates given in the page metadata, Pelican supports
|
||||||
|
the W3C's `suggested subset ISO 8601`__.
|
||||||
|
|
||||||
|
__ `W3C ISO 8601`_
|
||||||
|
|
||||||
|
If you do not explicitly specify summary metadata for a given post, the
|
||||||
|
``SUMMARY_MAX_LENGTH`` setting can be used to specify how many words from the
|
||||||
|
beginning of an article are used as the summary.
|
||||||
|
|
||||||
|
You can also extract any metadata from the filename through a regular
|
||||||
|
expression to be set in the ``FILENAME_METADATA`` setting. All named groups
|
||||||
|
that are matched will be set in the metadata object. The default value for the
|
||||||
|
``FILENAME_METADATA`` setting will only extract the date from the filename. For
|
||||||
|
example, if you would like to extract both the date and the slug, you could set
|
||||||
|
something like: ``'(?P<date>\d{4}-\d{2}-\d{2})_(?P<slug>.*)'``
|
||||||
|
|
||||||
|
Please note that the metadata available inside your files takes precedence over
|
||||||
|
the metadata extracted from the filename.
|
||||||
|
|
||||||
|
Pages
|
||||||
|
-----
|
||||||
|
|
||||||
|
If you create a folder named ``pages`` inside the content folder, all the
|
||||||
|
files in it will be used to generate static pages, such as **About** or
|
||||||
|
**Contact** pages. (See example filesystem layout below.)
|
||||||
|
|
||||||
|
You can use the ``DISPLAY_PAGES_ON_MENU`` setting to control whether all those
|
||||||
|
pages are displayed in the primary navigation menu. (Default is ``True``.)
|
||||||
|
|
||||||
|
If you want to exclude any pages from being linked to or listed in the menu
|
||||||
|
then add a ``status: hidden`` attribute to its metadata. This is useful for
|
||||||
|
things like making error pages that fit the generated theme of your site.
|
||||||
|
|
||||||
|
Linking to internal content
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
From Pelican 3.1 onwards, it is now possible to specify intra-site links to
|
||||||
|
files in the *source content* hierarchy instead of files in the *generated*
|
||||||
|
hierarchy. This makes it easier to link from the current post to other posts
|
||||||
|
and images that may be sitting alongside the current post (instead of having
|
||||||
|
to determine where those resources will be placed after site generation).
|
||||||
|
|
||||||
|
To link to internal content (files in the ``content`` directory), use the
|
||||||
|
following syntax: ``|filename|path/to/file``::
|
||||||
|
|
||||||
|
|
||||||
|
website/
|
||||||
|
├── content
|
||||||
|
│ ├── article1.rst
|
||||||
|
│ ├── cat/
|
||||||
|
│ │ └── article2.md
|
||||||
|
│ └── pages
|
||||||
|
│ └── about.md
|
||||||
|
└── pelican.conf.py
|
||||||
|
|
||||||
|
In this example, ``article1.rst`` could look like::
|
||||||
|
|
||||||
|
The first article
|
||||||
|
#################
|
||||||
|
|
||||||
|
:date: 2012-12-01 10:02
|
||||||
|
|
||||||
|
See below intra-site link examples in reStructuredText format.
|
||||||
|
|
||||||
|
`a link relative to content root <|filename|/cat/article2.md>`_
|
||||||
|
`a link relative to current file <|filename|cat/article2.md>`_
|
||||||
|
|
||||||
|
and ``article2.md``::
|
||||||
|
|
||||||
|
Title: The second article
|
||||||
|
Date: 2012-12-01 10:02
|
||||||
|
|
||||||
|
See below intra-site link examples in Markdown format.
|
||||||
|
|
||||||
|
[a link relative to content root](|filename|/article1.rst)
|
||||||
|
[a link relative to current file](|filename|../article1.rst)
|
||||||
|
|
||||||
|
Embedding non-article or non-page content is slightly different in that the
|
||||||
|
directories need to be specified in ``pelicanconf.py`` file. The ``images``
|
||||||
|
directory is configured for this by default but others will need to be added
|
||||||
|
manually::
|
||||||
|
|
||||||
|
content
|
||||||
|
├── images
|
||||||
|
│ └── han.jpg
|
||||||
|
└── misc
|
||||||
|
└── image-test.md
|
||||||
|
|
||||||
|
And ``image-test.md`` would include::
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Any content can be linked in this way. What happens is that the ``images``
|
||||||
|
directory gets copied to ``output/static/`` upon publishing. This is
|
||||||
|
because ``images`` is in the ``settings["STATIC_PATHS"]`` list by default. If
|
||||||
|
you want to have another directory, say ``pdfs`` you would need to add the
|
||||||
|
following to ``pelicanconf.py``::
|
||||||
|
|
||||||
|
STATIC_PATHS = ['images', 'pdfs']
|
||||||
|
|
||||||
|
And then the ``pdfs`` directory would also be copied to ``output/static/``.
|
||||||
|
|
||||||
|
Importing an existing blog
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
It is possible to import your blog from Dotclear, WordPress, and RSS feeds using
|
||||||
|
a simple script. See :ref:`import`.
|
||||||
|
|
||||||
|
Translations
|
||||||
|
------------
|
||||||
|
|
||||||
|
It is possible to translate articles. To do so, you need to add a ``lang`` meta
|
||||||
|
attribute to your articles/pages and set a ``DEFAULT_LANG`` setting (which is
|
||||||
|
English [en] by default). With those settings in place, only articles with the
|
||||||
|
default language will be listed, and each article will be accompanied by a list
|
||||||
|
of available translations for that article.
|
||||||
|
|
||||||
|
Pelican uses the article's URL "slug" to determine if two or more articles are
|
||||||
|
translations of one another. The slug can be set manually in the file's
|
||||||
|
metadata; if not set explicitly, Pelican will auto-generate the slug from the
|
||||||
|
title of the article.
|
||||||
|
|
||||||
|
Here is an example of two articles, one in English and the other in French.
|
||||||
|
|
||||||
|
The English article::
|
||||||
|
|
||||||
|
Foobar is not dead
|
||||||
|
##################
|
||||||
|
|
||||||
|
:slug: foobar-is-not-dead
|
||||||
|
:lang: en
|
||||||
|
|
||||||
|
That's true, foobar is still alive!
|
||||||
|
|
||||||
|
And the French version::
|
||||||
|
|
||||||
|
Foobar n'est pas mort !
|
||||||
|
#######################
|
||||||
|
|
||||||
|
:slug: foobar-is-not-dead
|
||||||
|
:lang: fr
|
||||||
|
|
||||||
|
Oui oui, foobar est toujours vivant !
|
||||||
|
|
||||||
|
Post content quality notwithstanding, you can see that only item in common
|
||||||
|
between the two articles is the slug, which is functioning here as an
|
||||||
|
identifier. If you'd rather not explicitly define the slug this way, you must
|
||||||
|
then instead ensure that the translated article titles are identical, since the
|
||||||
|
slug will be auto-generated from the article title.
|
||||||
|
|
||||||
|
If you do not want the original version of one specific article to be detected
|
||||||
|
by the ``DEFAULT_LANG`` setting, use the ``translation`` metadata to specify
|
||||||
|
which posts are translations::
|
||||||
|
|
||||||
|
Foobar is not dead
|
||||||
|
##################
|
||||||
|
|
||||||
|
:slug: foobar-is-not-dead
|
||||||
|
:lang: en
|
||||||
|
:translation: true
|
||||||
|
|
||||||
|
That's true, foobar is still alive!
|
||||||
|
|
||||||
|
Syntax highlighting
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Pelican is able to provide colorized syntax highlighting for your code blocks.
|
||||||
|
To do so, you have to use the following conventions inside your content files.
|
||||||
|
|
||||||
|
For reStructuredText, use the code-block directive::
|
||||||
|
|
||||||
|
.. code-block:: identifier
|
||||||
|
|
||||||
|
<indented code block goes here>
|
||||||
|
|
||||||
|
For Markdown, include the language identifier just above the code block,
|
||||||
|
indenting both the identifier and code::
|
||||||
|
|
||||||
|
A block of text.
|
||||||
|
|
||||||
|
:::identifier
|
||||||
|
<code goes here>
|
||||||
|
|
||||||
|
The specified identifier (e.g. ``python``, ``ruby``) should be one that
|
||||||
|
appears on the `list of available lexers <http://pygments.org/docs/lexers/>`_.
|
||||||
|
|
||||||
|
Publishing drafts
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
If you want to publish an article as a draft (for friends to review before
|
||||||
|
publishing, for example), you can add a ``status: draft`` attribute to its
|
||||||
|
metadata. That article will then be output to the ``drafts`` folder and not
|
||||||
|
listed on the index page nor on any category page.
|
||||||
|
|
||||||
|
.. _virtualenv: http://www.virtualenv.org/
|
||||||
|
.. _W3C ISO 8601: http://www.w3.org/TR/NOTE-datetime
|
||||||
107
docs/importer.rst
Normal file
107
docs/importer.rst
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
.. _import:
|
||||||
|
|
||||||
|
=================================
|
||||||
|
Import from other blog software
|
||||||
|
=================================
|
||||||
|
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
|
||||||
|
``pelican-import`` is a command-line tool for converting articles from other
|
||||||
|
software to reStructuredText or Markdown. The supported import formats are:
|
||||||
|
|
||||||
|
- WordPress XML export
|
||||||
|
- Dotclear export
|
||||||
|
- Posterous API
|
||||||
|
- RSS/Atom feed
|
||||||
|
|
||||||
|
The conversion from HTML to reStructuredText or Markdown relies on `Pandoc`_.
|
||||||
|
For Dotclear, if the source posts are written with Markdown syntax, they will
|
||||||
|
not be converted (as Pelican also supports Markdown).
|
||||||
|
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
============
|
||||||
|
|
||||||
|
``pelican-import`` has some dependencies not required by the rest of Pelican:
|
||||||
|
|
||||||
|
- *BeautifulSoup4* and *lxml*, for WordPress and Dotclear import. Can be installed like
|
||||||
|
any other Python package (``pip install BeautifulSoup4 lxml``).
|
||||||
|
- *Feedparser*, for feed import (``pip install feedparser``).
|
||||||
|
- *Pandoc*, see the `Pandoc site`_ for installation instructions on your
|
||||||
|
operating system.
|
||||||
|
|
||||||
|
.. _Pandoc: http://johnmacfarlane.net/pandoc/
|
||||||
|
.. _Pandoc site: http://johnmacfarlane.net/pandoc/installing.html
|
||||||
|
|
||||||
|
|
||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pelican-import [-h] [--wpfile] [--dotclear] [--posterous] [--feed] [-o OUTPUT]
|
||||||
|
[-m MARKUP] [--dir-cat] [--dir-page] [--strip-raw] [--disable-slugs]
|
||||||
|
[-e EMAIL] [-p PASSWORD]
|
||||||
|
input|api_token
|
||||||
|
|
||||||
|
Positional arguments
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
input The input file to read
|
||||||
|
api_token [Posterous only] api_token can be obtained from http://posterous.com/api/
|
||||||
|
|
||||||
|
Optional arguments
|
||||||
|
------------------
|
||||||
|
|
||||||
|
-h, --help Show this help message and exit
|
||||||
|
--wpfile WordPress XML export (default: False)
|
||||||
|
--dotclear Dotclear export (default: False)
|
||||||
|
--posterous Posterous API (default: False)
|
||||||
|
--feed Feed to parse (default: False)
|
||||||
|
-o OUTPUT, --output OUTPUT
|
||||||
|
Output path (default: output)
|
||||||
|
-m MARKUP, --markup MARKUP
|
||||||
|
Output markup format (supports rst & markdown)
|
||||||
|
(default: rst)
|
||||||
|
--dir-cat Put files in directories with categories name
|
||||||
|
(default: False)
|
||||||
|
--dir-page Put files recognised as pages in "pages/" sub-
|
||||||
|
directory (wordpress import only) (default: False)
|
||||||
|
--strip-raw Strip raw HTML code that can't be converted to markup
|
||||||
|
such as flash embeds or iframes (wordpress import
|
||||||
|
only) (default: False)
|
||||||
|
--disable-slugs Disable storing slugs from imported posts within
|
||||||
|
output. With this disabled, your Pelican URLs may not
|
||||||
|
be consistent with your original posts. (default:
|
||||||
|
False)
|
||||||
|
-e EMAIL, --email=EMAIL
|
||||||
|
Email used to authenticate Posterous API
|
||||||
|
-p PASSWORD, --password=PASSWORD
|
||||||
|
Password used to authenticate Posterous API
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
For WordPress::
|
||||||
|
|
||||||
|
$ pelican-import --wpfile -o ~/output ~/posts.xml
|
||||||
|
|
||||||
|
For Dotclear::
|
||||||
|
|
||||||
|
$ pelican-import --dotclear -o ~/output ~/backup.txt
|
||||||
|
|
||||||
|
for Posterous::
|
||||||
|
|
||||||
|
$ pelican-import --posterous -o ~/output --email=<email_address> --password=<password> <api_token>
|
||||||
|
|
||||||
|
|
||||||
|
Tests
|
||||||
|
=====
|
||||||
|
|
||||||
|
To test the module, one can use sample files:
|
||||||
|
|
||||||
|
- for WordPress: http://wpcandy.com/made/the-sample-post-collection
|
||||||
|
- for Dotclear: http://themes.dotaddict.org/files/public/downloads/lorem-backup.txt
|
||||||
81
docs/index.rst
Normal file
81
docs/index.rst
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
Pelican
|
||||||
|
=======
|
||||||
|
|
||||||
|
Pelican is a static site generator, written in Python_.
|
||||||
|
|
||||||
|
* Write your content directly with your editor of choice (vim!)
|
||||||
|
in reStructuredText_, Markdown_, or AsciiDoc_ formats
|
||||||
|
* Includes a simple CLI tool to (re)generate your site
|
||||||
|
* Easy to interface with distributed version control systems and web hooks
|
||||||
|
* Completely static output is easy to host anywhere
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
Pelican currently supports:
|
||||||
|
|
||||||
|
* Articles (e.g., blog posts) and pages (e.g., "About", "Projects", "Contact")
|
||||||
|
* Comments, via an external service (Disqus). (Please note that while
|
||||||
|
useful, Disqus is an external service, and thus the comment data will be
|
||||||
|
somewhat outside of your control and potentially subject to data loss.)
|
||||||
|
* Theming support (themes are created using Jinja2_ templates)
|
||||||
|
* Publication of articles in multiple languages
|
||||||
|
* Atom/RSS feeds
|
||||||
|
* Code syntax highlighting
|
||||||
|
* PDF generation of the articles/pages (optional)
|
||||||
|
* Import from WordPress, Dotclear, or RSS feeds
|
||||||
|
* Integration with external tools: Twitter, Google Analytics, etc. (optional)
|
||||||
|
|
||||||
|
Why the name "Pelican"?
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
"Pelican" is an anagram for *calepin*, which means "notebook" in French. ;)
|
||||||
|
|
||||||
|
Source code
|
||||||
|
-----------
|
||||||
|
|
||||||
|
You can access the source code at: https://github.com/getpelican/pelican
|
||||||
|
|
||||||
|
Feedback / Contact us
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
If you want to see new features in Pelican, don't hesitate to offer suggestions,
|
||||||
|
clone the repository, etc. There are many ways to :doc:`contribute<contribute>`.
|
||||||
|
That's open source, dude!
|
||||||
|
|
||||||
|
Send a message to "authors at getpelican dot com" with any requests/feedback! You
|
||||||
|
can also join the team at `#pelican on Freenode`_ (or if you don't have an IRC
|
||||||
|
client handy, use the webchat_ for quick feedback.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
A French version of the documentation is available at :doc:`fr/index`.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
getting_started
|
||||||
|
settings
|
||||||
|
themes
|
||||||
|
plugins
|
||||||
|
internals
|
||||||
|
pelican-themes
|
||||||
|
importer
|
||||||
|
faq
|
||||||
|
tips
|
||||||
|
contribute
|
||||||
|
report
|
||||||
|
changelog
|
||||||
|
|
||||||
|
.. Links
|
||||||
|
|
||||||
|
.. _Python: http://www.python.org/
|
||||||
|
.. _reStructuredText: http://docutils.sourceforge.net/rst.html
|
||||||
|
.. _Markdown: http://daringfireball.net/projects/markdown/
|
||||||
|
.. _AsciiDoc: http://www.methods.co.nz/asciidoc/index.html
|
||||||
|
.. _Jinja2: http://jinja.pocoo.org/
|
||||||
|
.. _`Pelican documentation`: http://docs.getpelican.com/latest/
|
||||||
|
.. _`Pelican's internals`: http://docs.getpelican.com/en/latest/internals.html
|
||||||
|
.. _`#pelican on Freenode`: irc://irc.freenode.net/pelican
|
||||||
|
.. _webchat: http://webchat.freenode.net/?channels=pelican&uio=d4
|
||||||
90
docs/internals.rst
Normal file
90
docs/internals.rst
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
Pelican internals
|
||||||
|
#################
|
||||||
|
|
||||||
|
This section describe how Pelican works internally. As you'll see, it's
|
||||||
|
quite simple, but a bit of documentation doesn't hurt. :)
|
||||||
|
|
||||||
|
You can also find in the :doc:`report` section an excerpt of a report the
|
||||||
|
original author wrote with some software design information.
|
||||||
|
|
||||||
|
.. _report: :doc:`report`
|
||||||
|
|
||||||
|
Overall structure
|
||||||
|
=================
|
||||||
|
|
||||||
|
What Pelican does is take a list of files and process them into some sort of
|
||||||
|
output. Usually, the input files are reStructuredText, Markdown and AsciiDoc
|
||||||
|
files, and the output is a blog, but both input and output can be anything you
|
||||||
|
want.
|
||||||
|
|
||||||
|
The logic is separated into different classes and concepts:
|
||||||
|
|
||||||
|
* **Writers** are responsible for writing files: .html files, RSS feeds, and so
|
||||||
|
on. Since those operations are commonly used, the object is created once and
|
||||||
|
then passed to the generators.
|
||||||
|
|
||||||
|
* **Readers** are used to read from various formats (AsciiDoc, HTML, Markdown and
|
||||||
|
reStructuredText for now, but the system is extensible). Given a file, they
|
||||||
|
return metadata (author, tags, category, etc.) and content (HTML-formatted).
|
||||||
|
|
||||||
|
* **Generators** generate the different outputs. For instance, Pelican comes with
|
||||||
|
``ArticlesGenerator`` and ``PageGenerator``. Given a configuration, they can do
|
||||||
|
whatever they want. Most of the time, it's generating files from inputs.
|
||||||
|
|
||||||
|
* Pelican also uses templates, so it's easy to write your own theme. The
|
||||||
|
syntax is `Jinja2 <http://jinja.pocoo.org/>`_ and is very easy to learn, so
|
||||||
|
don't hesitate to jump in and build your own theme.
|
||||||
|
|
||||||
|
How to implement a new reader?
|
||||||
|
==============================
|
||||||
|
|
||||||
|
Is there an awesome markup language you want to add to Pelican?
|
||||||
|
Well, the only thing you have to do is to create a class with a ``read``
|
||||||
|
method that returns HTML content and some metadata.
|
||||||
|
|
||||||
|
Take a look at the Markdown reader::
|
||||||
|
|
||||||
|
class MarkdownReader(Reader):
|
||||||
|
enabled = bool(Markdown)
|
||||||
|
|
||||||
|
def read(self, source_path):
|
||||||
|
"""Parse content and metadata of markdown files"""
|
||||||
|
text = pelican_open(source_path)
|
||||||
|
md = Markdown(extensions = ['meta', 'codehilite'])
|
||||||
|
content = md.convert(text)
|
||||||
|
|
||||||
|
metadata = {}
|
||||||
|
for name, value in md.Meta.items():
|
||||||
|
name = name.lower()
|
||||||
|
meta = self.process_metadata(name, value[0])
|
||||||
|
metadata[name] = meta
|
||||||
|
return content, metadata
|
||||||
|
|
||||||
|
Simple, isn't it?
|
||||||
|
|
||||||
|
If your new reader requires additional Python dependencies, then you should wrap
|
||||||
|
their ``import`` statements in a ``try...except`` block. Then inside the reader's
|
||||||
|
class, set the ``enabled`` class attribute to mark import success or failure.
|
||||||
|
This makes it possible for users to continue using their favourite markup method
|
||||||
|
without needing to install modules for formats they don't use.
|
||||||
|
|
||||||
|
How to implement a new generator?
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Generators have two important methods. You're not forced to create
|
||||||
|
both; only the existing ones will be called.
|
||||||
|
|
||||||
|
* ``generate_context``, that is called first, for all the generators.
|
||||||
|
Do whatever you have to do, and update the global context if needed. This
|
||||||
|
context is shared between all generators, and will be passed to the
|
||||||
|
templates. For instance, the ``PageGenerator`` ``generate_context`` method
|
||||||
|
finds all the pages, transforms them into objects, and populates the context
|
||||||
|
with them. Be careful *not* to output anything using this context at this
|
||||||
|
stage, as it is likely to change by the effect of other generators.
|
||||||
|
|
||||||
|
* ``generate_output`` is then called. And guess what is it made for? Oh,
|
||||||
|
generating the output. :) It's here that you may want to look at the context
|
||||||
|
and call the methods of the ``writer`` object that is passed as the first
|
||||||
|
argument of this function. In the ``PageGenerator`` example, this method will
|
||||||
|
look at all the pages recorded in the global context and output a file on
|
||||||
|
the disk (using the writer method ``write_file``) for each page encountered.
|
||||||
164
docs/pelican-themes.rst
Normal file
164
docs/pelican-themes.rst
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
pelican-themes
|
||||||
|
##############
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
|
||||||
|
``pelican-themes`` is a command line tool for managing themes for Pelican.
|
||||||
|
|
||||||
|
|
||||||
|
Usage
|
||||||
|
"""""
|
||||||
|
|
||||||
|
| pelican-themes [-h] [-l] [-i theme path [theme path ...]]
|
||||||
|
| [-r theme name [theme name ...]]
|
||||||
|
| [-s theme path [theme path ...]] [-v] [--version]
|
||||||
|
|
||||||
|
Optional arguments:
|
||||||
|
"""""""""""""""""""
|
||||||
|
|
||||||
|
|
||||||
|
-h, --help Show the help an exit
|
||||||
|
|
||||||
|
-l, --list Show the themes already installed
|
||||||
|
|
||||||
|
-i theme_path, --install theme_path One or more themes to install
|
||||||
|
|
||||||
|
-r theme_name, --remove theme_name One or more themes to remove
|
||||||
|
|
||||||
|
-s theme_path, --symlink theme_path Same as "--install", but create a symbolic link instead of copying the theme.
|
||||||
|
Useful for theme development
|
||||||
|
|
||||||
|
-v, --verbose Verbose output
|
||||||
|
|
||||||
|
--version Print the version of this script
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
========
|
||||||
|
|
||||||
|
|
||||||
|
Listing the installed themes
|
||||||
|
""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
With ``pelican-themes``, you can see the available themes by using the ``-l`` or ``--list`` option:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ pelican-themes -l
|
||||||
|
notmyidea
|
||||||
|
two-column@
|
||||||
|
simple
|
||||||
|
$ pelican-themes --list
|
||||||
|
notmyidea
|
||||||
|
two-column@
|
||||||
|
simple
|
||||||
|
|
||||||
|
In this example, we can see there are three themes available: ``notmyidea``, ``simple``, and ``two-column``.
|
||||||
|
|
||||||
|
``two-column`` is prefixed with an ``@`` because this theme is not copied to the Pelican theme path, but is instead just linked to it (see `Creating symbolic links`_ for details about creating symbolic links).
|
||||||
|
|
||||||
|
Note that you can combine the ``--list`` option with the ``-v`` or ``--verbose`` option to get more verbose output, like this:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ pelican-themes -v -l
|
||||||
|
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/notmyidea
|
||||||
|
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/two-column (symbolic link to `/home/skami/Dev/Python/pelican-themes/two-column')
|
||||||
|
/usr/local/lib/python2.6/dist-packages/pelican-2.6.0-py2.6.egg/pelican/themes/simple
|
||||||
|
|
||||||
|
|
||||||
|
Installing themes
|
||||||
|
"""""""""""""""""
|
||||||
|
|
||||||
|
You can install one or more themes using the ``-i`` or ``--install`` option.
|
||||||
|
This option takes as argument the path(s) of the theme(s) you want to install, and can be combined with the verbose option:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms --verbose
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --install ~/Dev/Python/pelican-themes/notmyidea-cms\
|
||||||
|
~/Dev/Python/pelican-themes/martyalchin \
|
||||||
|
--verbose
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes -vi ~/Dev/Python/pelican-themes/two-column
|
||||||
|
|
||||||
|
|
||||||
|
Removing themes
|
||||||
|
"""""""""""""""
|
||||||
|
|
||||||
|
The ``pelican-themes`` command can also remove themes from the Pelican themes path.
|
||||||
|
The ``-r`` or ``--remove`` option takes as argument the name(s) of the theme(s) you want to remove, and can be combined with the ``--verbose`` option.
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --remove two-column
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes -r martyachin notmyidea-cmd -v
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Creating symbolic links
|
||||||
|
"""""""""""""""""""""""
|
||||||
|
|
||||||
|
``pelican-themes`` can also install themes by creating symbolic links instead of copying entire themes into the Pelican themes path.
|
||||||
|
|
||||||
|
To symbolically link a theme, you can use the ``-s`` or ``--symlink``, which works exactly as the ``--install`` option:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --symlink ~/Dev/Python/pelican-themes/two-column
|
||||||
|
|
||||||
|
In this example, the ``two-column`` theme is now symbolically linked to the Pelican themes path, so we can use it, but we can also modify it without having to reinstall it after each modification.
|
||||||
|
|
||||||
|
This is useful for theme development:
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
$ sudo pelican-themes -s ~/Dev/Python/pelican-themes/two-column
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
$ firefox /tmp/out/index.html
|
||||||
|
$ vim ~/Dev/Pelican/pelican-themes/two-coumn/static/css/main.css
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
$ cp /tmp/bg.png ~/Dev/Pelican/pelican-themes/two-coumn/static/img/bg.png
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
$ vim ~/Dev/Pelican/pelican-themes/two-coumn/templates/index.html
|
||||||
|
$ pelican ~/Blog/content -o /tmp/out -t two-column
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Doing several things at once
|
||||||
|
""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
The ``--install``, ``--remove`` and ``--symlink`` option are not mutually exclusive, so you can combine them in the same command line to do more than one operation at time, like this:
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: console
|
||||||
|
|
||||||
|
# pelican-themes --remove notmyidea-cms two-column \
|
||||||
|
--install ~/Dev/Python/pelican-themes/notmyidea-cms-fr \
|
||||||
|
--symlink ~/Dev/Python/pelican-themes/two-column \
|
||||||
|
--verbose
|
||||||
|
|
||||||
|
In this example, the theme ``notmyidea-cms`` is replaced by the theme ``notmyidea-cms-fr``
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
See also
|
||||||
|
========
|
||||||
|
|
||||||
|
- http://docs.notmyidea.org/alexis/pelican/
|
||||||
|
- ``/usr/share/doc/pelican/`` if you have installed Pelican using the `APT repository <http://skami18.github.com/pelican-packages/>`_
|
||||||
125
docs/plugins.rst
Normal file
125
docs/plugins.rst
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
.. _plugins:
|
||||||
|
|
||||||
|
Plugins
|
||||||
|
#######
|
||||||
|
|
||||||
|
Beginning with version 3.0, Pelican supports plugins. Plugins are a way to add
|
||||||
|
features to Pelican without having to directly modify the Pelican core.
|
||||||
|
|
||||||
|
How to use plugins
|
||||||
|
==================
|
||||||
|
|
||||||
|
To load plugins, you have to specify them in your settings file. There are two
|
||||||
|
ways to do so. The first method is to specify strings with the path to the
|
||||||
|
callables::
|
||||||
|
|
||||||
|
PLUGINS = ['package.myplugin',]
|
||||||
|
|
||||||
|
Alternatively, another method is to import them and add them to the list::
|
||||||
|
|
||||||
|
from package import myplugin
|
||||||
|
PLUGINS = [myplugin,]
|
||||||
|
|
||||||
|
If your plugins are not in an importable path, you can specify a ``PLUGIN_PATH``
|
||||||
|
in the settings. ``PLUGIN_PATH`` can be an absolute path or a path relative to
|
||||||
|
the settings file::
|
||||||
|
|
||||||
|
PLUGIN_PATH = "plugins"
|
||||||
|
PLUGINS = ["list", "of", "plugins"]
|
||||||
|
|
||||||
|
Where to find plugins
|
||||||
|
=====================
|
||||||
|
|
||||||
|
We maintain a separate repository of plugins for people to share and use.
|
||||||
|
Please visit the `pelican-plugins`_ repository for a list of available plugins.
|
||||||
|
|
||||||
|
.. _pelican-plugins: https://github.com/getpelican/pelican-plugins
|
||||||
|
|
||||||
|
Please note that while we do our best to review and maintain these plugins,
|
||||||
|
they are submitted by the Pelican community and thus may have varying levels of
|
||||||
|
support and interoperability.
|
||||||
|
|
||||||
|
How to create plugins
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Plugins are based on the concept of signals. Pelican sends signals, and plugins
|
||||||
|
subscribe to those signals. The list of signals are defined in a subsequent
|
||||||
|
section.
|
||||||
|
|
||||||
|
The only rule to follow for plugins is to define a ``register`` callable, in
|
||||||
|
which you map the signals to your plugin logic. Let's take a simple example::
|
||||||
|
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
|
def test(sender):
|
||||||
|
print "%s initialized !!" % sender
|
||||||
|
|
||||||
|
def register():
|
||||||
|
signals.initialized.connect(test)
|
||||||
|
|
||||||
|
List of signals
|
||||||
|
===============
|
||||||
|
|
||||||
|
Here is the list of currently implemented signals:
|
||||||
|
|
||||||
|
============================= ============================ ===========================================================================
|
||||||
|
Signal Arguments Description
|
||||||
|
============================= ============================ ===========================================================================
|
||||||
|
initialized pelican object
|
||||||
|
finalized pelican object invoked after all the generators are executed and just before pelican exits
|
||||||
|
usefull for custom post processing actions, such as:
|
||||||
|
- minifying js/css assets.
|
||||||
|
- notify/ping search engines with an updated sitemap.
|
||||||
|
generator_init generator invoked in the Generator.__init__
|
||||||
|
article_generate_context article_generator, metadata
|
||||||
|
article_generate_preread article_generator invoked before a article is read in ArticlesGenerator.generate_context;
|
||||||
|
use if code needs to do something before every article is parsed
|
||||||
|
article_generator_init article_generator invoked in the ArticlesGenerator.__init__
|
||||||
|
article_generator_finalized article_generator invoked at the end of ArticlesGenerator.generate_context
|
||||||
|
get_generators generators invoked in Pelican.get_generator_classes,
|
||||||
|
can return a Generator, or several
|
||||||
|
generator in a tuple or in a list.
|
||||||
|
page_generate_context page_generator, metadata
|
||||||
|
page_generator_init page_generator invoked in the PagesGenerator.__init__
|
||||||
|
page_generator_finalized page_generator invoked at the end of PagesGenerator.generate_context
|
||||||
|
content_object_init content_object invoked at the end of Content.__init__ (see note below)
|
||||||
|
============================= ============================ ===========================================================================
|
||||||
|
|
||||||
|
The list is currently small, so don't hesitate to add signals and make a pull
|
||||||
|
request if you need them!
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The signal ``content_object_init`` can send a different type of object as
|
||||||
|
the argument. If you want to register only one type of object then you will
|
||||||
|
need to specify the sender when you are connecting to the signal.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from pelican import signals
|
||||||
|
from pelican import contents
|
||||||
|
|
||||||
|
def test(sender, instance):
|
||||||
|
print "%s : %s content initialized !!" % (sender, instance)
|
||||||
|
|
||||||
|
def register():
|
||||||
|
signals.content_object_init.connect(test, sender=contents.Article)
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
After Pelican 3.2, signal names were standardized. Older plugins
|
||||||
|
may need to be updated to use the new names:
|
||||||
|
|
||||||
|
========================== ===========================
|
||||||
|
Old name New name
|
||||||
|
========================== ===========================
|
||||||
|
article_generate_context article_generator_context
|
||||||
|
article_generate_finalized article_generator_finalized
|
||||||
|
article_generate_preread article_generator_preread
|
||||||
|
pages_generate_context page_generator_context
|
||||||
|
pages_generate_preread page_generator_preread
|
||||||
|
pages_generator_finalized page_generator_finalized
|
||||||
|
pages_generator_init page_generator_init
|
||||||
|
static_generate_context static_generator_context
|
||||||
|
static_generate_preread static_generator_preread
|
||||||
|
========================== ===========================
|
||||||
121
docs/report.rst
Normal file
121
docs/report.rst
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
Some history about Pelican
|
||||||
|
##########################
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
This page comes from a report the original author (Alexis Métaireau) wrote
|
||||||
|
right after writing Pelican, in December 2010. The information may not be
|
||||||
|
up-to-date.
|
||||||
|
|
||||||
|
Pelican is a simple static blog generator. It parses markup files
|
||||||
|
(Markdown or reStructuredText for now) and generates an HTML folder
|
||||||
|
with all the files in it.
|
||||||
|
I've chosen to use Python to implement Pelican because it seemed to
|
||||||
|
be simple and to fit to my needs. I did not wanted to define a class for
|
||||||
|
each thing, but still wanted to keep my things loosely coupled.
|
||||||
|
It turns out that it was exactly what I wanted. From time to time,
|
||||||
|
thanks to the feedback of some users, it took me a very few time to
|
||||||
|
provide fixes on it. So far, I've re-factored the Pelican code by two
|
||||||
|
times; each time took less than 30 minutes.
|
||||||
|
|
||||||
|
Use case
|
||||||
|
========
|
||||||
|
|
||||||
|
I was previously using WordPress, a solution you can host on a web
|
||||||
|
server to manage your blog. Most of the time, I prefer using markup
|
||||||
|
languages such as Markdown or reStructuredText to type my articles.
|
||||||
|
To do so, I use vim. I think it is important to let the people choose the
|
||||||
|
tool they want to write the articles. In my opinion, a blog manager
|
||||||
|
should just allow you to take any kind of input and transform it to a
|
||||||
|
weblog. That's what Pelican does.
|
||||||
|
You can write your articles using the tool you want, and the markup
|
||||||
|
language you want, and then generate a static HTML weblog.
|
||||||
|
|
||||||
|
.. image:: _static/overall.png
|
||||||
|
|
||||||
|
To be flexible enough, Pelican has template support, so you can easily write
|
||||||
|
your own themes if you want to.
|
||||||
|
|
||||||
|
Design process
|
||||||
|
==============
|
||||||
|
|
||||||
|
Pelican came from a need I have. I started by creating a single file
|
||||||
|
application, and I have make it grow to support what it does by now.
|
||||||
|
To start, I wrote a piece of documentation about what I wanted to do.
|
||||||
|
Then, I created the content I wanted to parse (the reStructuredText files)
|
||||||
|
and started experimenting with the code. Pelican was 200 lines long and
|
||||||
|
contained almost ten functions and one class when it was first usable.
|
||||||
|
|
||||||
|
I have been facing different problems all over the time and wanted to
|
||||||
|
add features to Pelican while using it. The first change I have done was
|
||||||
|
to add the support of a settings file. It is possible to pass the options to
|
||||||
|
the command line, but can be tedious if there is a lot of them.
|
||||||
|
In the same way, I have added the support of different things over
|
||||||
|
time: Atom feeds, multiple themes, multiple markup support, etc.
|
||||||
|
At some point, it appears that the "only one file" mantra was not good
|
||||||
|
enough for Pelican, so I decided to rework a bit all that, and split this in
|
||||||
|
multiple different files.
|
||||||
|
|
||||||
|
I’ve separated the logic in different classes and concepts:
|
||||||
|
|
||||||
|
* *writers* are responsible of all the writing process of the files.
|
||||||
|
They are responsible of writing .html files, RSS feeds and so on.
|
||||||
|
Since those operations are commonly used, the object is created
|
||||||
|
once, and then passed to the generators.
|
||||||
|
|
||||||
|
* *readers* are used to read from various formats (Markdown and
|
||||||
|
reStructuredText for now, but the system is extensible). Given a
|
||||||
|
file, they return metadata (author, tags, category, etc) and
|
||||||
|
content (HTML formatted).
|
||||||
|
|
||||||
|
* *generators* generate the different outputs. For instance, Pelican
|
||||||
|
comes with an ArticlesGenerator and PagesGenerator, into
|
||||||
|
others. Given a configuration, they can do whatever you want
|
||||||
|
them to do. Most of the time it's generating files from inputs
|
||||||
|
(user inputs and files).
|
||||||
|
|
||||||
|
I also deal with contents objects. They can be ``Articles``, ``Pages``,
|
||||||
|
``Quotes``, or whatever you want. They are defined in the ``contents.py``
|
||||||
|
module and represent some content to be used by the program.
|
||||||
|
|
||||||
|
In more detail
|
||||||
|
==============
|
||||||
|
|
||||||
|
Here is an overview of the classes involved in Pelican.
|
||||||
|
|
||||||
|
.. image:: _static/uml.jpg
|
||||||
|
|
||||||
|
The interface does not really exist, and I have added it only to clarify the
|
||||||
|
whole picture. I do use duck typing and not interfaces.
|
||||||
|
|
||||||
|
Internally, the following process is followed:
|
||||||
|
|
||||||
|
* First of all, the command line is parsed, and some content from
|
||||||
|
the user is used to initialize the different generator objects.
|
||||||
|
|
||||||
|
* A ``context`` is created. It contains the settings from the command
|
||||||
|
line and a settings file if provided.
|
||||||
|
* The ``generate_context`` method of each generator is called, updating
|
||||||
|
the context.
|
||||||
|
|
||||||
|
* The writer is created and given to the ``generate_output`` method of
|
||||||
|
each generator.
|
||||||
|
|
||||||
|
I make two calls because it is important that when the output is
|
||||||
|
generated by the generators, the context will not change. In other
|
||||||
|
words, the first method ``generate_context`` should modify the context,
|
||||||
|
whereas the second ``generate_output`` method should not.
|
||||||
|
|
||||||
|
Then, it is up to the generators to do what the want, in the
|
||||||
|
``generate_context`` and ``generate_content`` method.
|
||||||
|
Taking the ``ArticlesGenerator`` class will help to understand some others
|
||||||
|
concepts. Here is what happens when calling the ``generate_context``
|
||||||
|
method:
|
||||||
|
|
||||||
|
* Read the folder “path”, looking for restructured text files, load
|
||||||
|
each of them, and construct a content object (``Article``) with it. To do so,
|
||||||
|
use ``Reader`` objects.
|
||||||
|
* Update the ``context`` with all those articles.
|
||||||
|
|
||||||
|
Then, the ``generate_content`` method uses the ``context`` and the ``writer`` to
|
||||||
|
generate the wanted output.
|
||||||
616
docs/settings.rst
Normal file
616
docs/settings.rst
Normal file
|
|
@ -0,0 +1,616 @@
|
||||||
|
Settings
|
||||||
|
########
|
||||||
|
|
||||||
|
Pelican is configurable thanks to a configuration file you can pass to
|
||||||
|
the command line::
|
||||||
|
|
||||||
|
$ pelican -s path/to/your/settingsfile.py path
|
||||||
|
|
||||||
|
Settings are configured in the form of a Python module (a file). You can see an
|
||||||
|
example by looking at `/samples/pelican.conf.py
|
||||||
|
<https://github.com/getpelican/pelican/raw/master/samples/pelican.conf.py>`_
|
||||||
|
|
||||||
|
All the setting identifiers must be set in all-caps, otherwise they will not be
|
||||||
|
processed. Setting values that are numbers (5, 20, etc.), booleans (True,
|
||||||
|
False, None, etc.), dictionaries, or tuples should *not* be enclosed in
|
||||||
|
quotation marks. All other values (i.e., strings) *must* be enclosed in
|
||||||
|
quotation marks.
|
||||||
|
|
||||||
|
Unless otherwise specified, settings that refer to paths can be either absolute
|
||||||
|
or relative to the configuration file.
|
||||||
|
|
||||||
|
The settings you define in the configuration file will be passed to the
|
||||||
|
templates, which allows you to use your settings to add site-wide content.
|
||||||
|
|
||||||
|
Here is a list of settings for Pelican:
|
||||||
|
|
||||||
|
Basic settings
|
||||||
|
==============
|
||||||
|
|
||||||
|
===================================================================== =====================================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
===================================================================== =====================================================================
|
||||||
|
`AUTHOR` Default author (put your name)
|
||||||
|
`DATE_FORMATS` (``{}``) If you manage multiple languages, you can set the date formatting
|
||||||
|
here. See the "Date format and locales" section below for details.
|
||||||
|
`USE_FOLDER_AS_CATEGORY` (``True``) When you don't specify a category in your post metadata, set this
|
||||||
|
setting to ``True``, and organize your articles in subfolders, the
|
||||||
|
subfolder will become the category of your post. If set to ``False``,
|
||||||
|
``DEFAULT_CATEGORY`` will be used as a fallback.
|
||||||
|
`DEFAULT_CATEGORY` (``'misc'``) The default category to fall back on.
|
||||||
|
`DEFAULT_DATE_FORMAT` (``'%a %d %B %Y'``) The default date format you want to use.
|
||||||
|
`DISPLAY_PAGES_ON_MENU` (``True``) Whether to display pages on the menu of the
|
||||||
|
template. Templates may or may not honor this
|
||||||
|
setting.
|
||||||
|
`DISPLAY_CATEGORIES_ON_MENU` (``True``) Whether to display categories on the menu of the
|
||||||
|
template. Templates may or not honor this
|
||||||
|
setting.
|
||||||
|
`DEFAULT_DATE` (``None``) The default date you want to use.
|
||||||
|
If ``fs``, Pelican will use the file system
|
||||||
|
timestamp information (mtime) if it can't get
|
||||||
|
date information from the metadata.
|
||||||
|
If set to a tuple object, the default datetime object will instead
|
||||||
|
be generated by passing the tuple to the
|
||||||
|
``datetime.datetime`` constructor.
|
||||||
|
`DEFAULT_METADATA` (``()``) The default metadata you want to use for all articles
|
||||||
|
and pages.
|
||||||
|
`FILENAME_METADATA` (``'(?P<date>\d{4}-\d{2}-\d{2}).*'``) The regexp that will be used to extract any metadata
|
||||||
|
from the filename. All named groups that are matched
|
||||||
|
will be set in the metadata object.
|
||||||
|
The default value will only extract the date from
|
||||||
|
the filename.
|
||||||
|
For example, if you would like to extract both the
|
||||||
|
date and the slug, you could set something like:
|
||||||
|
``'(?P<date>\d{4}-\d{2}-\d{2})_(?P<slug>.*)'``.
|
||||||
|
See :ref:`path_metadata`.
|
||||||
|
`PATH_METADATA` (``''``) Like ``FILENAME_METADATA``, but parsed from a page's
|
||||||
|
full path relative to the content source directory.
|
||||||
|
See :ref:`path_metadata`.
|
||||||
|
`EXTRA_PATH_METADATA` (``{}``) Extra metadata dictionaries keyed by relative path.
|
||||||
|
See :ref:`path_metadata`.
|
||||||
|
`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the output directory, and **all** of its contents, before
|
||||||
|
generating new files. This can be useful in preventing older,
|
||||||
|
unnecessary files from persisting in your output. However, **this is
|
||||||
|
a destructive setting and should be handled with extreme care.**
|
||||||
|
`OUTPUT_RETENTION` (``()``) A tuple of filenames that should be retained and not deleted from the
|
||||||
|
output directory. One use case would be the preservation of version
|
||||||
|
control data. For example: ``(".hg", ".git", ".bzr")``
|
||||||
|
`JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use.
|
||||||
|
`JINJA_FILTERS` (``{}``) A list of custom Jinja2 filters you want to use.
|
||||||
|
The dictionary should map the filtername to the filter function.
|
||||||
|
For example: ``{'urlencode': urlencode_filter}``
|
||||||
|
See `Jinja custom filters documentation`_.
|
||||||
|
`LOCALE` (''[#]_) Change the locale. A list of locales can be provided
|
||||||
|
here or a single string representing one locale.
|
||||||
|
When providing a list, all the locales will be tried
|
||||||
|
until one works.
|
||||||
|
`MARKUP` (``('rst', 'md')``) A list of available markup languages you want
|
||||||
|
to use. For the moment, the only available values
|
||||||
|
are `rst`, `md`, `markdown`, `mkd`, `mdown`, `html`, and `htm`.
|
||||||
|
`IGNORE_FILES` (``['.#*']``) A list of file globbing patterns to match against the
|
||||||
|
source files to be ignored by the processor. For example,
|
||||||
|
the default ``['.#*']`` will ignore emacs lock files.
|
||||||
|
`MD_EXTENSIONS` (``['codehilite(css_class=highlight)','extra']``) A list of the extensions that the Markdown processor
|
||||||
|
will use. Refer to the Python Markdown documentation's
|
||||||
|
`Extensions section <http://pythonhosted.org/Markdown/extensions/>`_
|
||||||
|
for a complete list of supported extensions. (Note that
|
||||||
|
defining this in your settings file will override and
|
||||||
|
replace the default values. If your goal is to *add*
|
||||||
|
to the default values for this setting, you'll need to
|
||||||
|
include them explicitly and enumerate the full list of
|
||||||
|
desired Markdown extensions.)
|
||||||
|
`OUTPUT_PATH` (``'output/'``) Where to output the generated files.
|
||||||
|
`PATH` (``None``) Path to content directory to be processed by Pelican.
|
||||||
|
`PAGE_DIR` (``'pages'``) Directory to look at for pages, relative to `PATH`.
|
||||||
|
`PAGE_EXCLUDES` (``()``) A list of directories to exclude when looking for pages.
|
||||||
|
`ARTICLE_DIR` (``''``) Directory to look at for articles, relative to `PATH`.
|
||||||
|
`ARTICLE_EXCLUDES`: (``('pages',)``) A list of directories to exclude when looking for articles.
|
||||||
|
`PDF_GENERATOR` (``False``) Set to ``True`` if you want PDF versions of your documents to be.
|
||||||
|
generated. You will need to install ``rst2pdf``.
|
||||||
|
`OUTPUT_SOURCES` (``False``) Set to True if you want to copy the articles and pages in their
|
||||||
|
original format (e.g. Markdown or reStructuredText) to the
|
||||||
|
specified OUTPUT_PATH.
|
||||||
|
`OUTPUT_SOURCES_EXTENSION` (``.text``) Controls the extension that will be used by the SourcesGenerator.
|
||||||
|
Defaults to ``.text``. If not a valid string the default value
|
||||||
|
will be used.
|
||||||
|
`RELATIVE_URLS` (``False``) Defines whether Pelican should use document-relative URLs or
|
||||||
|
not. Only set this to ``True`` when developing/testing and only
|
||||||
|
if you fully understand the effect it can have on links/feeds.
|
||||||
|
`PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`.
|
||||||
|
`SITENAME` (``'A Pelican Blog'``) Your site name
|
||||||
|
`SITEURL` Base URL of your website. Not defined by default,
|
||||||
|
so it is best to specify your SITEURL; if you do not, feeds
|
||||||
|
will not be generated with properly-formed URLs. You should
|
||||||
|
include ``http://`` and your domain, with no trailing
|
||||||
|
slash at the end. Example: ``SITEURL = 'http://mydomain.com'``
|
||||||
|
`TEMPLATE_PAGES` (``None``) A mapping containing template pages that will be rendered with
|
||||||
|
the blog entries. See :ref:`template_pages`.
|
||||||
|
`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
|
||||||
|
output folder.
|
||||||
|
`TIMEZONE` The timezone used in the date information, to
|
||||||
|
generate Atom and RSS feeds. See the *Timezone*
|
||||||
|
section below for more info.
|
||||||
|
`TYPOGRIFY` (``False``) If set to True, several typographical improvements will be
|
||||||
|
incorporated into the generated HTML via the `Typogrify
|
||||||
|
<http://static.mintchaos.com/projects/typogrify/>`_
|
||||||
|
library, which can be installed via: ``pip install typogrify``
|
||||||
|
`DIRECT_TEMPLATES` (``('index', 'tags', 'categories', 'archives')``) List of templates that are used directly to render
|
||||||
|
content. Typically direct templates are used to generate
|
||||||
|
index pages for collections of content (e.g., tags and
|
||||||
|
category index pages). If the tag and category collections
|
||||||
|
are not needed, set ``DIRECT_TEMPLATES = ('index', 'archives')``
|
||||||
|
`PAGINATED_DIRECT_TEMPLATES` (``('index',)``) Provides the direct templates that should be paginated.
|
||||||
|
`SUMMARY_MAX_LENGTH` (``50``) When creating a short summary of an article, this will
|
||||||
|
be the default length in words of the text created.
|
||||||
|
This only applies if your content does not otherwise
|
||||||
|
specify a summary. Setting to ``None`` will cause the summary
|
||||||
|
to be a copy of the original content.
|
||||||
|
`EXTRA_TEMPLATES_PATHS` (``[]``) A list of paths you want Jinja2 to search for templates.
|
||||||
|
Can be used to separate templates from the theme.
|
||||||
|
Example: projects, resume, profile ...
|
||||||
|
These templates need to use ``DIRECT_TEMPLATES`` setting.
|
||||||
|
`ASCIIDOC_OPTIONS` (``[]``) A list of options to pass to AsciiDoc. See the `manpage
|
||||||
|
<http://www.methods.co.nz/asciidoc/manpage.html>`_
|
||||||
|
===================================================================== =====================================================================
|
||||||
|
|
||||||
|
.. [#] Default is the system locale.
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
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
|
||||||
|
input files' date metadata attribute. If the date is not specified for a
|
||||||
|
particular file, Pelican will rely on the file's mtime timestamp.
|
||||||
|
|
||||||
|
Check the Python datetime documentation at http://bit.ly/cNcJUC for more
|
||||||
|
information.
|
||||||
|
|
||||||
|
Also, you can use other file metadata attributes as well:
|
||||||
|
|
||||||
|
* slug
|
||||||
|
* date
|
||||||
|
* lang
|
||||||
|
* author
|
||||||
|
* category
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
* ARTICLE_URL = ``'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/'``
|
||||||
|
* ARTICLE_SAVE_AS = ``'posts/{date:%Y}/{date:%b}/{date:%d}/{slug}/index.html'``
|
||||||
|
|
||||||
|
This would save your articles in something like ``/posts/2011/Aug/07/sample-post/index.html``,
|
||||||
|
and the URL to this would be ``/posts/2011/Aug/07/sample-post/``.
|
||||||
|
|
||||||
|
Pelican can optionally create per-year, per-month, and per-day archives of your
|
||||||
|
posts. These secondary archives are disabled by default but are automatically
|
||||||
|
enabled if you supply format strings for their respective `_SAVE_AS` settings.
|
||||||
|
Period archives fit intuitively with the hierarchical model of web URLs and can
|
||||||
|
make it easier for readers to navigate through the posts you've written over time.
|
||||||
|
|
||||||
|
Example usage:
|
||||||
|
|
||||||
|
* YEAR_ARCHIVE_SAVE_AS = ``'posts/{date:%Y}/index.html'``
|
||||||
|
* MONTH_ARCHIVE_SAVE_AS = ``'posts/{date:%Y}/{date:%b}/index.html'``
|
||||||
|
|
||||||
|
With these settings, Pelican will create an archive of all your posts for the year
|
||||||
|
at (for instance) 'posts/2011/index.html', and an archive of all your posts for
|
||||||
|
the month at 'posts/2011/Aug/index.html'.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Period archives work best when the final path segment is 'index.html'.
|
||||||
|
This way a reader can remove a portion of your URL and automatically
|
||||||
|
arrive at an appropriate archive of posts, without having to specify
|
||||||
|
a page name.
|
||||||
|
|
||||||
|
==================================================== =====================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
==================================================== =====================================================
|
||||||
|
`ARTICLE_URL` (``'{slug}.html'``) The URL to refer to an ARTICLE.
|
||||||
|
`ARTICLE_SAVE_AS` (``'{slug}.html'``) The place where we will save an article.
|
||||||
|
`ARTICLE_LANG_URL` (``'{slug}-{lang}.html'``) The URL to refer to an ARTICLE which doesn't use the
|
||||||
|
default language.
|
||||||
|
`ARTICLE_LANG_SAVE_AS` (``'{slug}-{lang}.html'``) The place where we will save an article which
|
||||||
|
doesn't use the default language.
|
||||||
|
`PAGE_URL` (``'pages/{slug}.html'``) The URL we will use to link to a page.
|
||||||
|
`PAGE_SAVE_AS` (``'pages/{slug}.html'``) The location we will save the page. This value has to be
|
||||||
|
the same as PAGE_URL or you need to use a rewrite in
|
||||||
|
your server config.
|
||||||
|
`PAGE_LANG_URL` (``'pages/{slug}-{lang}.html'``) The URL we will use to link to a page which doesn't
|
||||||
|
use the default language.
|
||||||
|
`PAGE_LANG_SAVE_AS` (``'pages/{slug}-{lang}.html'``) The location we will save the page which doesn't
|
||||||
|
use the default language.
|
||||||
|
`CATEGORY_URL` (``'category/{slug}.html'``) The URL to use for a category.
|
||||||
|
`CATEGORY_SAVE_AS` (``'category/{slug}.html'``) The location to save a category.
|
||||||
|
`TAG_URL` (``'tag/{slug}.html'``) The URL to use for a tag.
|
||||||
|
`TAG_SAVE_AS` (``'tag/{slug}.html'``) The location to save the tag page.
|
||||||
|
`TAGS_URL` (``'tag/{slug}.html'``) The URL to use for the tag list.
|
||||||
|
`TAGS_SAVE_AS` (``'tags.html'``) The location to save the tag list.
|
||||||
|
`AUTHOR_URL` (``'author/{slug}.html'``) The URL to use for an author.
|
||||||
|
`AUTHOR_SAVE_AS` (``'author/{slug}.html'``) The location to save an author.
|
||||||
|
`AUTHORS_URL` (``'authors.html'``) The URL to use for the author list.
|
||||||
|
`AUTHORS_SAVE_AS` (``'authors.html'``) The location to save the author list.
|
||||||
|
`<DIRECT_TEMPLATE_NAME>_SAVE_AS` The location to save content generated from direct
|
||||||
|
templates. Where <DIRECT_TEMPLATE_NAME> is the
|
||||||
|
upper case template name.
|
||||||
|
`ARCHIVES_SAVE_AS` (``'archives.html'``) The location to save the article archives page.
|
||||||
|
`YEAR_ARCHIVE_SAVE_AS` (False) The location to save per-year archives of your
|
||||||
|
posts.
|
||||||
|
`MONTH_ARCHIVE_SAVE_AS` (False) The location to save per-month archives of your
|
||||||
|
posts.
|
||||||
|
`DAY_ARCHIVE_SAVE_AS` (False) The location to save per-day archives of your
|
||||||
|
posts.
|
||||||
|
==================================================== =====================================================
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
If you do not want one or more of the default pages to be created (e.g.,
|
||||||
|
you are the only author on your site and thus do not need an Authors page),
|
||||||
|
set the corresponding ``*_SAVE_AS`` setting to ``False`` to prevent the
|
||||||
|
relevant page from being generated.
|
||||||
|
|
||||||
|
Timezone
|
||||||
|
--------
|
||||||
|
|
||||||
|
If no timezone is defined, UTC is assumed. This means that the generated Atom
|
||||||
|
and RSS feeds will contain incorrect date information if your locale is not UTC.
|
||||||
|
|
||||||
|
Pelican issues a warning in case this setting is not defined, as it was not
|
||||||
|
mandatory in previous versions.
|
||||||
|
|
||||||
|
Have a look at `the wikipedia page`_ to get a list of valid timezone values.
|
||||||
|
|
||||||
|
.. _the wikipedia page: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||||
|
|
||||||
|
|
||||||
|
Date format and locale
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
If no DATE_FORMATS are set, Pelican will fall back to DEFAULT_DATE_FORMAT. If
|
||||||
|
you need to maintain multiple languages with different date formats, you can
|
||||||
|
set this dict using the language name (``lang`` metadata in your post content)
|
||||||
|
as the key. Regarding available format codes, see `strftime document of python`_ :
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
DATE_FORMATS = {
|
||||||
|
'en': '%a, %d %b %Y',
|
||||||
|
'jp': '%Y-%m-%d(%a)',
|
||||||
|
}
|
||||||
|
|
||||||
|
You can set locale to further control date format:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
LOCALE = ('usa', 'jpn', # On Windows
|
||||||
|
'en_US', 'ja_JP' # On Unix/Linux
|
||||||
|
)
|
||||||
|
|
||||||
|
Also, it is possible to set different locale settings for each language. If you
|
||||||
|
put (locale, format) tuples in the dict, this will override the LOCALE setting
|
||||||
|
above:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
# On Unix/Linux
|
||||||
|
DATE_FORMATS = {
|
||||||
|
'en': ('en_US','%a, %d %b %Y'),
|
||||||
|
'jp': ('ja_JP','%Y-%m-%d(%a)'),
|
||||||
|
}
|
||||||
|
|
||||||
|
# On Windows
|
||||||
|
DATE_FORMATS = {
|
||||||
|
'en': ('usa','%a, %d %b %Y'),
|
||||||
|
'jp': ('jpn','%Y-%m-%d(%a)'),
|
||||||
|
}
|
||||||
|
|
||||||
|
This is a list of available `locales on Windows`_ . On Unix/Linux, usually you
|
||||||
|
can get a list of available locales via the ``locale -a`` command; see manpage
|
||||||
|
`locale(1)`_ for more information.
|
||||||
|
|
||||||
|
|
||||||
|
.. _strftime document of python: http://docs.python.org/library/datetime.html#strftime-strptime-behavior
|
||||||
|
|
||||||
|
.. _locales on Windows: http://msdn.microsoft.com/en-us/library/cdax410z%28VS.71%29.aspx
|
||||||
|
|
||||||
|
.. _locale(1): http://linux.die.net/man/1/locale
|
||||||
|
|
||||||
|
|
||||||
|
.. _template_pages:
|
||||||
|
|
||||||
|
Template pages
|
||||||
|
==============
|
||||||
|
|
||||||
|
If you want to generate custom pages besides your blog entries, you can point
|
||||||
|
any Jinja2 template file with a path pointing to the file and the destination
|
||||||
|
path for the generated file.
|
||||||
|
|
||||||
|
For instance, if you have a blog with three static pages — a list of books,
|
||||||
|
your resume, and a contact page — you could have::
|
||||||
|
|
||||||
|
TEMPLATE_PAGES = {'src/books.html': 'dest/books.html',
|
||||||
|
'src/resume.html': 'dest/resume.html',
|
||||||
|
'src/contact.html': 'dest/contact.html'}
|
||||||
|
|
||||||
|
|
||||||
|
.. _path_metadata:
|
||||||
|
|
||||||
|
Path metadata
|
||||||
|
=============
|
||||||
|
|
||||||
|
Not all metadata needs to be `embedded in source file itself`__. For
|
||||||
|
example, blog posts are often named following a ``YYYY-MM-DD-SLUG.rst``
|
||||||
|
pattern, or nested into ``YYYY/MM/DD-SLUG`` directories. To extract
|
||||||
|
metadata from the filename or path, set ``FILENAME_METADATA`` or
|
||||||
|
``PATH_METADATA`` to regular expressions that use Python's `group name
|
||||||
|
notation`_ ``(?P<name>…)``. If you want to attach additional metadata
|
||||||
|
but don't want to encode it in the path, you can set
|
||||||
|
``EXTRA_PATH_METADATA``:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
EXTRA_PATH_METADATA = {
|
||||||
|
'relative/path/to/file-1': {
|
||||||
|
'key-1a': 'value-1a',
|
||||||
|
'key-1b': 'value-1b',
|
||||||
|
},
|
||||||
|
'relative/path/to/file-2': {
|
||||||
|
'key-2': 'value-2',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
This can be a convenient way to shift the installed location of a
|
||||||
|
particular file:
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
# Take advantage of the following defaults
|
||||||
|
# STATIC_SAVE_AS = '{path}'
|
||||||
|
# STATIC_URL = '{path}'
|
||||||
|
STATIC_PATHS = [
|
||||||
|
'extra/robots.txt',
|
||||||
|
]
|
||||||
|
EXTRA_PATH_METADATA = {
|
||||||
|
'extra/robots.txt': {'path': 'robots.txt'},
|
||||||
|
}
|
||||||
|
|
||||||
|
__ internal_metadata__
|
||||||
|
.. _group name notation:
|
||||||
|
http://docs.python.org/3/library/re.html#regular-expression-syntax
|
||||||
|
|
||||||
|
Feed settings
|
||||||
|
=============
|
||||||
|
|
||||||
|
By default, Pelican uses Atom feeds. However, it is also possible to use RSS
|
||||||
|
feeds if you prefer.
|
||||||
|
|
||||||
|
Pelican generates category feeds as well as feeds for all your articles. It does
|
||||||
|
not generate feeds for tags by default, but it is possible to do so using
|
||||||
|
the ``TAG_FEED_ATOM`` and ``TAG_FEED_RSS`` settings:
|
||||||
|
|
||||||
|
================================================ =====================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
================================================ =====================================================
|
||||||
|
`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_ATOM` (``None``, i.e. no Atom feed) Relative URL to output the Atom feed.
|
||||||
|
`FEED_RSS` (``None``, i.e. no RSS) Relative URL to output the RSS feed.
|
||||||
|
`FEED_ALL_ATOM` (``'feeds/all.atom.xml'``) Relative URL to output the all posts Atom feed:
|
||||||
|
this feed will contain all posts regardless of their
|
||||||
|
language.
|
||||||
|
`FEED_ALL_RSS` (``None``, i.e. no all RSS) Relative URL to output the all posts RSS feed:
|
||||||
|
this feed will contain all posts regardless of their
|
||||||
|
language.
|
||||||
|
`CATEGORY_FEED_ATOM` ('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_ATOM` (``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.
|
||||||
|
================================================ =====================================================
|
||||||
|
|
||||||
|
If you don't want to generate some or any of these feeds, set the above variables to ``None``.
|
||||||
|
|
||||||
|
.. [2] %s is the name of the category.
|
||||||
|
|
||||||
|
FeedBurner
|
||||||
|
----------
|
||||||
|
|
||||||
|
If you want to use FeedBurner for your feed, you will likely need to decide
|
||||||
|
upon a unique identifier. For example, if your site were called "Thyme" and
|
||||||
|
hosted on the www.example.com domain, you might use "thymefeeds" as your
|
||||||
|
unique identifier, which we'll use throughout this section for illustrative
|
||||||
|
purposes. In your Pelican settings, set the `FEED_ATOM` attribute to
|
||||||
|
"thymefeeds/main.xml" to create an Atom feed with an original address of
|
||||||
|
`http://www.example.com/thymefeeds/main.xml`. Set the `FEED_DOMAIN` attribute
|
||||||
|
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).
|
||||||
|
|
||||||
|
There are two fields to configure in the `FeedBurner
|
||||||
|
<http://feedburner.google.com>`_ interface: "Original Feed" and "Feed
|
||||||
|
Address". In this example, the "Original Feed" would be
|
||||||
|
`http://www.example.com/thymefeeds/main.xml` and the "Feed Address" suffix
|
||||||
|
would be `thymefeeds/main.xml`.
|
||||||
|
|
||||||
|
Pagination
|
||||||
|
==========
|
||||||
|
|
||||||
|
The default behaviour of Pelican is to list all the article titles along
|
||||||
|
with a short description on the index page. While it works pretty well
|
||||||
|
for small-to-medium blogs, for sites with large quantity of articles it would
|
||||||
|
be convenient to have a way to paginate the list.
|
||||||
|
|
||||||
|
You can use the following settings to configure the pagination.
|
||||||
|
|
||||||
|
================================================ =====================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
================================================ =====================================================
|
||||||
|
`DEFAULT_ORPHANS` (``0``) The minimum number of articles allowed on the
|
||||||
|
last page. Use this when you don't want to
|
||||||
|
have a last page with very few articles.
|
||||||
|
`DEFAULT_PAGINATION` (``False``) The maximum number of articles to include on a
|
||||||
|
page, not including orphans. False to disable
|
||||||
|
pagination.
|
||||||
|
================================================ =====================================================
|
||||||
|
|
||||||
|
Tag cloud
|
||||||
|
=========
|
||||||
|
|
||||||
|
If you want to generate a tag cloud with all your tags, you can do so using the
|
||||||
|
following settings.
|
||||||
|
|
||||||
|
================================================ =====================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
================================================ =====================================================
|
||||||
|
`TAG_CLOUD_STEPS` (``4``) Count of different font sizes in the tag
|
||||||
|
cloud.
|
||||||
|
`TAG_CLOUD_MAX_ITEMS` (``100``) Maximum number of tags in the cloud.
|
||||||
|
================================================ =====================================================
|
||||||
|
|
||||||
|
The default theme does not support tag clouds, but it is pretty easy to add::
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for tag in tag_cloud %}
|
||||||
|
<li class="tag-{{ tag.1 }}"><a href="/tag/{{ tag.0|string|replace(" ", "-" ) }}.html">{{ tag.0 }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
You should then also define a CSS style with the appropriate classes (tag-0 to tag-N, where
|
||||||
|
N matches `TAG_CLOUD_STEPS` -1).
|
||||||
|
|
||||||
|
Translations
|
||||||
|
============
|
||||||
|
|
||||||
|
Pelican offers a way to translate articles. See the :doc:`Getting Started <getting_started>` section for
|
||||||
|
more information.
|
||||||
|
|
||||||
|
===================================================== =====================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
===================================================== =====================================================
|
||||||
|
`DEFAULT_LANG` (``'en'``) The default language to use.
|
||||||
|
`TRANSLATION_FEED_ATOM` ('feeds/all-%s.atom.xml'[3]_) Where to put the Atom feed for translations.
|
||||||
|
`TRANSLATION_FEED_RSS` (``None``, i.e. no RSS) Where to put the RSS feed for translations.
|
||||||
|
===================================================== =====================================================
|
||||||
|
|
||||||
|
.. [3] %s is the language
|
||||||
|
|
||||||
|
Ordering content
|
||||||
|
=================
|
||||||
|
|
||||||
|
================================================ =====================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
================================================ =====================================================
|
||||||
|
`NEWEST_FIRST_ARCHIVES` (``True``) Order archives by newest first by date. (False:
|
||||||
|
orders by date with older articles first.)
|
||||||
|
`REVERSE_CATEGORY_ORDER` (``False``) Reverse the category order. (True: lists by reverse
|
||||||
|
alphabetical order; default lists alphabetically.)
|
||||||
|
================================================ =====================================================
|
||||||
|
|
||||||
|
Themes
|
||||||
|
======
|
||||||
|
|
||||||
|
Creating Pelican themes is addressed in a dedicated section (see :ref:`theming-pelican`).
|
||||||
|
However, here are the settings that are related to themes.
|
||||||
|
|
||||||
|
================================================ =====================================================
|
||||||
|
Setting name (default value) What does it do?
|
||||||
|
================================================ =====================================================
|
||||||
|
`THEME` Theme to use to produce the output. Can be a relative
|
||||||
|
or absolute path to a theme folder, or the name of a
|
||||||
|
default theme or a theme installed via
|
||||||
|
``pelican-themes`` (see below).
|
||||||
|
`THEME_STATIC_PATHS` (``['static']``) Static theme paths you want to copy. Default
|
||||||
|
value is `static`, but if your theme has
|
||||||
|
other static paths, you can put them here.
|
||||||
|
`CSS_FILE` (``'main.css'``) Specify the CSS file you want to load.
|
||||||
|
================================================ =====================================================
|
||||||
|
|
||||||
|
|
||||||
|
By default, two themes are available. You can specify them using the `THEME` setting or by passing the
|
||||||
|
``-t`` option to the ``pelican`` command:
|
||||||
|
|
||||||
|
* notmyidea
|
||||||
|
* simple (a synonym for "plain text" :)
|
||||||
|
|
||||||
|
There are a number of other themes available at http://github.com/getpelican/pelican-themes.
|
||||||
|
Pelican comes with :doc:`pelican-themes`, a small script for managing themes.
|
||||||
|
|
||||||
|
You can define your own theme, either by starting from scratch or by duplicating
|
||||||
|
and modifying a pre-existing theme. Here is :doc:`a guide on how to create your theme <themes>`.
|
||||||
|
|
||||||
|
Following are example ways to specify your preferred theme::
|
||||||
|
|
||||||
|
# Specify name of a built-in theme
|
||||||
|
THEME = "notmyidea"
|
||||||
|
# Specify name of a theme installed via the pelican-themes tool
|
||||||
|
THEME = "chunk"
|
||||||
|
# Specify a customized theme, via path relative to the settings file
|
||||||
|
THEME = "themes/mycustomtheme"
|
||||||
|
# Specify a customized theme, via absolute path
|
||||||
|
THEME = "~/projects/mysite/themes/mycustomtheme"
|
||||||
|
|
||||||
|
The built-in ``notmyidea`` theme can make good use of the following settings. Feel
|
||||||
|
free to use them in your themes as well.
|
||||||
|
|
||||||
|
======================= =======================================================
|
||||||
|
Setting name What does it do ?
|
||||||
|
======================= =======================================================
|
||||||
|
`SITESUBTITLE` A subtitle to appear in the header.
|
||||||
|
`DISQUS_SITENAME` Pelican can handle Disqus comments. Specify the
|
||||||
|
Disqus sitename identifier here.
|
||||||
|
`GITHUB_URL` Your GitHub URL (if you have one). It will then
|
||||||
|
use this information to create a GitHub ribbon.
|
||||||
|
`GOOGLE_ANALYTICS` 'UA-XXXX-YYYY' to activate Google Analytics.
|
||||||
|
`GOSQUARED_SITENAME` 'XXX-YYYYYY-X' to activate GoSquared.
|
||||||
|
`MENUITEMS` A list of tuples (Title, URL) for additional menu
|
||||||
|
items to appear at the beginning of the main menu.
|
||||||
|
`PIWIK_URL` URL to your Piwik server - without 'http://' at the
|
||||||
|
beginning.
|
||||||
|
`PIWIK_SSL_URL` If the SSL-URL differs from the normal Piwik-URL
|
||||||
|
you have to include this setting too. (optional)
|
||||||
|
`PIWIK_SITE_ID` ID for the monitored website. You can find the ID
|
||||||
|
in the Piwik admin interface > settings > websites.
|
||||||
|
`LINKS` A list of tuples (Title, URL) for links to appear on
|
||||||
|
the header.
|
||||||
|
`SOCIAL` A list of tuples (Title, URL) to appear in the
|
||||||
|
"social" section.
|
||||||
|
`TWITTER_USERNAME` Allows for adding a button to articles to encourage
|
||||||
|
others to tweet about them. Add your Twitter username
|
||||||
|
if you want this button to appear.
|
||||||
|
======================= =======================================================
|
||||||
|
|
||||||
|
In addition, you can use the "wide" version of the ``notmyidea`` theme by
|
||||||
|
adding the following to your configuration::
|
||||||
|
|
||||||
|
CSS_FILE = "wide.css"
|
||||||
|
|
||||||
|
Example settings
|
||||||
|
================
|
||||||
|
|
||||||
|
.. literalinclude:: ../samples/pelican.conf.py
|
||||||
|
:language: python
|
||||||
|
|
||||||
|
|
||||||
|
.. _Jinja custom filters documentation: http://jinja.pocoo.org/docs/api/#custom-filters
|
||||||
347
docs/themes.rst
Normal file
347
docs/themes.rst
Normal file
|
|
@ -0,0 +1,347 @@
|
||||||
|
.. _theming-pelican:
|
||||||
|
|
||||||
|
How to create themes for Pelican
|
||||||
|
################################
|
||||||
|
|
||||||
|
Pelican uses the great `Jinja2 <http://jinja.pocoo.org/>`_ templating engine to
|
||||||
|
generate its HTML output. Jinja2 syntax is really simple. If you want to
|
||||||
|
create your own theme, feel free to take inspiration from the `"simple" theme
|
||||||
|
<https://github.com/getpelican/pelican/tree/master/pelican/themes/simple/templates>`_.
|
||||||
|
|
||||||
|
Structure
|
||||||
|
=========
|
||||||
|
|
||||||
|
To make your own theme, you must follow the following structure::
|
||||||
|
|
||||||
|
├── static
|
||||||
|
│ ├── css
|
||||||
|
│ └── images
|
||||||
|
└── templates
|
||||||
|
├── archives.html // to display archives
|
||||||
|
├── period_archives.html // to display time-period archives
|
||||||
|
├── article.html // processed for each article
|
||||||
|
├── author.html // processed for each author
|
||||||
|
├── authors.html // must list all the authors
|
||||||
|
├── categories.html // must list all the categories
|
||||||
|
├── category.html // processed for each category
|
||||||
|
├── index.html // the index. List all the articles
|
||||||
|
├── page.html // processed for each page
|
||||||
|
├── tag.html // processed for each tag
|
||||||
|
└── tags.html // must list all the tags. Can be a tag cloud.
|
||||||
|
|
||||||
|
* `static` contains all the static assets, which will be copied to the output
|
||||||
|
`theme` folder. I've put the CSS and image folders here, but they are
|
||||||
|
just examples. Put what you need here.
|
||||||
|
|
||||||
|
* `templates` contains all the templates that will be used to generate the content.
|
||||||
|
I've just put the mandatory templates here; you can define your own if it helps
|
||||||
|
you keep things organized while creating your theme.
|
||||||
|
|
||||||
|
Templates and variables
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The idea is to use a simple syntax that you can embed into your HTML pages.
|
||||||
|
This document describes which templates should exist in a theme, and which
|
||||||
|
variables will be passed to each template at generation time.
|
||||||
|
|
||||||
|
All templates will receive the variables defined in your settings file, if they
|
||||||
|
are in all-caps. You can access them directly.
|
||||||
|
|
||||||
|
Common variables
|
||||||
|
----------------
|
||||||
|
|
||||||
|
All of these settings will be available to all templates.
|
||||||
|
|
||||||
|
============= ===================================================
|
||||||
|
Variable Description
|
||||||
|
============= ===================================================
|
||||||
|
output_file The name of the file currently being generated. For
|
||||||
|
instance, when Pelican is rendering the homepage,
|
||||||
|
output_file will be "index.html".
|
||||||
|
articles The list of articles, ordered descending by date
|
||||||
|
All the elements are `Article` objects, so you can
|
||||||
|
access their attributes (e.g. title, summary, author
|
||||||
|
etc.). Sometimes this is shadowed (for instance in
|
||||||
|
the tags page). You will then find info about it
|
||||||
|
in the `all_articles` variable.
|
||||||
|
dates The same list of articles, but ordered by date,
|
||||||
|
ascending
|
||||||
|
tags A list of (tag, articles) tuples, containing all
|
||||||
|
the tags.
|
||||||
|
categories A list of (category, articles) tuples, containing
|
||||||
|
all the categories.
|
||||||
|
and the list of respective articles (values)
|
||||||
|
pages The list of pages
|
||||||
|
============= ===================================================
|
||||||
|
|
||||||
|
Sorting
|
||||||
|
-------
|
||||||
|
|
||||||
|
URL wrappers (currently categories, tags, and authors), have
|
||||||
|
comparison methods that allow them to be easily sorted by name::
|
||||||
|
|
||||||
|
{% for tag, articles in tags|sort %}
|
||||||
|
|
||||||
|
If you want to sort based on different criteria, `Jinja's sort
|
||||||
|
command`__ has a number of options.
|
||||||
|
|
||||||
|
__ http://jinja.pocoo.org/docs/templates/#sort
|
||||||
|
|
||||||
|
|
||||||
|
Date Formatting
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Pelican formats the date with according to your settings and locale
|
||||||
|
(``DATE_FORMATS``/``DEFAULT_DATE_FORMAT``) and provides a
|
||||||
|
``locale_date`` attribute. On the other hand, ``date`` attribute will
|
||||||
|
be a `datetime`_ object. If you need custom formatting for a date
|
||||||
|
different than your settings, use the Jinja filter ``strftime``
|
||||||
|
that comes with Pelican. Usage is same as Python `strftime`_ format,
|
||||||
|
but the filter will do the right thing and format your date according
|
||||||
|
to the locale given in your settings::
|
||||||
|
|
||||||
|
{{ article.date|strftime('%d %B %Y') }}
|
||||||
|
|
||||||
|
.. _datetime: http://docs.python.org/2/library/datetime.html#datetime-objects
|
||||||
|
.. _strftime: http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior
|
||||||
|
|
||||||
|
index.html
|
||||||
|
----------
|
||||||
|
|
||||||
|
This is the home page of your blog, generated at output/index.html.
|
||||||
|
|
||||||
|
If pagination is active, subsequent pages will reside in output/index`n`.html.
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
articles_paginator A paginator object for the list of articles
|
||||||
|
articles_page The current page of articles
|
||||||
|
dates_paginator A paginator object for the article list, ordered by
|
||||||
|
date, ascending.
|
||||||
|
dates_page The current page of articles, ordered by date,
|
||||||
|
ascending.
|
||||||
|
page_name 'index' -- useful for pagination links
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
|
author.html
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This template will be processed for each of the existing authors, with
|
||||||
|
output generated at output/author/`author_name`.html.
|
||||||
|
|
||||||
|
If pagination is active, subsequent pages will reside as defined by setting
|
||||||
|
AUTHOR_SAVE_AS (`Default:` output/author/`author_name'n'`.html).
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
author The name of the author being processed
|
||||||
|
articles Articles by this author
|
||||||
|
dates Articles by this author, but ordered by date,
|
||||||
|
ascending
|
||||||
|
articles_paginator A paginator object for the list of articles
|
||||||
|
articles_page The current page of articles
|
||||||
|
dates_paginator A paginator object for the article list, ordered by
|
||||||
|
date, ascending.
|
||||||
|
dates_page The current page of articles, ordered by date,
|
||||||
|
ascending.
|
||||||
|
page_name AUTHOR_URL where everything after `{slug}` is
|
||||||
|
removed -- useful for pagination links
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
|
category.html
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This template will be processed for each of the existing categories, with
|
||||||
|
output generated at output/category/`category_name`.html.
|
||||||
|
|
||||||
|
If pagination is active, subsequent pages will reside as defined by setting
|
||||||
|
CATEGORY_SAVE_AS (`Default:` output/category/`category_name'n'`.html).
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
category The name of the category being processed
|
||||||
|
articles Articles for this category
|
||||||
|
dates Articles for this category, but ordered by date,
|
||||||
|
ascending
|
||||||
|
articles_paginator A paginator object for the list of articles
|
||||||
|
articles_page The current page of articles
|
||||||
|
dates_paginator A paginator object for the list of articles,
|
||||||
|
ordered by date, ascending
|
||||||
|
dates_page The current page of articles, ordered by date,
|
||||||
|
ascending
|
||||||
|
page_name CATEGORY_URL where everything after `{slug}` is
|
||||||
|
removed -- useful for pagination links
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
|
article.html
|
||||||
|
-------------
|
||||||
|
|
||||||
|
This template will be processed for each article, with .html files saved
|
||||||
|
as output/`article_name`.html. Here are the specific variables it gets.
|
||||||
|
|
||||||
|
============= ===================================================
|
||||||
|
Variable Description
|
||||||
|
============= ===================================================
|
||||||
|
article The article object to be displayed
|
||||||
|
category The name of the category for the current article
|
||||||
|
============= ===================================================
|
||||||
|
|
||||||
|
page.html
|
||||||
|
---------
|
||||||
|
|
||||||
|
This template will be processed for each page, with corresponding .html files
|
||||||
|
saved as output/`page_name`.html.
|
||||||
|
|
||||||
|
============= ===================================================
|
||||||
|
Variable Description
|
||||||
|
============= ===================================================
|
||||||
|
page The page object to be displayed. You can access its
|
||||||
|
title, slug, and content.
|
||||||
|
============= ===================================================
|
||||||
|
|
||||||
|
tag.html
|
||||||
|
--------
|
||||||
|
|
||||||
|
This template will be processed for each tag, with corresponding .html files
|
||||||
|
saved as output/tag/`tag_name`.html.
|
||||||
|
|
||||||
|
If pagination is active, subsequent pages will reside as defined in setting
|
||||||
|
TAG_SAVE_AS (`Default:` output/tag/`tag_name'n'`.html).
|
||||||
|
|
||||||
|
=================== ===================================================
|
||||||
|
Variable Description
|
||||||
|
=================== ===================================================
|
||||||
|
tag The name of the tag being processed
|
||||||
|
articles Articles related to this tag
|
||||||
|
dates Articles related to this tag, but ordered by date,
|
||||||
|
ascending
|
||||||
|
articles_paginator A paginator object for the list of articles
|
||||||
|
articles_page The current page of articles
|
||||||
|
dates_paginator A paginator object for the list of articles,
|
||||||
|
ordered by date, ascending
|
||||||
|
dates_page The current page of articles, ordered by date,
|
||||||
|
ascending
|
||||||
|
page_name TAG_URL where everything after `{slug}` is removed
|
||||||
|
-- useful for pagination links
|
||||||
|
=================== ===================================================
|
||||||
|
|
||||||
|
Feeds
|
||||||
|
=====
|
||||||
|
|
||||||
|
The feed variables changed in 3.0. Each variable now explicitly lists ATOM or
|
||||||
|
RSS in the name. ATOM is still the default. Old themes will need to be updated.
|
||||||
|
Here is a complete list of the feed variables::
|
||||||
|
|
||||||
|
FEED_ATOM
|
||||||
|
FEED_RSS
|
||||||
|
FEED_ALL_ATOM
|
||||||
|
FEED_ALL_RSS
|
||||||
|
CATEGORY_FEED_ATOM
|
||||||
|
CATEGORY_FEED_RSS
|
||||||
|
TAG_FEED_ATOM
|
||||||
|
TAG_FEED_RSS
|
||||||
|
TRANSLATION_FEED_ATOM
|
||||||
|
TRANSLATION_FEED_RSS
|
||||||
|
|
||||||
|
|
||||||
|
Inheritance
|
||||||
|
===========
|
||||||
|
|
||||||
|
Since version 3.0, Pelican supports inheritance from the ``simple`` theme, so
|
||||||
|
you can re-use the ``simple`` theme templates in your own themes.
|
||||||
|
|
||||||
|
If one of the mandatory files in the ``templates/`` directory of your theme is
|
||||||
|
missing, it will be replaced by the matching template from the ``simple`` theme.
|
||||||
|
So if the HTML structure of a template in the ``simple`` theme is right for you,
|
||||||
|
you don't have to write a new template from scratch.
|
||||||
|
|
||||||
|
You can also extend templates from the ``simple`` themes in your own themes by using the ``{% extends %}`` directive as in the following example:
|
||||||
|
|
||||||
|
.. code-block:: html+jinja
|
||||||
|
|
||||||
|
{% extends "!simple/index.html" %} <!-- extends the ``index.html`` template from the ``simple`` theme -->
|
||||||
|
|
||||||
|
{% extends "index.html" %} <!-- "regular" extending -->
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
With this system, it is possible to create a theme with just two files.
|
||||||
|
|
||||||
|
base.html
|
||||||
|
"""""""""
|
||||||
|
|
||||||
|
The first file is the ``templates/base.html`` template:
|
||||||
|
|
||||||
|
.. code-block:: html+jinja
|
||||||
|
|
||||||
|
{% extends "!simple/base.html" %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ SITEURL }}/theme/css/style.css" />
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
1. On the first line, we extend the ``base.html`` template from the ``simple`` theme, so we don't have to rewrite the entire file.
|
||||||
|
2. On the third line, we open the ``head`` block which has already been defined in the ``simple`` theme.
|
||||||
|
3. On the fourth line, the function ``super()`` keeps the content previously inserted in the ``head`` block.
|
||||||
|
4. On the fifth line, we append a stylesheet to the page.
|
||||||
|
5. On the last line, we close the ``head`` block.
|
||||||
|
|
||||||
|
This file will be extended by all the other templates, so the stylesheet will be linked from all pages.
|
||||||
|
|
||||||
|
style.css
|
||||||
|
"""""""""
|
||||||
|
|
||||||
|
The second file is the ``static/css/style.css`` CSS stylesheet:
|
||||||
|
|
||||||
|
.. code-block:: css
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family : monospace ;
|
||||||
|
font-size : 100% ;
|
||||||
|
background-color : white ;
|
||||||
|
color : #111 ;
|
||||||
|
width : 80% ;
|
||||||
|
min-width : 400px ;
|
||||||
|
min-height : 200px ;
|
||||||
|
padding : 1em ;
|
||||||
|
margin : 5% 10% ;
|
||||||
|
border : thin solid gray ;
|
||||||
|
border-radius : 5px ;
|
||||||
|
display : block ;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link { color : blue ; text-decoration : none ; }
|
||||||
|
a:hover { color : blue ; text-decoration : underline ; }
|
||||||
|
a:visited { color : blue ; }
|
||||||
|
|
||||||
|
h1 a { color : inherit !important }
|
||||||
|
h2 a { color : inherit !important }
|
||||||
|
h3 a { color : inherit !important }
|
||||||
|
h4 a { color : inherit !important }
|
||||||
|
h5 a { color : inherit !important }
|
||||||
|
h6 a { color : inherit !important }
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin : 2em 1em 2em 4em ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#menu li {
|
||||||
|
display : inline ;
|
||||||
|
}
|
||||||
|
|
||||||
|
#post-list {
|
||||||
|
margin-bottom : 1em ;
|
||||||
|
margin-top : 1em ;
|
||||||
|
}
|
||||||
|
|
||||||
|
Download
|
||||||
|
""""""""
|
||||||
|
|
||||||
|
You can download this example theme :download:`here <_static/theme-basic.zip>`.
|
||||||
85
docs/tips.rst
Normal file
85
docs/tips.rst
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
Tips
|
||||||
|
####
|
||||||
|
|
||||||
|
Here are some tips about Pelican that you might find useful.
|
||||||
|
|
||||||
|
Publishing to GitHub
|
||||||
|
====================
|
||||||
|
|
||||||
|
`GitHub Pages <https://help.github.com/categories/20/articles>`_ offer an easy
|
||||||
|
and convenient way to publish Pelican sites. There are `two types of GitHub
|
||||||
|
Pages <https://help.github.com/articles/user-organization-and-project-pages>`_:
|
||||||
|
*Project Pages* and *User Pages*. Pelican sites can be published as both
|
||||||
|
Project Pages and User Pages.
|
||||||
|
|
||||||
|
Project Pages
|
||||||
|
-------------
|
||||||
|
|
||||||
|
To publish a Pelican site as Project Pages you need to *push* the content of
|
||||||
|
the ``output`` dir generated by Pelican to a repository's ``gh-pages`` branch
|
||||||
|
on GitHub.
|
||||||
|
|
||||||
|
The excellent `ghp-import <https://github.com/davisp/ghp-import>`_, which can
|
||||||
|
be installed with ``easy_install`` or ``pip``, makes this process really easy.
|
||||||
|
|
||||||
|
For example, if the sources of your Pelican site are contained in a GitHub
|
||||||
|
repository, and if you want to publish your Pelican site as Project Pages of
|
||||||
|
this repository, you can then use the following::
|
||||||
|
|
||||||
|
$ pelican content -o output -s pelicanconf.py
|
||||||
|
$ ghp-import output
|
||||||
|
$ git push origin gh-pages
|
||||||
|
|
||||||
|
The ``ghp-import output`` command updates the local ``gh-pages`` branch with
|
||||||
|
the content of the ``output`` directory (creating the branch if it doesn't
|
||||||
|
already exist). The ``git push origin gh-pages`` command updates the remote
|
||||||
|
``gh-pages`` branch, effectively publishing the Pelican site.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The ``github`` target of the Makefile created by the ``pelican-quickstart``
|
||||||
|
command publishes the Pelican site as Project Pages as described above.
|
||||||
|
|
||||||
|
User Pages
|
||||||
|
----------
|
||||||
|
|
||||||
|
To publish a Pelican site as User Pages you need to *push* the content of the
|
||||||
|
``output`` dir generated by Pelican to the ``master`` branch of your
|
||||||
|
``<username>.github.com`` repository on GitHub.
|
||||||
|
|
||||||
|
Again, you can take advantage of ``ghp-import``::
|
||||||
|
|
||||||
|
$ pelican content -o output -s pelicanconf.py
|
||||||
|
$ ghp-import output
|
||||||
|
$ git push git@github.com:elemoine/elemoine.github.com.git gh-pages:master
|
||||||
|
|
||||||
|
The ``git push`` command pushes the local ``gh-pages`` branch (freshly updated
|
||||||
|
by the ``ghp-import`` command) to the ``elemoine.github.com`` repository's
|
||||||
|
``master`` branch on GitHub.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
To publish your Pelican site as User Pages feel free to adjust the the
|
||||||
|
``github`` target of the Makefile.
|
||||||
|
|
||||||
|
Extra Tips
|
||||||
|
----------
|
||||||
|
|
||||||
|
Tip #1:
|
||||||
|
|
||||||
|
To automatically update your Pelican site on each commit you can create
|
||||||
|
a post-commit hook. For example, you can add the following to
|
||||||
|
``.git/hooks/post-commit``::
|
||||||
|
|
||||||
|
pelican pelican content -o output -s pelicanconf.py && ghp-import output && git push origin gh-pages
|
||||||
|
|
||||||
|
Tip #2:
|
||||||
|
|
||||||
|
To use a `custom domain
|
||||||
|
<https://help.github.com/articles/setting-up-a-custom-domain-with-pages>`_ with
|
||||||
|
GitHub Pages you need to have a ``CNAME`` file at the root of your pages. For
|
||||||
|
that you will add ``CNAME`` file to your ``content``, dir and use the
|
||||||
|
``FILES_TO_COPY`` setting variable to tell Pelican to copy that file
|
||||||
|
to the ``output`` dir. For example::
|
||||||
|
|
||||||
|
FILES_TO_COPY = (('extra/CNAME', 'CNAME'),)
|
||||||
1556
package-lock.json
generated
1556
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"devDependencies": {
|
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
|
||||||
"tailwindcss": "^3.4.17"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
400
pelican/__init__.py
Normal file
400
pelican/__init__.py
Normal file
|
|
@ -0,0 +1,400 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
import six
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import argparse
|
||||||
|
import locale
|
||||||
|
import collections
|
||||||
|
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
|
from pelican.generators import (ArticlesGenerator, PagesGenerator,
|
||||||
|
StaticGenerator, PdfGenerator,
|
||||||
|
SourceFileGenerator, TemplatePagesGenerator)
|
||||||
|
from pelican.log import init
|
||||||
|
from pelican.settings import read_settings
|
||||||
|
from pelican.utils import clean_output_dir, folder_watcher, file_watcher
|
||||||
|
from pelican.writers import Writer
|
||||||
|
|
||||||
|
__major__ = 3
|
||||||
|
__minor__ = 2
|
||||||
|
__micro__ = 0
|
||||||
|
__version__ = "{0}.{1}.{2}".format(__major__, __minor__, __micro__)
|
||||||
|
|
||||||
|
DEFAULT_CONFIG_NAME = 'pelicanconf.py'
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Pelican(object):
|
||||||
|
def __init__(self, settings):
|
||||||
|
"""
|
||||||
|
Pelican initialisation, performs some checks on the environment before
|
||||||
|
doing anything else.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# define the default settings
|
||||||
|
self.settings = settings
|
||||||
|
self._handle_deprecation()
|
||||||
|
|
||||||
|
self.path = settings['PATH']
|
||||||
|
self.theme = settings['THEME']
|
||||||
|
self.output_path = settings['OUTPUT_PATH']
|
||||||
|
self.markup = settings['MARKUP']
|
||||||
|
self.ignore_files = settings['IGNORE_FILES']
|
||||||
|
self.delete_outputdir = settings['DELETE_OUTPUT_DIRECTORY']
|
||||||
|
self.output_retention = settings['OUTPUT_RETENTION']
|
||||||
|
|
||||||
|
self.init_path()
|
||||||
|
self.init_plugins()
|
||||||
|
signals.initialized.send(self)
|
||||||
|
|
||||||
|
def init_path(self):
|
||||||
|
if not any(p in sys.path for p in ['', os.curdir]):
|
||||||
|
logger.debug("Adding current directory to system path")
|
||||||
|
sys.path.insert(0, '')
|
||||||
|
|
||||||
|
def init_plugins(self):
|
||||||
|
self.plugins = []
|
||||||
|
logger.debug('Temporarily adding PLUGIN_PATH to system path')
|
||||||
|
_sys_path = sys.path[:]
|
||||||
|
sys.path.insert(0, self.settings['PLUGIN_PATH'])
|
||||||
|
for plugin in self.settings['PLUGINS']:
|
||||||
|
# if it's a string, then import it
|
||||||
|
if isinstance(plugin, six.string_types):
|
||||||
|
logger.debug("Loading plugin `{0}`".format(plugin))
|
||||||
|
try:
|
||||||
|
plugin = __import__(plugin, globals(), locals(), str('module'))
|
||||||
|
except ImportError as e:
|
||||||
|
logger.error("Can't find plugin `{0}`: {1}".format(plugin, e))
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.debug("Registering plugin `{0}`".format(plugin.__name__))
|
||||||
|
plugin.register()
|
||||||
|
self.plugins.append(plugin)
|
||||||
|
logger.debug('Restoring system path')
|
||||||
|
sys.path = _sys_path
|
||||||
|
|
||||||
|
def _handle_deprecation(self):
|
||||||
|
|
||||||
|
if self.settings.get('CLEAN_URLS', False):
|
||||||
|
logger.warning('Found deprecated `CLEAN_URLS` in settings.'
|
||||||
|
' Modifying the following settings for the'
|
||||||
|
' same behaviour.')
|
||||||
|
|
||||||
|
self.settings['ARTICLE_URL'] = '{slug}/'
|
||||||
|
self.settings['ARTICLE_LANG_URL'] = '{slug}-{lang}/'
|
||||||
|
self.settings['PAGE_URL'] = 'pages/{slug}/'
|
||||||
|
self.settings['PAGE_LANG_URL'] = 'pages/{slug}-{lang}/'
|
||||||
|
|
||||||
|
for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL',
|
||||||
|
'PAGE_LANG_URL'):
|
||||||
|
logger.warning("%s = '%s'" % (setting, self.settings[setting]))
|
||||||
|
|
||||||
|
if self.settings.get('ARTICLE_PERMALINK_STRUCTURE', False):
|
||||||
|
logger.warning('Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in'
|
||||||
|
' settings. Modifying the following settings for'
|
||||||
|
' the same behaviour.')
|
||||||
|
|
||||||
|
structure = self.settings['ARTICLE_PERMALINK_STRUCTURE']
|
||||||
|
|
||||||
|
# Convert %(variable) into {variable}.
|
||||||
|
structure = re.sub('%\((\w+)\)s', '{\g<1>}', structure)
|
||||||
|
|
||||||
|
# Convert %x into {date:%x} for strftime
|
||||||
|
structure = re.sub('(%[A-z])', '{date:\g<1>}', structure)
|
||||||
|
|
||||||
|
# Strip a / prefix
|
||||||
|
structure = re.sub('^/', '', structure)
|
||||||
|
|
||||||
|
for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL',
|
||||||
|
'PAGE_LANG_URL', 'ARTICLE_SAVE_AS',
|
||||||
|
'ARTICLE_LANG_SAVE_AS', 'PAGE_SAVE_AS',
|
||||||
|
'PAGE_LANG_SAVE_AS'):
|
||||||
|
self.settings[setting] = os.path.join(structure,
|
||||||
|
self.settings[setting])
|
||||||
|
logger.warning("%s = '%s'" % (setting, self.settings[setting]))
|
||||||
|
|
||||||
|
if self.settings.get('FEED', False):
|
||||||
|
logger.warning('Found deprecated `FEED` in settings. Modify FEED'
|
||||||
|
' to FEED_ATOM in your settings and theme for the same behavior.'
|
||||||
|
' Temporarily setting FEED_ATOM for backwards compatibility.')
|
||||||
|
self.settings['FEED_ATOM'] = self.settings['FEED']
|
||||||
|
|
||||||
|
if self.settings.get('TAG_FEED', False):
|
||||||
|
logger.warning('Found deprecated `TAG_FEED` in settings. Modify '
|
||||||
|
' TAG_FEED to TAG_FEED_ATOM in your settings and theme for the '
|
||||||
|
'same behavior. Temporarily setting TAG_FEED_ATOM for backwards '
|
||||||
|
'compatibility.')
|
||||||
|
self.settings['TAG_FEED_ATOM'] = self.settings['TAG_FEED']
|
||||||
|
|
||||||
|
if self.settings.get('CATEGORY_FEED', False):
|
||||||
|
logger.warning('Found deprecated `CATEGORY_FEED` in settings. '
|
||||||
|
'Modify CATEGORY_FEED to CATEGORY_FEED_ATOM in your settings and '
|
||||||
|
'theme for the same behavior. Temporarily setting '
|
||||||
|
'CATEGORY_FEED_ATOM for backwards compatibility.')
|
||||||
|
self.settings['CATEGORY_FEED_ATOM'] =\
|
||||||
|
self.settings['CATEGORY_FEED']
|
||||||
|
|
||||||
|
if self.settings.get('TRANSLATION_FEED', False):
|
||||||
|
logger.warning('Found deprecated `TRANSLATION_FEED` in settings. '
|
||||||
|
'Modify TRANSLATION_FEED to TRANSLATION_FEED_ATOM in your '
|
||||||
|
'settings and theme for the same behavior. Temporarily setting '
|
||||||
|
'TRANSLATION_FEED_ATOM for backwards compatibility.')
|
||||||
|
self.settings['TRANSLATION_FEED_ATOM'] =\
|
||||||
|
self.settings['TRANSLATION_FEED']
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Run the generators and return"""
|
||||||
|
start_time = time.time()
|
||||||
|
|
||||||
|
context = self.settings.copy()
|
||||||
|
context['filenames'] = {} # share the dict between all the generators
|
||||||
|
context['localsiteurl'] = self.settings['SITEURL'] # share
|
||||||
|
generators = [
|
||||||
|
cls(
|
||||||
|
context=context,
|
||||||
|
settings=self.settings,
|
||||||
|
path=self.path,
|
||||||
|
theme=self.theme,
|
||||||
|
output_path=self.output_path,
|
||||||
|
markup=self.markup,
|
||||||
|
) for cls in self.get_generator_classes()
|
||||||
|
]
|
||||||
|
|
||||||
|
for p in generators:
|
||||||
|
if hasattr(p, 'generate_context'):
|
||||||
|
p.generate_context()
|
||||||
|
|
||||||
|
# erase the directory if it is not the source and if that's
|
||||||
|
# explicitely asked
|
||||||
|
if (self.delete_outputdir and not
|
||||||
|
os.path.realpath(self.path).startswith(self.output_path)):
|
||||||
|
clean_output_dir(self.output_path, self.output_retention)
|
||||||
|
|
||||||
|
writer = self.get_writer()
|
||||||
|
|
||||||
|
for p in generators:
|
||||||
|
if hasattr(p, 'generate_output'):
|
||||||
|
p.generate_output(writer)
|
||||||
|
|
||||||
|
signals.finalized.send(self)
|
||||||
|
|
||||||
|
articles_generator = next(g for g in generators if isinstance(g, ArticlesGenerator))
|
||||||
|
pages_generator = next(g for g in generators if isinstance(g, PagesGenerator))
|
||||||
|
|
||||||
|
print('Done: Processed {} articles and {} pages in {:.2f} seconds.'.format(
|
||||||
|
len(articles_generator.articles) + len(articles_generator.translations),
|
||||||
|
len(pages_generator.pages) + len(pages_generator.translations),
|
||||||
|
time.time() - start_time))
|
||||||
|
|
||||||
|
def get_generator_classes(self):
|
||||||
|
generators = [StaticGenerator, ArticlesGenerator, PagesGenerator]
|
||||||
|
|
||||||
|
if self.settings['TEMPLATE_PAGES']:
|
||||||
|
generators.append(TemplatePagesGenerator)
|
||||||
|
if self.settings['PDF_GENERATOR']:
|
||||||
|
generators.append(PdfGenerator)
|
||||||
|
if self.settings['OUTPUT_SOURCES']:
|
||||||
|
generators.append(SourceFileGenerator)
|
||||||
|
|
||||||
|
for pair in signals.get_generators.send(self):
|
||||||
|
(funct, value) = pair
|
||||||
|
|
||||||
|
if not isinstance(value, collections.Iterable):
|
||||||
|
value = (value, )
|
||||||
|
|
||||||
|
for v in value:
|
||||||
|
if isinstance(v, type):
|
||||||
|
logger.debug('Found generator: {0}'.format(v))
|
||||||
|
generators.append(v)
|
||||||
|
|
||||||
|
return generators
|
||||||
|
|
||||||
|
def get_writer(self):
|
||||||
|
return Writer(self.output_path, settings=self.settings)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_arguments():
|
||||||
|
parser = argparse.ArgumentParser(description="""A tool to generate a
|
||||||
|
static blog, with restructured text input files.""",
|
||||||
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
|
|
||||||
|
parser.add_argument(dest='path', nargs='?',
|
||||||
|
help='Path where to find the content files.',
|
||||||
|
default=None)
|
||||||
|
|
||||||
|
parser.add_argument('-t', '--theme-path', dest='theme',
|
||||||
|
help='Path where to find the theme templates. If not specified, it'
|
||||||
|
'will use the default one included with pelican.')
|
||||||
|
|
||||||
|
parser.add_argument('-o', '--output', dest='output',
|
||||||
|
help='Where to output the generated files. If not specified, a '
|
||||||
|
'directory will be created, named "output" in the current path.')
|
||||||
|
|
||||||
|
parser.add_argument('-m', '--markup', dest='markup',
|
||||||
|
help='The list of markup language to use (rst or md). Please indicate '
|
||||||
|
'them separated by commas.')
|
||||||
|
|
||||||
|
parser.add_argument('-s', '--settings', dest='settings',
|
||||||
|
help='The settings of the application, this is automatically set to '
|
||||||
|
'{0} if a file exists with this name.'.format(DEFAULT_CONFIG_NAME))
|
||||||
|
|
||||||
|
parser.add_argument('-d', '--delete-output-directory',
|
||||||
|
dest='delete_outputdir',
|
||||||
|
action='store_true',
|
||||||
|
default=None,
|
||||||
|
help='Delete the output directory.')
|
||||||
|
|
||||||
|
parser.add_argument('-v', '--verbose', action='store_const',
|
||||||
|
const=logging.INFO, dest='verbosity',
|
||||||
|
help='Show all messages.')
|
||||||
|
|
||||||
|
parser.add_argument('-q', '--quiet', action='store_const',
|
||||||
|
const=logging.CRITICAL, dest='verbosity',
|
||||||
|
help='Show only critical errors.')
|
||||||
|
|
||||||
|
parser.add_argument('-D', '--debug', action='store_const',
|
||||||
|
const=logging.DEBUG, dest='verbosity',
|
||||||
|
help='Show all message, including debug messages.')
|
||||||
|
|
||||||
|
parser.add_argument('--version', action='version', version=__version__,
|
||||||
|
help='Print the pelican version and exit.')
|
||||||
|
|
||||||
|
parser.add_argument('-r', '--autoreload', dest='autoreload',
|
||||||
|
action='store_true',
|
||||||
|
help="Relaunch pelican each time a modification occurs"
|
||||||
|
" on the content files.")
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
|
def get_config(args):
|
||||||
|
config = {}
|
||||||
|
if args.path:
|
||||||
|
config['PATH'] = os.path.abspath(os.path.expanduser(args.path))
|
||||||
|
if args.output:
|
||||||
|
config['OUTPUT_PATH'] = \
|
||||||
|
os.path.abspath(os.path.expanduser(args.output))
|
||||||
|
if args.markup:
|
||||||
|
config['MARKUP'] = [a.strip().lower() for a in args.markup.split(',')]
|
||||||
|
if args.theme:
|
||||||
|
abstheme = os.path.abspath(os.path.expanduser(args.theme))
|
||||||
|
config['THEME'] = abstheme if os.path.exists(abstheme) else args.theme
|
||||||
|
if args.delete_outputdir is not None:
|
||||||
|
config['DELETE_OUTPUT_DIRECTORY'] = args.delete_outputdir
|
||||||
|
|
||||||
|
# argparse returns bytes in Py2. There is no definite answer as to which
|
||||||
|
# encoding argparse (or sys.argv) uses.
|
||||||
|
# "Best" option seems to be locale.getpreferredencoding()
|
||||||
|
# ref: http://mail.python.org/pipermail/python-list/2006-October/405766.html
|
||||||
|
if not six.PY3:
|
||||||
|
enc = locale.getpreferredencoding()
|
||||||
|
for key in config:
|
||||||
|
if key in ('PATH', 'OUTPUT_PATH', 'THEME'):
|
||||||
|
config[key] = config[key].decode(enc)
|
||||||
|
if key == "MARKUP":
|
||||||
|
config[key] = [a.decode(enc) for a in config[key]]
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
def get_instance(args):
|
||||||
|
|
||||||
|
config_file = args.settings
|
||||||
|
if config_file is None and os.path.isfile(DEFAULT_CONFIG_NAME):
|
||||||
|
config_file = DEFAULT_CONFIG_NAME
|
||||||
|
|
||||||
|
settings = read_settings(config_file, override=get_config(args))
|
||||||
|
|
||||||
|
cls = settings['PELICAN_CLASS']
|
||||||
|
if isinstance(cls, six.string_types):
|
||||||
|
module, cls_name = cls.rsplit('.', 1)
|
||||||
|
module = __import__(module)
|
||||||
|
cls = getattr(module, cls_name)
|
||||||
|
|
||||||
|
return cls(settings)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parse_arguments()
|
||||||
|
init(args.verbosity)
|
||||||
|
pelican = get_instance(args)
|
||||||
|
|
||||||
|
watchers = {'content': folder_watcher(pelican.path,
|
||||||
|
pelican.markup,
|
||||||
|
pelican.ignore_files),
|
||||||
|
'theme': folder_watcher(pelican.theme,
|
||||||
|
[''],
|
||||||
|
pelican.ignore_files),
|
||||||
|
'settings': file_watcher(args.settings)}
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.autoreload:
|
||||||
|
print(' --- AutoReload Mode: Monitoring `content`, `theme` and `settings`'
|
||||||
|
' for changes. ---')
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# Check source dir for changed files ending with the given
|
||||||
|
# extension in the settings. In the theme dir is no such
|
||||||
|
# restriction; all files are recursively checked if they
|
||||||
|
# have changed, no matter what extension the filenames
|
||||||
|
# have.
|
||||||
|
modified = {k: next(v) for k, v in watchers.items()}
|
||||||
|
|
||||||
|
if modified['settings']:
|
||||||
|
pelican = get_instance(args)
|
||||||
|
|
||||||
|
if any(modified.values()):
|
||||||
|
print('\n-> Modified: {}. re-generating...'.format(
|
||||||
|
', '.join(k for k, v in modified.items() if v)))
|
||||||
|
|
||||||
|
if modified['content'] is None:
|
||||||
|
logger.warning('No valid files found in content.')
|
||||||
|
|
||||||
|
if modified['theme'] is None:
|
||||||
|
logger.warning('Empty theme folder. Using `basic` theme.')
|
||||||
|
|
||||||
|
pelican.run()
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.warning("Keyboard interrupt, quitting.")
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if (args.verbosity == logging.DEBUG):
|
||||||
|
logger.critical(e.args)
|
||||||
|
raise
|
||||||
|
logger.warning(
|
||||||
|
'Caught exception "{0}". Reloading.'.format(e))
|
||||||
|
|
||||||
|
finally:
|
||||||
|
time.sleep(.5) # sleep to avoid cpu load
|
||||||
|
|
||||||
|
else:
|
||||||
|
if next(watchers['content']) is None:
|
||||||
|
logger.warning('No valid files found in content.')
|
||||||
|
|
||||||
|
if next(watchers['theme']) is None:
|
||||||
|
logger.warning('Empty theme folder. Using `basic` theme.')
|
||||||
|
|
||||||
|
pelican.run()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# localized systems have errors in native language if locale is set
|
||||||
|
# so convert the message to unicode with the correct encoding
|
||||||
|
msg = str(e)
|
||||||
|
if not six.PY3:
|
||||||
|
msg = msg.decode(locale.getpreferredencoding(False))
|
||||||
|
|
||||||
|
logger.critical(msg)
|
||||||
|
|
||||||
|
if (args.verbosity == logging.DEBUG):
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
sys.exit(getattr(e, 'exitcode', 1))
|
||||||
327
pelican/contents.py
Normal file
327
pelican/contents.py
Normal file
|
|
@ -0,0 +1,327 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
import six
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import locale
|
||||||
|
import logging
|
||||||
|
import functools
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
from pelican import signals
|
||||||
|
from pelican.settings import DEFAULT_CONFIG
|
||||||
|
from pelican.utils import (slugify, truncate_html_words, memoized, strftime,
|
||||||
|
python_2_unicode_compatible, deprecated_attribute,
|
||||||
|
path_to_url)
|
||||||
|
|
||||||
|
# Import these so that they're avalaible when you import from pelican.contents.
|
||||||
|
from pelican.urlwrappers import (URLWrapper, Author, Category, Tag) # NOQA
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Content(object):
|
||||||
|
"""Represents a content.
|
||||||
|
|
||||||
|
:param content: the string to parse, containing the original content.
|
||||||
|
:param metadata: the metadata associated to this page (optional).
|
||||||
|
:param settings: the settings dictionary (optional).
|
||||||
|
:param source_path: The location of the source of this content (if any).
|
||||||
|
:param context: The shared context between generators.
|
||||||
|
|
||||||
|
"""
|
||||||
|
@deprecated_attribute(old='filename', new='source_path', since=(3, 2, 0))
|
||||||
|
def filename():
|
||||||
|
return None
|
||||||
|
|
||||||
|
def __init__(self, content, metadata=None, settings=None,
|
||||||
|
source_path=None, context=None):
|
||||||
|
if metadata is None:
|
||||||
|
metadata = {}
|
||||||
|
if settings is None:
|
||||||
|
settings = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
|
||||||
|
self.settings = settings
|
||||||
|
self._content = content
|
||||||
|
if context is None:
|
||||||
|
context = {}
|
||||||
|
self._context = context
|
||||||
|
self.translations = []
|
||||||
|
|
||||||
|
local_metadata = dict(settings['DEFAULT_METADATA'])
|
||||||
|
local_metadata.update(metadata)
|
||||||
|
|
||||||
|
# set metadata as attributes
|
||||||
|
for key, value in local_metadata.items():
|
||||||
|
if key in ('save_as', 'url'):
|
||||||
|
key = 'override_' + key
|
||||||
|
setattr(self, key.lower(), value)
|
||||||
|
|
||||||
|
# also keep track of the metadata attributes available
|
||||||
|
self.metadata = local_metadata
|
||||||
|
|
||||||
|
#default template if it's not defined in page
|
||||||
|
self.template = self._get_template()
|
||||||
|
|
||||||
|
# First, read the authors from "authors", if not, fallback to "author"
|
||||||
|
# and if not use the settings defined one, if any.
|
||||||
|
if not hasattr(self, 'author') and 'AUTHOR' in settings:
|
||||||
|
self.author = Author(settings['AUTHOR'], settings)
|
||||||
|
|
||||||
|
if not hasattr(self, 'authors') and hasattr(self, 'author'):
|
||||||
|
setattr(self, 'authors', [self.author])
|
||||||
|
|
||||||
|
if hasattr(self, 'authors') and not hasattr(self, 'author'):
|
||||||
|
setattr(self, 'author', self.authors[0])
|
||||||
|
|
||||||
|
# XXX Split all the following code into pieces, there is too much here.
|
||||||
|
|
||||||
|
# manage languages
|
||||||
|
self.in_default_lang = True
|
||||||
|
if 'DEFAULT_LANG' in settings:
|
||||||
|
default_lang = settings['DEFAULT_LANG'].lower()
|
||||||
|
if not hasattr(self, 'lang'):
|
||||||
|
self.lang = default_lang
|
||||||
|
|
||||||
|
self.in_default_lang = (self.lang == default_lang)
|
||||||
|
|
||||||
|
# create the slug if not existing, from the title
|
||||||
|
if not hasattr(self, 'slug') and hasattr(self, 'title'):
|
||||||
|
self.slug = slugify(self.title)
|
||||||
|
|
||||||
|
self.source_path = source_path
|
||||||
|
|
||||||
|
# manage the date format
|
||||||
|
if not hasattr(self, 'date_format'):
|
||||||
|
if hasattr(self, 'lang') and self.lang in settings['DATE_FORMATS']:
|
||||||
|
self.date_format = settings['DATE_FORMATS'][self.lang]
|
||||||
|
else:
|
||||||
|
self.date_format = settings['DEFAULT_DATE_FORMAT']
|
||||||
|
|
||||||
|
if isinstance(self.date_format, tuple):
|
||||||
|
locale_string = self.date_format[0]
|
||||||
|
if sys.version_info < (3, ) and isinstance(locale_string,
|
||||||
|
six.text_type):
|
||||||
|
locale_string = locale_string.encode('ascii')
|
||||||
|
locale.setlocale(locale.LC_ALL, locale_string)
|
||||||
|
self.date_format = self.date_format[1]
|
||||||
|
|
||||||
|
if hasattr(self, 'date'):
|
||||||
|
self.locale_date = strftime(self.date, self.date_format)
|
||||||
|
|
||||||
|
# manage status
|
||||||
|
if not hasattr(self, 'status'):
|
||||||
|
self.status = settings['DEFAULT_STATUS']
|
||||||
|
if not settings['WITH_FUTURE_DATES']:
|
||||||
|
if hasattr(self, 'date') and self.date > datetime.now():
|
||||||
|
self.status = 'draft'
|
||||||
|
|
||||||
|
# store the summary metadata if it is set
|
||||||
|
if 'summary' in metadata:
|
||||||
|
self._summary = metadata['summary']
|
||||||
|
|
||||||
|
signals.content_object_init.send(self)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.source_path is None:
|
||||||
|
return repr(self)
|
||||||
|
elif six.PY3:
|
||||||
|
return self.source_path or repr(self)
|
||||||
|
else:
|
||||||
|
return str(self.source_path.encode('utf-8', 'replace'))
|
||||||
|
|
||||||
|
def check_properties(self):
|
||||||
|
"""Test mandatory properties are set."""
|
||||||
|
for prop in self.mandatory_properties:
|
||||||
|
if not hasattr(self, prop):
|
||||||
|
raise NameError(prop)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url_format(self):
|
||||||
|
"""Returns the URL, formatted with the proper values"""
|
||||||
|
metadata = copy.copy(self.metadata)
|
||||||
|
path = self.metadata.get('path', self.get_relative_source_path())
|
||||||
|
metadata.update({
|
||||||
|
'path': path_to_url(path),
|
||||||
|
'slug': getattr(self, 'slug', ''),
|
||||||
|
'lang': getattr(self, 'lang', 'en'),
|
||||||
|
'date': getattr(self, 'date', datetime.now()),
|
||||||
|
'author': getattr(self, 'author', ''),
|
||||||
|
'category': getattr(self, 'category',
|
||||||
|
self.settings['DEFAULT_CATEGORY']),
|
||||||
|
})
|
||||||
|
return metadata
|
||||||
|
|
||||||
|
def _expand_settings(self, key):
|
||||||
|
fq_key = ('%s_%s' % (self.__class__.__name__, key)).upper()
|
||||||
|
return self.settings[fq_key].format(**self.url_format)
|
||||||
|
|
||||||
|
def get_url_setting(self, key):
|
||||||
|
if hasattr(self, 'override_' + key):
|
||||||
|
return getattr(self, 'override_' + key)
|
||||||
|
key = key if self.in_default_lang else 'lang_%s' % key
|
||||||
|
return self._expand_settings(key)
|
||||||
|
|
||||||
|
def _update_content(self, content, siteurl):
|
||||||
|
"""Update the content attribute.
|
||||||
|
|
||||||
|
Change all the relative paths of the content to relative paths
|
||||||
|
suitable for the ouput content.
|
||||||
|
|
||||||
|
:param content: content resource that will be passed to the templates.
|
||||||
|
:param siteurl: siteurl which is locally generated by the writer in
|
||||||
|
case of RELATIVE_URLS.
|
||||||
|
"""
|
||||||
|
if not content:
|
||||||
|
return content
|
||||||
|
|
||||||
|
hrefs = re.compile(r"""
|
||||||
|
(?P<markup><\s*[^\>]* # match tag with src and href attr
|
||||||
|
(?:href|src)\s*=)
|
||||||
|
|
||||||
|
(?P<quote>["\']) # require value to be quoted
|
||||||
|
(?P<path>\|(?P<what>.*?)\|(?P<value>.*?)) # the url value
|
||||||
|
\2""", re.X)
|
||||||
|
|
||||||
|
def replacer(m):
|
||||||
|
what = m.group('what')
|
||||||
|
value = m.group('value')
|
||||||
|
origin = m.group('path')
|
||||||
|
|
||||||
|
# we support only filename for now. the plan is to support
|
||||||
|
# categories, tags, etc. in the future, but let's keep things
|
||||||
|
# simple for now.
|
||||||
|
|
||||||
|
# XXX Put this in a different location.
|
||||||
|
if what == 'filename':
|
||||||
|
if value.startswith('/'):
|
||||||
|
value = value[1:]
|
||||||
|
else:
|
||||||
|
# relative to the source path of this content
|
||||||
|
value = self.get_relative_source_path(
|
||||||
|
os.path.join(self.relative_dir, value)
|
||||||
|
)
|
||||||
|
|
||||||
|
if value in self._context['filenames']:
|
||||||
|
origin = '/'.join((siteurl,
|
||||||
|
self._context['filenames'][value].url))
|
||||||
|
origin = origin.replace('\\', '/') # Fow windows paths.
|
||||||
|
else:
|
||||||
|
logger.warning("Unable to find {fn}, skipping url"
|
||||||
|
" replacement".format(fn=value))
|
||||||
|
|
||||||
|
return ''.join((m.group('markup'), m.group('quote'), origin,
|
||||||
|
m.group('quote')))
|
||||||
|
|
||||||
|
return hrefs.sub(replacer, content)
|
||||||
|
|
||||||
|
@memoized
|
||||||
|
def get_content(self, siteurl):
|
||||||
|
|
||||||
|
if hasattr(self, '_get_content'):
|
||||||
|
content = self._get_content()
|
||||||
|
else:
|
||||||
|
content = self._content
|
||||||
|
return self._update_content(content, siteurl)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def content(self):
|
||||||
|
return self.get_content(self._context.get('localsiteurl', ''))
|
||||||
|
|
||||||
|
def _get_summary(self):
|
||||||
|
"""Returns the summary of an article.
|
||||||
|
|
||||||
|
This is based on the summary metadata if set, otherwise truncate the
|
||||||
|
content.
|
||||||
|
"""
|
||||||
|
if hasattr(self, '_summary'):
|
||||||
|
return self._summary
|
||||||
|
|
||||||
|
if self.settings['SUMMARY_MAX_LENGTH'] is None:
|
||||||
|
return self.content
|
||||||
|
|
||||||
|
return truncate_html_words(self.content,
|
||||||
|
self.settings['SUMMARY_MAX_LENGTH'])
|
||||||
|
|
||||||
|
def _set_summary(self, summary):
|
||||||
|
"""Dummy function"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
summary = property(_get_summary, _set_summary, "Summary of the article."
|
||||||
|
"Based on the content. Can't be set")
|
||||||
|
url = property(functools.partial(get_url_setting, key='url'))
|
||||||
|
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
|
||||||
|
|
||||||
|
def get_relative_source_path(self, source_path=None):
|
||||||
|
"""Return the relative path (from the content path) to the given
|
||||||
|
source_path.
|
||||||
|
|
||||||
|
If no source path is specified, use the source path of this
|
||||||
|
content object.
|
||||||
|
"""
|
||||||
|
if not source_path:
|
||||||
|
source_path = self.source_path
|
||||||
|
if source_path is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return os.path.relpath(
|
||||||
|
os.path.abspath(os.path.join(self.settings['PATH'], source_path)),
|
||||||
|
os.path.abspath(self.settings['PATH'])
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def relative_dir(self):
|
||||||
|
return os.path.dirname(os.path.relpath(
|
||||||
|
os.path.abspath(self.source_path),
|
||||||
|
os.path.abspath(self.settings['PATH']))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Page(Content):
|
||||||
|
mandatory_properties = ('title',)
|
||||||
|
default_template = 'page'
|
||||||
|
|
||||||
|
|
||||||
|
class Article(Page):
|
||||||
|
mandatory_properties = ('title', 'date', 'category')
|
||||||
|
default_template = 'article'
|
||||||
|
|
||||||
|
|
||||||
|
class Quote(Page):
|
||||||
|
base_properties = ('author', 'date')
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class Static(Page):
|
||||||
|
@deprecated_attribute(old='filepath', new='source_path', since=(3, 2, 0))
|
||||||
|
def filepath():
|
||||||
|
return None
|
||||||
|
|
||||||
|
@deprecated_attribute(old='src', new='source_path', since=(3, 2, 0))
|
||||||
|
def src():
|
||||||
|
return None
|
||||||
|
|
||||||
|
@deprecated_attribute(old='dst', new='save_as', since=(3, 2, 0))
|
||||||
|
def dst():
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid_content(content, f):
|
||||||
|
try:
|
||||||
|
content.check_properties()
|
||||||
|
return True
|
||||||
|
except NameError as e:
|
||||||
|
logger.error("Skipping %s: could not find information about "
|
||||||
|
"'%s'" % (f, e))
|
||||||
|
return False
|
||||||
638
pelican/generators.py
Normal file
638
pelican/generators.py
Normal file
|
|
@ -0,0 +1,638 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
|
||||||
|
import os
|
||||||
|
import math
|
||||||
|
import random
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from codecs import open
|
||||||
|
from collections import defaultdict
|
||||||
|
from functools import partial
|
||||||
|
from itertools import chain, groupby
|
||||||
|
from operator import attrgetter, itemgetter
|
||||||
|
|
||||||
|
from jinja2 import (
|
||||||
|
Environment, FileSystemLoader, PrefixLoader, ChoiceLoader, BaseLoader,
|
||||||
|
TemplateNotFound
|
||||||
|
)
|
||||||
|
|
||||||
|
from pelican.contents import Article, Page, Static, is_valid_content
|
||||||
|
from pelican.readers import read_file
|
||||||
|
from pelican.utils import copy, process_translations, mkdir_p, DateFormatter
|
||||||
|
from pelican import signals
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Generator(object):
|
||||||
|
"""Baseclass generator"""
|
||||||
|
|
||||||
|
def __init__(self, context, settings, path, theme, output_path, markup,
|
||||||
|
**kwargs):
|
||||||
|
self.context = context
|
||||||
|
self.settings = settings
|
||||||
|
self.path = path
|
||||||
|
self.theme = theme
|
||||||
|
self.output_path = output_path
|
||||||
|
self.markup = markup
|
||||||
|
|
||||||
|
for arg, value in kwargs.items():
|
||||||
|
setattr(self, arg, value)
|
||||||
|
|
||||||
|
# templates cache
|
||||||
|
self._templates = {}
|
||||||
|
self._templates_path = []
|
||||||
|
self._templates_path.append(os.path.expanduser(
|
||||||
|
os.path.join(self.theme, 'templates')))
|
||||||
|
self._templates_path += self.settings['EXTRA_TEMPLATES_PATHS']
|
||||||
|
|
||||||
|
theme_path = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
simple_loader = FileSystemLoader(os.path.join(theme_path,
|
||||||
|
"themes", "simple", "templates"))
|
||||||
|
self.env = Environment(
|
||||||
|
trim_blocks=True,
|
||||||
|
loader=ChoiceLoader([
|
||||||
|
FileSystemLoader(self._templates_path),
|
||||||
|
simple_loader, # implicit inheritance
|
||||||
|
PrefixLoader({'!simple': simple_loader}) # explicit one
|
||||||
|
]),
|
||||||
|
extensions=self.settings['JINJA_EXTENSIONS'],
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.debug('template list: {0}'.format(self.env.list_templates()))
|
||||||
|
|
||||||
|
# provide utils.strftime as a jinja filter
|
||||||
|
self.env.filters.update({'strftime': DateFormatter()})
|
||||||
|
|
||||||
|
# get custom Jinja filters from user settings
|
||||||
|
custom_filters = self.settings['JINJA_FILTERS']
|
||||||
|
self.env.filters.update(custom_filters)
|
||||||
|
|
||||||
|
signals.generator_init.send(self)
|
||||||
|
|
||||||
|
def get_template(self, name):
|
||||||
|
"""Return the template by name.
|
||||||
|
Use self.theme to get the templates to use, and return a list of
|
||||||
|
templates ready to use with Jinja2.
|
||||||
|
"""
|
||||||
|
if name not in self._templates:
|
||||||
|
try:
|
||||||
|
self._templates[name] = self.env.get_template(name + '.html')
|
||||||
|
except TemplateNotFound:
|
||||||
|
raise Exception(
|
||||||
|
('[templates] unable to load %s.html from %s'
|
||||||
|
% (name, self._templates_path)))
|
||||||
|
return self._templates[name]
|
||||||
|
|
||||||
|
def _include_path(self, path, extensions=None):
|
||||||
|
"""Inclusion logic for .get_files(), returns True/False
|
||||||
|
|
||||||
|
:param path: the path which might be including
|
||||||
|
:param extensions: the list of allowed extensions (if False, all
|
||||||
|
extensions are allowed)
|
||||||
|
"""
|
||||||
|
if extensions is None:
|
||||||
|
extensions = tuple(self.markup)
|
||||||
|
basename = os.path.basename(path)
|
||||||
|
if extensions is False or basename.endswith(extensions):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_files(self, path, exclude=[], extensions=None):
|
||||||
|
"""Return a list of files to use, based on rules
|
||||||
|
|
||||||
|
:param path: the path to search (relative to self.path)
|
||||||
|
:param exclude: the list of path to exclude
|
||||||
|
:param extensions: the list of allowed extensions (if False, all
|
||||||
|
extensions are allowed)
|
||||||
|
"""
|
||||||
|
files = []
|
||||||
|
root = os.path.join(self.path, path)
|
||||||
|
|
||||||
|
if os.path.isdir(root):
|
||||||
|
for dirpath, dirs, temp_files in os.walk(root, followlinks=True):
|
||||||
|
for e in exclude:
|
||||||
|
if e in dirs:
|
||||||
|
dirs.remove(e)
|
||||||
|
reldir = os.path.relpath(dirpath, self.path)
|
||||||
|
for f in temp_files:
|
||||||
|
fp = os.path.join(reldir, f)
|
||||||
|
if self._include_path(fp, extensions):
|
||||||
|
files.append(fp)
|
||||||
|
elif os.path.exists(root) and self._include_path(path, extensions):
|
||||||
|
files.append(path) # can't walk non-directories
|
||||||
|
return files
|
||||||
|
|
||||||
|
def add_source_path(self, content):
|
||||||
|
location = content.get_relative_source_path()
|
||||||
|
self.context['filenames'][location] = content
|
||||||
|
|
||||||
|
def _update_context(self, items):
|
||||||
|
"""Update the context with the given items from the currrent
|
||||||
|
processor.
|
||||||
|
"""
|
||||||
|
for item in items:
|
||||||
|
value = getattr(self, item)
|
||||||
|
if hasattr(value, 'items'):
|
||||||
|
value = list(value.items()) # py3k safeguard for iterators
|
||||||
|
self.context[item] = value
|
||||||
|
|
||||||
|
|
||||||
|
class _FileLoader(BaseLoader):
|
||||||
|
|
||||||
|
def __init__(self, path, basedir):
|
||||||
|
self.path = path
|
||||||
|
self.fullpath = os.path.join(basedir, path)
|
||||||
|
|
||||||
|
def get_source(self, environment, template):
|
||||||
|
if template != self.path or not os.path.exists(self.fullpath):
|
||||||
|
raise TemplateNotFound(template)
|
||||||
|
mtime = os.path.getmtime(self.fullpath)
|
||||||
|
with open(self.fullpath, 'r', encoding='utf-8') as f:
|
||||||
|
source = f.read()
|
||||||
|
return (source, self.fullpath,
|
||||||
|
lambda: mtime == os.path.getmtime(self.fullpath))
|
||||||
|
|
||||||
|
|
||||||
|
class TemplatePagesGenerator(Generator):
|
||||||
|
|
||||||
|
def generate_output(self, writer):
|
||||||
|
for source, dest in self.settings['TEMPLATE_PAGES'].items():
|
||||||
|
self.env.loader.loaders.insert(0, _FileLoader(source, self.path))
|
||||||
|
try:
|
||||||
|
template = self.env.get_template(source)
|
||||||
|
rurls = self.settings['RELATIVE_URLS']
|
||||||
|
writer.write_file(dest, template, self.context, rurls)
|
||||||
|
finally:
|
||||||
|
del self.env.loader.loaders[0]
|
||||||
|
|
||||||
|
|
||||||
|
class ArticlesGenerator(Generator):
|
||||||
|
"""Generate blog articles"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""initialize properties"""
|
||||||
|
self.articles = [] # only articles in default language
|
||||||
|
self.translations = []
|
||||||
|
self.dates = {}
|
||||||
|
self.tags = defaultdict(list)
|
||||||
|
self.categories = defaultdict(list)
|
||||||
|
self.related_posts = []
|
||||||
|
self.authors = defaultdict(list)
|
||||||
|
self.drafts = []
|
||||||
|
super(ArticlesGenerator, self).__init__(*args, **kwargs)
|
||||||
|
signals.article_generator_init.send(self)
|
||||||
|
|
||||||
|
def generate_feeds(self, writer):
|
||||||
|
"""Generate the feeds from the current context, and output files."""
|
||||||
|
|
||||||
|
if self.settings.get('FEED_ATOM'):
|
||||||
|
writer.write_feed(self.articles, self.context,
|
||||||
|
self.settings['FEED_ATOM'])
|
||||||
|
|
||||||
|
if self.settings.get('FEED_RSS'):
|
||||||
|
writer.write_feed(self.articles, self.context,
|
||||||
|
self.settings['FEED_RSS'], feed_type='rss')
|
||||||
|
|
||||||
|
if (self.settings.get('FEED_ALL_ATOM')
|
||||||
|
or self.settings.get('FEED_ALL_RSS')):
|
||||||
|
all_articles = list(self.articles)
|
||||||
|
for article in self.articles:
|
||||||
|
all_articles.extend(article.translations)
|
||||||
|
all_articles.sort(key=attrgetter('date'), reverse=True)
|
||||||
|
|
||||||
|
if self.settings.get('FEED_ALL_ATOM'):
|
||||||
|
writer.write_feed(all_articles, self.context,
|
||||||
|
self.settings['FEED_ALL_ATOM'])
|
||||||
|
|
||||||
|
if self.settings.get('FEED_ALL_RSS'):
|
||||||
|
writer.write_feed(all_articles, self.context,
|
||||||
|
self.settings['FEED_ALL_RSS'],
|
||||||
|
feed_type='rss')
|
||||||
|
|
||||||
|
for cat, arts in self.categories:
|
||||||
|
arts.sort(key=attrgetter('date'), reverse=True)
|
||||||
|
if self.settings.get('CATEGORY_FEED_ATOM'):
|
||||||
|
writer.write_feed(arts, self.context,
|
||||||
|
self.settings['CATEGORY_FEED_ATOM']
|
||||||
|
% cat.slug)
|
||||||
|
|
||||||
|
if self.settings.get('CATEGORY_FEED_RSS'):
|
||||||
|
writer.write_feed(arts, self.context,
|
||||||
|
self.settings['CATEGORY_FEED_RSS']
|
||||||
|
% cat.slug, feed_type='rss')
|
||||||
|
|
||||||
|
if (self.settings.get('TAG_FEED_ATOM')
|
||||||
|
or self.settings.get('TAG_FEED_RSS')):
|
||||||
|
for tag, arts in self.tags.items():
|
||||||
|
arts.sort(key=attrgetter('date'), reverse=True)
|
||||||
|
if self.settings.get('TAG_FEED_ATOM'):
|
||||||
|
writer.write_feed(arts, self.context,
|
||||||
|
self.settings['TAG_FEED_ATOM']
|
||||||
|
% tag.slug)
|
||||||
|
|
||||||
|
if self.settings.get('TAG_FEED_RSS'):
|
||||||
|
writer.write_feed(arts, self.context,
|
||||||
|
self.settings['TAG_FEED_RSS'] % tag.slug,
|
||||||
|
feed_type='rss')
|
||||||
|
|
||||||
|
if (self.settings.get('TRANSLATION_FEED_ATOM')
|
||||||
|
or self.settings.get('TRANSLATION_FEED_RSS')):
|
||||||
|
translations_feeds = defaultdict(list)
|
||||||
|
for article in chain(self.articles, self.translations):
|
||||||
|
translations_feeds[article.lang].append(article)
|
||||||
|
|
||||||
|
for lang, items in translations_feeds.items():
|
||||||
|
items.sort(key=attrgetter('date'), reverse=True)
|
||||||
|
if self.settings.get('TRANSLATION_FEED_ATOM'):
|
||||||
|
writer.write_feed(items, self.context,
|
||||||
|
self.settings['TRANSLATION_FEED_ATOM'] % lang)
|
||||||
|
if self.settings.get('TRANSLATION_FEED_RSS'):
|
||||||
|
writer.write_feed(items, self.context,
|
||||||
|
self.settings['TRANSLATION_FEED_RSS'] % lang,
|
||||||
|
feed_type='rss')
|
||||||
|
|
||||||
|
def generate_articles(self, write):
|
||||||
|
"""Generate the articles."""
|
||||||
|
for article in chain(self.translations, self.articles):
|
||||||
|
write(article.save_as, self.get_template(article.template),
|
||||||
|
self.context, article=article, category=article.category)
|
||||||
|
|
||||||
|
def generate_period_archives(self, write):
|
||||||
|
"""Generate per-year, per-month, and per-day archives."""
|
||||||
|
try:
|
||||||
|
template = self.get_template('period_archives')
|
||||||
|
except Exception:
|
||||||
|
template = self.get_template('archives')
|
||||||
|
|
||||||
|
def _generate_period_archives(dates, key, save_as_fmt):
|
||||||
|
"""Generate period archives from `dates`, grouped by
|
||||||
|
`key` and written to `save_as`.
|
||||||
|
"""
|
||||||
|
# `dates` is already sorted by date
|
||||||
|
for _period, group in groupby(dates, key=key):
|
||||||
|
archive = list(group)
|
||||||
|
# arbitrarily grab the first date so that the usual
|
||||||
|
# format string syntax can be used for specifying the
|
||||||
|
# period archive dates
|
||||||
|
date = archive[0].date
|
||||||
|
save_as = save_as_fmt.format(date=date)
|
||||||
|
write(save_as, template, self.context,
|
||||||
|
dates=archive, blog=True)
|
||||||
|
|
||||||
|
period_save_as = {
|
||||||
|
'year': self.settings['YEAR_ARCHIVE_SAVE_AS'],
|
||||||
|
'month': self.settings['MONTH_ARCHIVE_SAVE_AS'],
|
||||||
|
'day': self.settings['DAY_ARCHIVE_SAVE_AS'],
|
||||||
|
}
|
||||||
|
|
||||||
|
period_date_key = {
|
||||||
|
'year': attrgetter('date.year'),
|
||||||
|
'month': attrgetter('date.year', 'date.month'),
|
||||||
|
'day': attrgetter('date.year', 'date.month', 'date.day')
|
||||||
|
}
|
||||||
|
|
||||||
|
for period in 'year', 'month', 'day':
|
||||||
|
save_as = period_save_as[period]
|
||||||
|
if save_as:
|
||||||
|
key = period_date_key[period]
|
||||||
|
_generate_period_archives(self.dates, key, save_as)
|
||||||
|
|
||||||
|
def generate_direct_templates(self, write):
|
||||||
|
"""Generate direct templates pages"""
|
||||||
|
PAGINATED_TEMPLATES = self.settings['PAGINATED_DIRECT_TEMPLATES']
|
||||||
|
for template in self.settings['DIRECT_TEMPLATES']:
|
||||||
|
paginated = {}
|
||||||
|
if template in PAGINATED_TEMPLATES:
|
||||||
|
paginated = {'articles': self.articles, 'dates': self.dates}
|
||||||
|
save_as = self.settings.get("%s_SAVE_AS" % template.upper(),
|
||||||
|
'%s.html' % template)
|
||||||
|
if not save_as:
|
||||||
|
continue
|
||||||
|
|
||||||
|
write(save_as, self.get_template(template),
|
||||||
|
self.context, blog=True, paginated=paginated,
|
||||||
|
page_name=os.path.splitext(save_as)[0])
|
||||||
|
|
||||||
|
def generate_tags(self, write):
|
||||||
|
"""Generate Tags pages."""
|
||||||
|
tag_template = self.get_template('tag')
|
||||||
|
for tag, articles in self.tags.items():
|
||||||
|
articles.sort(key=attrgetter('date'), reverse=True)
|
||||||
|
dates = [article for article in self.dates if article in articles]
|
||||||
|
write(tag.save_as, tag_template, self.context, tag=tag,
|
||||||
|
articles=articles, dates=dates,
|
||||||
|
paginated={'articles': articles, 'dates': dates},
|
||||||
|
page_name=tag.page_name, all_articles=self.articles)
|
||||||
|
|
||||||
|
def generate_categories(self, write):
|
||||||
|
"""Generate category pages."""
|
||||||
|
category_template = self.get_template('category')
|
||||||
|
for cat, articles in self.categories:
|
||||||
|
dates = [article for article in self.dates if article in articles]
|
||||||
|
write(cat.save_as, category_template, self.context,
|
||||||
|
category=cat, articles=articles, dates=dates,
|
||||||
|
paginated={'articles': articles, 'dates': dates},
|
||||||
|
page_name=cat.page_name, all_articles=self.articles)
|
||||||
|
|
||||||
|
def generate_authors(self, write):
|
||||||
|
"""Generate Author pages."""
|
||||||
|
author_template = self.get_template('author')
|
||||||
|
for aut, articles in self.authors:
|
||||||
|
dates = [article for article in self.dates if article in articles]
|
||||||
|
write(aut.save_as, author_template, self.context,
|
||||||
|
author=aut, articles=articles, dates=dates,
|
||||||
|
paginated={'articles': articles, 'dates': dates},
|
||||||
|
page_name=aut.page_name, all_articles=self.articles)
|
||||||
|
|
||||||
|
def generate_drafts(self, write):
|
||||||
|
"""Generate drafts pages."""
|
||||||
|
for article in self.drafts:
|
||||||
|
write(os.path.join('drafts', '%s.html' % article.slug),
|
||||||
|
self.get_template(article.template), self.context,
|
||||||
|
article=article, category=article.category,
|
||||||
|
all_articles=self.articles)
|
||||||
|
|
||||||
|
def generate_pages(self, writer):
|
||||||
|
"""Generate the pages on the disk"""
|
||||||
|
write = partial(writer.write_file,
|
||||||
|
relative_urls=self.settings['RELATIVE_URLS'])
|
||||||
|
|
||||||
|
# to minimize the number of relative path stuff modification
|
||||||
|
# in writer, articles pass first
|
||||||
|
self.generate_articles(write)
|
||||||
|
self.generate_period_archives(write)
|
||||||
|
self.generate_direct_templates(write)
|
||||||
|
|
||||||
|
# and subfolders after that
|
||||||
|
self.generate_tags(write)
|
||||||
|
self.generate_categories(write)
|
||||||
|
self.generate_authors(write)
|
||||||
|
self.generate_drafts(write)
|
||||||
|
|
||||||
|
def generate_context(self):
|
||||||
|
"""Add the articles into the shared context"""
|
||||||
|
|
||||||
|
all_articles = []
|
||||||
|
for f in self.get_files(
|
||||||
|
self.settings['ARTICLE_DIR'],
|
||||||
|
exclude=self.settings['ARTICLE_EXCLUDES']):
|
||||||
|
try:
|
||||||
|
article = read_file(
|
||||||
|
base_path=self.path, path=f, content_class=Article,
|
||||||
|
settings=self.settings, context=self.context,
|
||||||
|
preread_signal=signals.article_generator_preread,
|
||||||
|
preread_sender=self,
|
||||||
|
context_signal=signals.article_generator_context,
|
||||||
|
context_sender=self)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning('Could not process {}\n{}'.format(f, e))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not is_valid_content(article, f):
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.add_source_path(article)
|
||||||
|
|
||||||
|
if article.status == "published":
|
||||||
|
all_articles.append(article)
|
||||||
|
elif article.status == "draft":
|
||||||
|
self.drafts.append(article)
|
||||||
|
else:
|
||||||
|
logger.warning("Unknown status %s for file %s, skipping it." %
|
||||||
|
(repr(article.status),
|
||||||
|
repr(f)))
|
||||||
|
|
||||||
|
self.articles, self.translations = process_translations(all_articles)
|
||||||
|
|
||||||
|
for article in self.articles:
|
||||||
|
# only main articles are listed in categories and tags
|
||||||
|
# not translations
|
||||||
|
self.categories[article.category].append(article)
|
||||||
|
if hasattr(article, 'tags'):
|
||||||
|
for tag in article.tags:
|
||||||
|
self.tags[tag].append(article)
|
||||||
|
# ignore blank authors as well as undefined
|
||||||
|
if hasattr(article, 'authors'):
|
||||||
|
for author in article.authors:
|
||||||
|
if author.name != '':
|
||||||
|
self.authors[author].append(article)
|
||||||
|
|
||||||
|
# sort the articles by date
|
||||||
|
self.articles.sort(key=attrgetter('date'), reverse=True)
|
||||||
|
self.dates = list(self.articles)
|
||||||
|
self.dates.sort(key=attrgetter('date'),
|
||||||
|
reverse=self.context['NEWEST_FIRST_ARCHIVES'])
|
||||||
|
|
||||||
|
# create tag cloud
|
||||||
|
tag_cloud = defaultdict(int)
|
||||||
|
for article in self.articles:
|
||||||
|
for tag in getattr(article, 'tags', []):
|
||||||
|
tag_cloud[tag] += 1
|
||||||
|
|
||||||
|
tag_cloud = sorted(tag_cloud.items(), key=itemgetter(1), reverse=True)
|
||||||
|
tag_cloud = tag_cloud[:self.settings.get('TAG_CLOUD_MAX_ITEMS')]
|
||||||
|
|
||||||
|
tags = list(map(itemgetter(1), tag_cloud))
|
||||||
|
if tags:
|
||||||
|
max_count = max(tags)
|
||||||
|
steps = self.settings.get('TAG_CLOUD_STEPS')
|
||||||
|
|
||||||
|
# calculate word sizes
|
||||||
|
self.tag_cloud = [
|
||||||
|
(
|
||||||
|
tag,
|
||||||
|
int(math.floor(steps - (steps - 1) * math.log(count)
|
||||||
|
/ (math.log(max_count)or 1)))
|
||||||
|
)
|
||||||
|
for tag, count in tag_cloud
|
||||||
|
]
|
||||||
|
# put words in chaos
|
||||||
|
random.shuffle(self.tag_cloud)
|
||||||
|
|
||||||
|
# and generate the output :)
|
||||||
|
|
||||||
|
# order the categories per name
|
||||||
|
self.categories = list(self.categories.items())
|
||||||
|
self.categories.sort(
|
||||||
|
reverse=self.settings['REVERSE_CATEGORY_ORDER'])
|
||||||
|
|
||||||
|
self.authors = list(self.authors.items())
|
||||||
|
self.authors.sort()
|
||||||
|
|
||||||
|
self._update_context(('articles', 'dates', 'tags', 'categories',
|
||||||
|
'tag_cloud', 'authors', 'related_posts'))
|
||||||
|
|
||||||
|
signals.article_generator_finalized.send(self)
|
||||||
|
|
||||||
|
def generate_output(self, writer):
|
||||||
|
self.generate_feeds(writer)
|
||||||
|
self.generate_pages(writer)
|
||||||
|
|
||||||
|
|
||||||
|
class PagesGenerator(Generator):
|
||||||
|
"""Generate pages"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.pages = []
|
||||||
|
self.hidden_pages = []
|
||||||
|
self.hidden_translations = []
|
||||||
|
super(PagesGenerator, self).__init__(*args, **kwargs)
|
||||||
|
signals.page_generator_init.send(self)
|
||||||
|
|
||||||
|
def generate_context(self):
|
||||||
|
all_pages = []
|
||||||
|
hidden_pages = []
|
||||||
|
for f in self.get_files(
|
||||||
|
self.settings['PAGE_DIR'],
|
||||||
|
exclude=self.settings['PAGE_EXCLUDES']):
|
||||||
|
try:
|
||||||
|
page = read_file(
|
||||||
|
base_path=self.path, path=f, content_class=Page,
|
||||||
|
settings=self.settings, context=self.context,
|
||||||
|
preread_signal=signals.page_generator_preread,
|
||||||
|
preread_sender=self,
|
||||||
|
context_signal=signals.page_generator_context,
|
||||||
|
context_sender=self)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning('Could not process {}\n{}'.format(f, e))
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not is_valid_content(page, f):
|
||||||
|
continue
|
||||||
|
|
||||||
|
self.add_source_path(page)
|
||||||
|
|
||||||
|
if page.status == "published":
|
||||||
|
all_pages.append(page)
|
||||||
|
elif page.status == "hidden":
|
||||||
|
hidden_pages.append(page)
|
||||||
|
else:
|
||||||
|
logger.warning("Unknown status %s for file %s, skipping it." %
|
||||||
|
(repr(page.status),
|
||||||
|
repr(f)))
|
||||||
|
|
||||||
|
self.pages, self.translations = process_translations(all_pages)
|
||||||
|
self.hidden_pages, self.hidden_translations = (
|
||||||
|
process_translations(hidden_pages))
|
||||||
|
|
||||||
|
self._update_context(('pages', ))
|
||||||
|
self.context['PAGES'] = self.pages
|
||||||
|
|
||||||
|
signals.page_generator_finalized.send(self)
|
||||||
|
|
||||||
|
def generate_output(self, writer):
|
||||||
|
for page in chain(self.translations, self.pages,
|
||||||
|
self.hidden_translations, self.hidden_pages):
|
||||||
|
writer.write_file(page.save_as, self.get_template(page.template),
|
||||||
|
self.context, page=page,
|
||||||
|
relative_urls=self.settings['RELATIVE_URLS'])
|
||||||
|
|
||||||
|
|
||||||
|
class StaticGenerator(Generator):
|
||||||
|
"""copy static paths (what you want to copy, like images, medias etc.
|
||||||
|
to output"""
|
||||||
|
|
||||||
|
def _copy_paths(self, paths, source, destination, output_path,
|
||||||
|
final_path=None):
|
||||||
|
"""Copy all the paths from source to destination"""
|
||||||
|
for path in paths:
|
||||||
|
copy(path, source, os.path.join(output_path, destination),
|
||||||
|
final_path, overwrite=True)
|
||||||
|
|
||||||
|
def generate_context(self):
|
||||||
|
self.staticfiles = []
|
||||||
|
|
||||||
|
# walk static paths
|
||||||
|
for static_path in self.settings['STATIC_PATHS']:
|
||||||
|
for f in self.get_files(
|
||||||
|
static_path, extensions=False):
|
||||||
|
static = read_file(
|
||||||
|
base_path=self.path, path=f, content_class=Static,
|
||||||
|
fmt='static',
|
||||||
|
settings=self.settings, context=self.context,
|
||||||
|
preread_signal=signals.static_generator_preread,
|
||||||
|
preread_sender=self,
|
||||||
|
context_signal=signals.static_generator_context,
|
||||||
|
context_sender=self)
|
||||||
|
self.staticfiles.append(static)
|
||||||
|
self.add_source_path(static)
|
||||||
|
|
||||||
|
def generate_output(self, writer):
|
||||||
|
self._copy_paths(self.settings['THEME_STATIC_PATHS'], self.theme,
|
||||||
|
'theme', self.output_path, os.curdir)
|
||||||
|
# copy all Static files
|
||||||
|
for sc in self.staticfiles:
|
||||||
|
source_path = os.path.join(self.path, sc.source_path)
|
||||||
|
save_as = os.path.join(self.output_path, sc.save_as)
|
||||||
|
mkdir_p(os.path.dirname(save_as))
|
||||||
|
shutil.copy(source_path, save_as)
|
||||||
|
logger.info('copying {} to {}'.format(sc.source_path, sc.save_as))
|
||||||
|
|
||||||
|
|
||||||
|
class PdfGenerator(Generator):
|
||||||
|
"""Generate PDFs on the output dir, for all articles and pages coming from
|
||||||
|
rst"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(PdfGenerator, self).__init__(*args, **kwargs)
|
||||||
|
try:
|
||||||
|
from rst2pdf.createpdf import RstToPdf
|
||||||
|
pdf_style_path = os.path.join(self.settings['PDF_STYLE_PATH'])
|
||||||
|
pdf_style = self.settings['PDF_STYLE']
|
||||||
|
self.pdfcreator = RstToPdf(breakside=0,
|
||||||
|
stylesheets=[pdf_style],
|
||||||
|
style_path=[pdf_style_path])
|
||||||
|
except ImportError:
|
||||||
|
raise Exception("unable to find rst2pdf")
|
||||||
|
|
||||||
|
def _create_pdf(self, obj, output_path):
|
||||||
|
if obj.source_path.endswith('.rst'):
|
||||||
|
filename = obj.slug + ".pdf"
|
||||||
|
output_pdf = os.path.join(output_path, filename)
|
||||||
|
# print('Generating pdf for', obj.source_path, 'in', output_pdf)
|
||||||
|
with open(obj.source_path) as f:
|
||||||
|
self.pdfcreator.createPdf(text=f.read(), output=output_pdf)
|
||||||
|
logger.info(' [ok] writing %s' % output_pdf)
|
||||||
|
|
||||||
|
def generate_context(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def generate_output(self, writer=None):
|
||||||
|
# we don't use the writer passed as argument here
|
||||||
|
# since we write our own files
|
||||||
|
logger.info(' Generating PDF files...')
|
||||||
|
pdf_path = os.path.join(self.output_path, 'pdf')
|
||||||
|
if not os.path.exists(pdf_path):
|
||||||
|
try:
|
||||||
|
os.mkdir(pdf_path)
|
||||||
|
except OSError:
|
||||||
|
logger.error("Couldn't create the pdf output folder in " +
|
||||||
|
pdf_path)
|
||||||
|
|
||||||
|
for article in self.context['articles']:
|
||||||
|
self._create_pdf(article, pdf_path)
|
||||||
|
|
||||||
|
for page in self.context['pages']:
|
||||||
|
self._create_pdf(page, pdf_path)
|
||||||
|
|
||||||
|
|
||||||
|
class SourceFileGenerator(Generator):
|
||||||
|
def generate_context(self):
|
||||||
|
self.output_extension = self.settings['OUTPUT_SOURCES_EXTENSION']
|
||||||
|
|
||||||
|
def _create_source(self, obj):
|
||||||
|
output_path, _ = os.path.splitext(obj.save_as)
|
||||||
|
dest = os.path.join(self.output_path,
|
||||||
|
output_path + self.output_extension)
|
||||||
|
copy('', obj.source_path, dest)
|
||||||
|
|
||||||
|
def generate_output(self, writer=None):
|
||||||
|
logger.info(' Generating source files...')
|
||||||
|
for obj in chain(self.context['articles'], self.context['pages']):
|
||||||
|
self._create_source(obj)
|
||||||
|
for obj_trans in obj.translations:
|
||||||
|
self._create_source(obj_trans)
|
||||||
89
pelican/log.py
Normal file
89
pelican/log.py
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'init'
|
||||||
|
]
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from logging import Formatter, getLogger, StreamHandler, DEBUG
|
||||||
|
|
||||||
|
|
||||||
|
RESET_TERM = '\033[0;m'
|
||||||
|
|
||||||
|
COLOR_CODES = {
|
||||||
|
'red': 31,
|
||||||
|
'yellow': 33,
|
||||||
|
'cyan': 36,
|
||||||
|
'white': 37,
|
||||||
|
'bgred': 41,
|
||||||
|
'bggrey': 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def ansi(color, text):
|
||||||
|
"""Wrap text in an ansi escape sequence"""
|
||||||
|
code = COLOR_CODES[color]
|
||||||
|
return '\033[1;{0}m{1}{2}'.format(code, text, RESET_TERM)
|
||||||
|
|
||||||
|
|
||||||
|
class ANSIFormatter(Formatter):
|
||||||
|
"""Convert a `logging.LogRecord' object into colored text, using ANSI
|
||||||
|
escape sequences.
|
||||||
|
|
||||||
|
"""
|
||||||
|
def format(self, record):
|
||||||
|
msg = record.getMessage()
|
||||||
|
if record.levelname == 'INFO':
|
||||||
|
return ansi('cyan', '-> ') + msg
|
||||||
|
elif record.levelname == 'WARNING':
|
||||||
|
return ansi('yellow', record.levelname) + ': ' + msg
|
||||||
|
elif record.levelname == 'ERROR':
|
||||||
|
return ansi('red', record.levelname) + ': ' + msg
|
||||||
|
elif record.levelname == 'CRITICAL':
|
||||||
|
return ansi('bgred', record.levelname) + ': ' + msg
|
||||||
|
elif record.levelname == 'DEBUG':
|
||||||
|
return ansi('bggrey', record.levelname) + ': ' + msg
|
||||||
|
else:
|
||||||
|
return ansi('white', record.levelname) + ': ' + msg
|
||||||
|
|
||||||
|
|
||||||
|
class TextFormatter(Formatter):
|
||||||
|
"""
|
||||||
|
Convert a `logging.LogRecord' object into text.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def format(self, record):
|
||||||
|
if not record.levelname or record.levelname == 'INFO':
|
||||||
|
return record.getMessage()
|
||||||
|
else:
|
||||||
|
return record.levelname + ': ' + record.getMessage()
|
||||||
|
|
||||||
|
|
||||||
|
def init(level=None, logger=getLogger(), handler=StreamHandler()):
|
||||||
|
logger = logging.getLogger()
|
||||||
|
|
||||||
|
if (os.isatty(sys.stdout.fileno())
|
||||||
|
and not sys.platform.startswith('win')):
|
||||||
|
fmt = ANSIFormatter()
|
||||||
|
else:
|
||||||
|
fmt = TextFormatter()
|
||||||
|
handler.setFormatter(fmt)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
if level:
|
||||||
|
logger.setLevel(level)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
init(level=DEBUG)
|
||||||
|
|
||||||
|
root_logger = logging.getLogger()
|
||||||
|
root_logger.debug('debug')
|
||||||
|
root_logger.info('info')
|
||||||
|
root_logger.warning('warning')
|
||||||
|
root_logger.error('error')
|
||||||
|
root_logger.critical('critical')
|
||||||
89
pelican/paginator.py
Normal file
89
pelican/paginator.py
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
|
||||||
|
# From django.core.paginator
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
|
|
||||||
|
class Paginator(object):
|
||||||
|
def __init__(self, object_list, per_page, orphans=0):
|
||||||
|
self.object_list = object_list
|
||||||
|
self.per_page = per_page
|
||||||
|
self.orphans = orphans
|
||||||
|
self._num_pages = self._count = None
|
||||||
|
|
||||||
|
def page(self, number):
|
||||||
|
"Returns a Page object for the given 1-based page number."
|
||||||
|
bottom = (number - 1) * self.per_page
|
||||||
|
top = bottom + self.per_page
|
||||||
|
if top + self.orphans >= self.count:
|
||||||
|
top = self.count
|
||||||
|
return Page(self.object_list[bottom:top], number, self)
|
||||||
|
|
||||||
|
def _get_count(self):
|
||||||
|
"Returns the total number of objects, across all pages."
|
||||||
|
if self._count is None:
|
||||||
|
self._count = len(self.object_list)
|
||||||
|
return self._count
|
||||||
|
count = property(_get_count)
|
||||||
|
|
||||||
|
def _get_num_pages(self):
|
||||||
|
"Returns the total number of pages."
|
||||||
|
if self._num_pages is None:
|
||||||
|
hits = max(1, self.count - self.orphans)
|
||||||
|
self._num_pages = int(ceil(hits / (float(self.per_page) or 1)))
|
||||||
|
return self._num_pages
|
||||||
|
num_pages = property(_get_num_pages)
|
||||||
|
|
||||||
|
def _get_page_range(self):
|
||||||
|
"""
|
||||||
|
Returns a 1-based range of pages for iterating through within
|
||||||
|
a template for loop.
|
||||||
|
"""
|
||||||
|
return list(range(1, self.num_pages + 1))
|
||||||
|
page_range = property(_get_page_range)
|
||||||
|
|
||||||
|
|
||||||
|
class Page(object):
|
||||||
|
def __init__(self, object_list, number, paginator):
|
||||||
|
self.object_list = object_list
|
||||||
|
self.number = number
|
||||||
|
self.paginator = paginator
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Page %s of %s>' % (self.number, self.paginator.num_pages)
|
||||||
|
|
||||||
|
def has_next(self):
|
||||||
|
return self.number < self.paginator.num_pages
|
||||||
|
|
||||||
|
def has_previous(self):
|
||||||
|
return self.number > 1
|
||||||
|
|
||||||
|
def has_other_pages(self):
|
||||||
|
return self.has_previous() or self.has_next()
|
||||||
|
|
||||||
|
def next_page_number(self):
|
||||||
|
return self.number + 1
|
||||||
|
|
||||||
|
def previous_page_number(self):
|
||||||
|
return self.number - 1
|
||||||
|
|
||||||
|
def start_index(self):
|
||||||
|
"""
|
||||||
|
Returns the 1-based index of the first object on this page,
|
||||||
|
relative to total objects in the paginator.
|
||||||
|
"""
|
||||||
|
# Special case, return zero if no items.
|
||||||
|
if self.paginator.count == 0:
|
||||||
|
return 0
|
||||||
|
return (self.paginator.per_page * (self.number - 1)) + 1
|
||||||
|
|
||||||
|
def end_index(self):
|
||||||
|
"""
|
||||||
|
Returns the 1-based index of the last object on this page,
|
||||||
|
relative to total objects found (hits).
|
||||||
|
"""
|
||||||
|
# Special case for the last page because there can be orphans.
|
||||||
|
if self.number == self.paginator.num_pages:
|
||||||
|
return self.paginator.count
|
||||||
|
return self.number * self.paginator.per_page
|
||||||
470
pelican/readers.py
Normal file
470
pelican/readers.py
Normal file
|
|
@ -0,0 +1,470 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
try:
|
||||||
|
import docutils
|
||||||
|
import docutils.core
|
||||||
|
import docutils.io
|
||||||
|
from docutils.writers.html4css1 import HTMLTranslator
|
||||||
|
|
||||||
|
# import the directives to have pygments support
|
||||||
|
from pelican import rstdirectives # NOQA
|
||||||
|
except ImportError:
|
||||||
|
core = False
|
||||||
|
try:
|
||||||
|
from markdown import Markdown
|
||||||
|
except ImportError:
|
||||||
|
Markdown = False # NOQA
|
||||||
|
try:
|
||||||
|
from asciidocapi import AsciiDocAPI
|
||||||
|
asciidoc = True
|
||||||
|
except ImportError:
|
||||||
|
asciidoc = False
|
||||||
|
try:
|
||||||
|
from html import escape
|
||||||
|
except ImportError:
|
||||||
|
from cgi import escape # NOQA
|
||||||
|
try:
|
||||||
|
from html.parser import HTMLParser
|
||||||
|
except ImportError:
|
||||||
|
from HTMLParser import HTMLParser
|
||||||
|
|
||||||
|
from pelican.contents import Page, Category, Tag, Author
|
||||||
|
from pelican.utils import get_date, pelican_open
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
METADATA_PROCESSORS = {
|
||||||
|
'tags': lambda x, y: [Tag(tag, y) for tag in x.split(',')],
|
||||||
|
'date': lambda x, y: get_date(x),
|
||||||
|
'status': lambda x, y: x.strip(),
|
||||||
|
'category': Category,
|
||||||
|
'author': Author,
|
||||||
|
'authors': lambda x, y: [Author(name, y) for name in x.split(',')],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Reader(object):
|
||||||
|
enabled = True
|
||||||
|
file_extensions = ['static']
|
||||||
|
extensions = None
|
||||||
|
|
||||||
|
def __init__(self, settings):
|
||||||
|
self.settings = settings
|
||||||
|
|
||||||
|
def process_metadata(self, name, value):
|
||||||
|
if name in METADATA_PROCESSORS:
|
||||||
|
return METADATA_PROCESSORS[name](value, self.settings)
|
||||||
|
return value
|
||||||
|
|
||||||
|
def read(self, source_path):
|
||||||
|
"No-op parser"
|
||||||
|
content = None
|
||||||
|
metadata = {}
|
||||||
|
return content, metadata
|
||||||
|
|
||||||
|
|
||||||
|
class _FieldBodyTranslator(HTMLTranslator):
|
||||||
|
|
||||||
|
def __init__(self, document):
|
||||||
|
HTMLTranslator.__init__(self, document)
|
||||||
|
self.compact_p = None
|
||||||
|
|
||||||
|
def astext(self):
|
||||||
|
return ''.join(self.body)
|
||||||
|
|
||||||
|
def visit_field_body(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def depart_field_body(self, node):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def render_node_to_html(document, node):
|
||||||
|
visitor = _FieldBodyTranslator(document)
|
||||||
|
node.walkabout(visitor)
|
||||||
|
return visitor.astext()
|
||||||
|
|
||||||
|
|
||||||
|
class PelicanHTMLTranslator(HTMLTranslator):
|
||||||
|
|
||||||
|
def visit_abbreviation(self, node):
|
||||||
|
attrs = {}
|
||||||
|
if node.hasattr('explanation'):
|
||||||
|
attrs['title'] = node['explanation']
|
||||||
|
self.body.append(self.starttag(node, 'abbr', '', **attrs))
|
||||||
|
|
||||||
|
def depart_abbreviation(self, node):
|
||||||
|
self.body.append('</abbr>')
|
||||||
|
|
||||||
|
|
||||||
|
class RstReader(Reader):
|
||||||
|
enabled = bool(docutils)
|
||||||
|
file_extensions = ['rst']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(RstReader, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _parse_metadata(self, document):
|
||||||
|
"""Return the dict containing document metadata"""
|
||||||
|
output = {}
|
||||||
|
for docinfo in document.traverse(docutils.nodes.docinfo):
|
||||||
|
for element in docinfo.children:
|
||||||
|
if element.tagname == 'field': # custom fields (e.g. summary)
|
||||||
|
name_elem, body_elem = element.children
|
||||||
|
name = name_elem.astext()
|
||||||
|
if name == 'summary':
|
||||||
|
value = render_node_to_html(document, body_elem)
|
||||||
|
else:
|
||||||
|
value = body_elem.astext()
|
||||||
|
else: # standard fields (e.g. address)
|
||||||
|
name = element.tagname
|
||||||
|
value = element.astext()
|
||||||
|
name = name.lower()
|
||||||
|
|
||||||
|
output[name] = self.process_metadata(name, value)
|
||||||
|
return output
|
||||||
|
|
||||||
|
def _get_publisher(self, source_path):
|
||||||
|
extra_params = {'initial_header_level': '2',
|
||||||
|
'syntax_highlight': 'short',
|
||||||
|
'input_encoding': 'utf-8'}
|
||||||
|
user_params = self.settings.get('DOCUTILS_SETTINGS')
|
||||||
|
if user_params:
|
||||||
|
extra_params.update(user_params)
|
||||||
|
|
||||||
|
pub = docutils.core.Publisher(
|
||||||
|
destination_class=docutils.io.StringOutput)
|
||||||
|
pub.set_components('standalone', 'restructuredtext', 'html')
|
||||||
|
pub.writer.translator_class = PelicanHTMLTranslator
|
||||||
|
pub.process_programmatic_settings(None, extra_params, None)
|
||||||
|
pub.set_source(source_path=source_path)
|
||||||
|
pub.publish()
|
||||||
|
return pub
|
||||||
|
|
||||||
|
def read(self, source_path):
|
||||||
|
"""Parses restructured text"""
|
||||||
|
pub = self._get_publisher(source_path)
|
||||||
|
parts = pub.writer.parts
|
||||||
|
content = parts.get('body')
|
||||||
|
|
||||||
|
metadata = self._parse_metadata(pub.document)
|
||||||
|
metadata.setdefault('title', parts.get('title'))
|
||||||
|
|
||||||
|
return content, metadata
|
||||||
|
|
||||||
|
|
||||||
|
class MarkdownReader(Reader):
|
||||||
|
enabled = bool(Markdown)
|
||||||
|
file_extensions = ['md', 'markdown', 'mkd', 'mdown']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(MarkdownReader, self).__init__(*args, **kwargs)
|
||||||
|
self.extensions = self.settings['MD_EXTENSIONS']
|
||||||
|
self.extensions.append('meta')
|
||||||
|
self._md = Markdown(extensions=self.extensions)
|
||||||
|
|
||||||
|
def _parse_metadata(self, meta):
|
||||||
|
"""Return the dict containing document metadata"""
|
||||||
|
output = {}
|
||||||
|
for name, value in meta.items():
|
||||||
|
name = name.lower()
|
||||||
|
if name == "summary":
|
||||||
|
summary_values = "\n".join(value)
|
||||||
|
# reset the markdown instance to clear any state
|
||||||
|
self._md.reset()
|
||||||
|
summary = self._md.convert(summary_values)
|
||||||
|
output[name] = self.process_metadata(name, summary)
|
||||||
|
else:
|
||||||
|
output[name] = self.process_metadata(name, value[0])
|
||||||
|
return output
|
||||||
|
|
||||||
|
def read(self, source_path):
|
||||||
|
"""Parse content and metadata of markdown files"""
|
||||||
|
|
||||||
|
with pelican_open(source_path) as text:
|
||||||
|
content = self._md.convert(text)
|
||||||
|
|
||||||
|
metadata = self._parse_metadata(self._md.Meta)
|
||||||
|
return content, metadata
|
||||||
|
|
||||||
|
|
||||||
|
class HTMLReader(Reader):
|
||||||
|
"""Parses HTML files as input, looking for meta, title, and body tags"""
|
||||||
|
file_extensions = ['htm', 'html']
|
||||||
|
enabled = True
|
||||||
|
|
||||||
|
class _HTMLParser(HTMLParser):
|
||||||
|
def __init__(self, settings):
|
||||||
|
HTMLParser.__init__(self)
|
||||||
|
self.body = ''
|
||||||
|
self.metadata = {}
|
||||||
|
self.settings = settings
|
||||||
|
|
||||||
|
self._data_buffer = ''
|
||||||
|
|
||||||
|
self._in_top_level = True
|
||||||
|
self._in_head = False
|
||||||
|
self._in_title = False
|
||||||
|
self._in_body = False
|
||||||
|
self._in_tags = False
|
||||||
|
|
||||||
|
def handle_starttag(self, tag, attrs):
|
||||||
|
if tag == 'head' and self._in_top_level:
|
||||||
|
self._in_top_level = False
|
||||||
|
self._in_head = True
|
||||||
|
elif tag == 'title' and self._in_head:
|
||||||
|
self._in_title = True
|
||||||
|
self._data_buffer = ''
|
||||||
|
elif tag == 'body' and self._in_top_level:
|
||||||
|
self._in_top_level = False
|
||||||
|
self._in_body = True
|
||||||
|
self._data_buffer = ''
|
||||||
|
elif tag == 'meta' and self._in_head:
|
||||||
|
self._handle_meta_tag(attrs)
|
||||||
|
|
||||||
|
elif self._in_body:
|
||||||
|
self._data_buffer += self.build_tag(tag, attrs, False)
|
||||||
|
|
||||||
|
def handle_endtag(self, tag):
|
||||||
|
if tag == 'head':
|
||||||
|
if self._in_head:
|
||||||
|
self._in_head = False
|
||||||
|
self._in_top_level = True
|
||||||
|
elif tag == 'title':
|
||||||
|
self._in_title = False
|
||||||
|
self.metadata['title'] = self._data_buffer
|
||||||
|
elif tag == 'body':
|
||||||
|
self.body = self._data_buffer
|
||||||
|
self._in_body = False
|
||||||
|
self._in_top_level = True
|
||||||
|
elif self._in_body:
|
||||||
|
self._data_buffer += '</{}>'.format(escape(tag))
|
||||||
|
|
||||||
|
def handle_startendtag(self, tag, attrs):
|
||||||
|
if tag == 'meta' and self._in_head:
|
||||||
|
self._handle_meta_tag(attrs)
|
||||||
|
if self._in_body:
|
||||||
|
self._data_buffer += self.build_tag(tag, attrs, True)
|
||||||
|
|
||||||
|
def handle_comment(self, data):
|
||||||
|
self._data_buffer += '<!--{}-->'.format(data)
|
||||||
|
|
||||||
|
def handle_data(self, data):
|
||||||
|
self._data_buffer += data
|
||||||
|
|
||||||
|
def handle_entityref(self, data):
|
||||||
|
self._data_buffer += '&{};'.format(data)
|
||||||
|
|
||||||
|
def handle_charref(self, data):
|
||||||
|
self._data_buffer += '&#{};'.format(data)
|
||||||
|
|
||||||
|
def build_tag(self, tag, attrs, close_tag):
|
||||||
|
result = '<{}'.format(escape(tag))
|
||||||
|
for k, v in attrs:
|
||||||
|
result += ' ' + escape(k)
|
||||||
|
if v is not None:
|
||||||
|
result += '="{}"'.format(escape(v))
|
||||||
|
if close_tag:
|
||||||
|
return result + ' />'
|
||||||
|
return result + '>'
|
||||||
|
|
||||||
|
def _handle_meta_tag(self, attrs):
|
||||||
|
name = self._attr_value(attrs, 'name').lower()
|
||||||
|
contents = self._attr_value(attrs, 'contents', '')
|
||||||
|
|
||||||
|
if name == 'keywords':
|
||||||
|
name = 'tags'
|
||||||
|
self.metadata[name] = contents
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _attr_value(cls, attrs, name, default=None):
|
||||||
|
return next((x[1] for x in attrs if x[0] == name), default)
|
||||||
|
|
||||||
|
def read(self, filename):
|
||||||
|
"""Parse content and metadata of HTML files"""
|
||||||
|
with pelican_open(filename) as content:
|
||||||
|
parser = self._HTMLParser(self.settings)
|
||||||
|
parser.feed(content)
|
||||||
|
parser.close()
|
||||||
|
|
||||||
|
metadata = {}
|
||||||
|
for k in parser.metadata:
|
||||||
|
metadata[k] = self.process_metadata(k, parser.metadata[k])
|
||||||
|
return parser.body, metadata
|
||||||
|
|
||||||
|
|
||||||
|
class AsciiDocReader(Reader):
|
||||||
|
enabled = bool(asciidoc)
|
||||||
|
file_extensions = ['asc']
|
||||||
|
default_options = ["--no-header-footer", "-a newline=\\n"]
|
||||||
|
|
||||||
|
def read(self, source_path):
|
||||||
|
"""Parse content and metadata of asciidoc files"""
|
||||||
|
from cStringIO import StringIO
|
||||||
|
with pelican_open(source_path) as source:
|
||||||
|
text = StringIO(source)
|
||||||
|
content = StringIO()
|
||||||
|
ad = AsciiDocAPI()
|
||||||
|
|
||||||
|
options = self.settings['ASCIIDOC_OPTIONS']
|
||||||
|
if isinstance(options, (str, unicode)):
|
||||||
|
options = [m.strip() for m in options.split(',')]
|
||||||
|
options = self.default_options + options
|
||||||
|
for o in options:
|
||||||
|
ad.options(*o.split())
|
||||||
|
|
||||||
|
ad.execute(text, content, backend="html4")
|
||||||
|
content = content.getvalue()
|
||||||
|
|
||||||
|
metadata = {}
|
||||||
|
for name, value in ad.asciidoc.document.attributes.items():
|
||||||
|
name = name.lower()
|
||||||
|
metadata[name] = self.process_metadata(name, value)
|
||||||
|
if 'doctitle' in metadata:
|
||||||
|
metadata['title'] = metadata['doctitle']
|
||||||
|
return content, metadata
|
||||||
|
|
||||||
|
|
||||||
|
EXTENSIONS = {}
|
||||||
|
|
||||||
|
for cls in [Reader] + Reader.__subclasses__():
|
||||||
|
for ext in cls.file_extensions:
|
||||||
|
EXTENSIONS[ext] = cls
|
||||||
|
|
||||||
|
|
||||||
|
def read_file(base_path, path, content_class=Page, fmt=None,
|
||||||
|
settings=None, context=None,
|
||||||
|
preread_signal=None, preread_sender=None,
|
||||||
|
context_signal=None, context_sender=None):
|
||||||
|
"""Return a content object parsed with the given format."""
|
||||||
|
path = os.path.abspath(os.path.join(base_path, path))
|
||||||
|
source_path = os.path.relpath(path, base_path)
|
||||||
|
base, ext = os.path.splitext(os.path.basename(path))
|
||||||
|
logger.debug('read file {} -> {}'.format(
|
||||||
|
source_path, content_class.__name__))
|
||||||
|
if not fmt:
|
||||||
|
fmt = ext[1:]
|
||||||
|
|
||||||
|
if fmt not in EXTENSIONS:
|
||||||
|
raise TypeError('Pelican does not know how to parse {}'.format(path))
|
||||||
|
|
||||||
|
if preread_signal:
|
||||||
|
logger.debug('signal {}.send({})'.format(
|
||||||
|
preread_signal, preread_sender))
|
||||||
|
preread_signal.send(preread_sender)
|
||||||
|
|
||||||
|
if settings is None:
|
||||||
|
settings = {}
|
||||||
|
|
||||||
|
reader_class = EXTENSIONS[fmt]
|
||||||
|
if not reader_class.enabled:
|
||||||
|
raise ValueError('Missing dependencies for {}'.format(fmt))
|
||||||
|
|
||||||
|
reader = reader_class(settings)
|
||||||
|
|
||||||
|
settings_key = '%s_EXTENSIONS' % fmt.upper()
|
||||||
|
|
||||||
|
if settings and settings_key in settings:
|
||||||
|
reader.extensions = settings[settings_key]
|
||||||
|
|
||||||
|
metadata = default_metadata(
|
||||||
|
settings=settings, process=reader.process_metadata)
|
||||||
|
metadata.update(path_metadata(
|
||||||
|
full_path=path, source_path=source_path, settings=settings))
|
||||||
|
metadata.update(parse_path_metadata(
|
||||||
|
source_path=source_path, settings=settings,
|
||||||
|
process=reader.process_metadata))
|
||||||
|
content, reader_metadata = reader.read(path)
|
||||||
|
metadata.update(reader_metadata)
|
||||||
|
|
||||||
|
# eventually filter the content with typogrify if asked so
|
||||||
|
if content and settings and settings['TYPOGRIFY']:
|
||||||
|
from typogrify.filters import typogrify
|
||||||
|
content = typogrify(content)
|
||||||
|
metadata['title'] = typogrify(metadata['title'])
|
||||||
|
|
||||||
|
if context_signal:
|
||||||
|
logger.debug('signal {}.send({}, <metadata>)'.format(
|
||||||
|
context_signal, context_sender))
|
||||||
|
context_signal.send(context_sender, metadata=metadata)
|
||||||
|
return content_class(
|
||||||
|
content=content,
|
||||||
|
metadata=metadata,
|
||||||
|
settings=settings,
|
||||||
|
source_path=path,
|
||||||
|
context=context)
|
||||||
|
|
||||||
|
|
||||||
|
def default_metadata(settings=None, process=None):
|
||||||
|
metadata = {}
|
||||||
|
if settings:
|
||||||
|
if 'DEFAULT_CATEGORY' in settings:
|
||||||
|
value = settings['DEFAULT_CATEGORY']
|
||||||
|
if process:
|
||||||
|
value = process('category', value)
|
||||||
|
metadata['category'] = value
|
||||||
|
if 'DEFAULT_DATE' in settings and settings['DEFAULT_DATE'] != 'fs':
|
||||||
|
metadata['date'] = datetime.datetime(*settings['DEFAULT_DATE'])
|
||||||
|
return metadata
|
||||||
|
|
||||||
|
|
||||||
|
def path_metadata(full_path, source_path, settings=None):
|
||||||
|
metadata = {}
|
||||||
|
if settings:
|
||||||
|
if settings.get('DEFAULT_DATE', None) == 'fs':
|
||||||
|
metadata['date'] = datetime.datetime.fromtimestamp(
|
||||||
|
os.stat(full_path).st_ctime)
|
||||||
|
metadata.update(settings.get('EXTRA_PATH_METADATA', {}).get(
|
||||||
|
source_path, {}))
|
||||||
|
return metadata
|
||||||
|
|
||||||
|
|
||||||
|
def parse_path_metadata(source_path, settings=None, process=None):
|
||||||
|
"""Extract a metadata dictionary from a file's path
|
||||||
|
|
||||||
|
>>> import pprint
|
||||||
|
>>> settings = {
|
||||||
|
... 'FILENAME_METADATA': '(?P<slug>[^.]*).*',
|
||||||
|
... 'PATH_METADATA':
|
||||||
|
... '(?P<category>[^/]*)/(?P<date>\d{4}-\d{2}-\d{2})/.*',
|
||||||
|
... }
|
||||||
|
>>> reader = Reader(settings=settings)
|
||||||
|
>>> metadata = parse_path_metadata(
|
||||||
|
... source_path='my-cat/2013-01-01/my-slug.html',
|
||||||
|
... settings=settings,
|
||||||
|
... process=reader.process_metadata)
|
||||||
|
>>> pprint.pprint(metadata) # doctest: +ELLIPSIS
|
||||||
|
{'category': <pelican.urlwrappers.Category object at ...>,
|
||||||
|
'date': datetime.datetime(2013, 1, 1, 0, 0),
|
||||||
|
'slug': 'my-slug'}
|
||||||
|
"""
|
||||||
|
metadata = {}
|
||||||
|
dirname, basename = os.path.split(source_path)
|
||||||
|
base, ext = os.path.splitext(basename)
|
||||||
|
subdir = os.path.basename(dirname)
|
||||||
|
if settings:
|
||||||
|
checks = []
|
||||||
|
for key, data in [('FILENAME_METADATA', base),
|
||||||
|
('PATH_METADATA', source_path),
|
||||||
|
]:
|
||||||
|
checks.append((settings.get(key, None), data))
|
||||||
|
if settings.get('USE_FOLDER_AS_CATEGORY', None):
|
||||||
|
checks.insert(0, ('(?P<category>.*)', subdir))
|
||||||
|
for regexp, data in checks:
|
||||||
|
if regexp and data:
|
||||||
|
match = re.match(regexp, data)
|
||||||
|
if match:
|
||||||
|
# .items() for py3k compat.
|
||||||
|
for k, v in match.groupdict().items():
|
||||||
|
if k not in metadata:
|
||||||
|
k = k.lower() # metadata must be lowercase
|
||||||
|
if process:
|
||||||
|
v = process(k, v)
|
||||||
|
metadata[k] = v
|
||||||
|
return metadata
|
||||||
117
pelican/rstdirectives.py
Normal file
117
pelican/rstdirectives.py
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
|
||||||
|
from docutils import nodes, utils
|
||||||
|
from docutils.parsers.rst import directives, roles, Directive
|
||||||
|
from pygments.formatters import HtmlFormatter
|
||||||
|
from pygments import highlight
|
||||||
|
from pygments.lexers import get_lexer_by_name, TextLexer
|
||||||
|
import re
|
||||||
|
|
||||||
|
INLINESTYLES = False
|
||||||
|
DEFAULT = HtmlFormatter(noclasses=INLINESTYLES)
|
||||||
|
VARIANTS = {
|
||||||
|
'linenos': HtmlFormatter(noclasses=INLINESTYLES, linenos=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Pygments(Directive):
|
||||||
|
""" Source code syntax hightlighting.
|
||||||
|
"""
|
||||||
|
required_arguments = 1
|
||||||
|
optional_arguments = 0
|
||||||
|
final_argument_whitespace = True
|
||||||
|
option_spec = dict([(key, directives.flag) for key in VARIANTS])
|
||||||
|
has_content = True
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.assert_has_content()
|
||||||
|
try:
|
||||||
|
lexer = get_lexer_by_name(self.arguments[0])
|
||||||
|
except ValueError:
|
||||||
|
# no lexer found - use the text one instead of an exception
|
||||||
|
lexer = TextLexer()
|
||||||
|
# take an arbitrary option if more than one is given
|
||||||
|
formatter = self.options and VARIANTS[self.options.keys()[0]] \
|
||||||
|
or DEFAULT
|
||||||
|
parsed = highlight('\n'.join(self.content), lexer, formatter)
|
||||||
|
return [nodes.raw('', parsed, format='html')]
|
||||||
|
|
||||||
|
directives.register_directive('code-block', Pygments)
|
||||||
|
directives.register_directive('sourcecode', Pygments)
|
||||||
|
|
||||||
|
|
||||||
|
class YouTube(Directive):
|
||||||
|
""" Embed YouTube video in posts.
|
||||||
|
|
||||||
|
Courtesy of Brian Hsu: https://gist.github.com/1422773
|
||||||
|
|
||||||
|
VIDEO_ID is required, with / height are optional integer,
|
||||||
|
and align could be left / center / right.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
.. youtube:: VIDEO_ID
|
||||||
|
:width: 640
|
||||||
|
:height: 480
|
||||||
|
:align: center
|
||||||
|
"""
|
||||||
|
|
||||||
|
def align(argument):
|
||||||
|
"""Conversion function for the "align" option."""
|
||||||
|
return directives.choice(argument, ('left', 'center', 'right'))
|
||||||
|
|
||||||
|
required_arguments = 1
|
||||||
|
optional_arguments = 2
|
||||||
|
option_spec = {
|
||||||
|
'width': directives.positive_int,
|
||||||
|
'height': directives.positive_int,
|
||||||
|
'align': align
|
||||||
|
}
|
||||||
|
|
||||||
|
final_argument_whitespace = False
|
||||||
|
has_content = False
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
videoID = self.arguments[0].strip()
|
||||||
|
width = 420
|
||||||
|
height = 315
|
||||||
|
align = 'left'
|
||||||
|
|
||||||
|
if 'width' in self.options:
|
||||||
|
width = self.options['width']
|
||||||
|
|
||||||
|
if 'height' in self.options:
|
||||||
|
height = self.options['height']
|
||||||
|
|
||||||
|
if 'align' in self.options:
|
||||||
|
align = self.options['align']
|
||||||
|
|
||||||
|
url = 'http://www.youtube.com/embed/%s' % videoID
|
||||||
|
div_block = '<div class="youtube" align="%s">' % align
|
||||||
|
embed_block = '<iframe width="%s" height="%s" src="%s" '\
|
||||||
|
'frameborder="0"></iframe>' % (width, height, url)
|
||||||
|
|
||||||
|
return [
|
||||||
|
nodes.raw('', div_block, format='html'),
|
||||||
|
nodes.raw('', embed_block, format='html'),
|
||||||
|
nodes.raw('', '</div>', format='html')]
|
||||||
|
|
||||||
|
directives.register_directive('youtube', YouTube)
|
||||||
|
|
||||||
|
_abbr_re = re.compile('\((.*)\)$')
|
||||||
|
|
||||||
|
|
||||||
|
class abbreviation(nodes.Inline, nodes.TextElement):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def abbr_role(typ, rawtext, text, lineno, inliner, options={}, content=[]):
|
||||||
|
text = utils.unescape(text)
|
||||||
|
m = _abbr_re.search(text)
|
||||||
|
if m is None:
|
||||||
|
return [abbreviation(text, text)], []
|
||||||
|
abbr = text[:m.start()].strip()
|
||||||
|
expl = m.group(1)
|
||||||
|
return [abbreviation(abbr, abbr, explanation=expl)], []
|
||||||
|
|
||||||
|
roles.register_local_role('abbr', abbr_role)
|
||||||
29
pelican/server.py
Normal file
29
pelican/server.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
from __future__ import print_function
|
||||||
|
import sys
|
||||||
|
try:
|
||||||
|
import SimpleHTTPServer as srvmod
|
||||||
|
except ImportError:
|
||||||
|
import http.server as srvmod # NOQA
|
||||||
|
|
||||||
|
try:
|
||||||
|
import SocketServer as socketserver
|
||||||
|
except ImportError:
|
||||||
|
import socketserver # NOQA
|
||||||
|
|
||||||
|
PORT = 8000
|
||||||
|
|
||||||
|
Handler = srvmod.SimpleHTTPRequestHandler
|
||||||
|
|
||||||
|
try:
|
||||||
|
httpd = socketserver.TCPServer(("", PORT), Handler)
|
||||||
|
except OSError as e:
|
||||||
|
print("Could not listen on port", PORT)
|
||||||
|
sys.exit(getattr(e, 'exitcode', 1))
|
||||||
|
|
||||||
|
|
||||||
|
print("serving at port", PORT)
|
||||||
|
try:
|
||||||
|
httpd.serve_forever()
|
||||||
|
except KeyboardInterrupt as e:
|
||||||
|
print("shutting down server")
|
||||||
|
httpd.socket.close()
|
||||||
271
pelican/settings.py
Normal file
271
pelican/settings.py
Normal file
|
|
@ -0,0 +1,271 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
import six
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import inspect
|
||||||
|
import os
|
||||||
|
import locale
|
||||||
|
import logging
|
||||||
|
|
||||||
|
try:
|
||||||
|
# SourceFileLoader is the recommended way in 3.3+
|
||||||
|
from importlib.machinery import SourceFileLoader
|
||||||
|
load_source = lambda name, path: SourceFileLoader(name, path).load_module()
|
||||||
|
except ImportError:
|
||||||
|
# but it does not exist in 3.2-, so fall back to imp
|
||||||
|
import imp
|
||||||
|
load_source = imp.load_source
|
||||||
|
|
||||||
|
from os.path import isabs
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_THEME = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||||
|
'themes', 'notmyidea')
|
||||||
|
DEFAULT_CONFIG = {
|
||||||
|
'PATH': os.curdir,
|
||||||
|
'ARTICLE_DIR': '',
|
||||||
|
'ARTICLE_EXCLUDES': ('pages',),
|
||||||
|
'PAGE_DIR': 'pages',
|
||||||
|
'PAGE_EXCLUDES': (),
|
||||||
|
'THEME': DEFAULT_THEME,
|
||||||
|
'OUTPUT_PATH': 'output',
|
||||||
|
'MARKUP': ('rst', 'md'),
|
||||||
|
'STATIC_PATHS': ['images', ],
|
||||||
|
'THEME_STATIC_PATHS': ['static', ],
|
||||||
|
'FEED_ALL_ATOM': os.path.join('feeds', 'all.atom.xml'),
|
||||||
|
'CATEGORY_FEED_ATOM': os.path.join('feeds', '%s.atom.xml'),
|
||||||
|
'TRANSLATION_FEED_ATOM': os.path.join('feeds', 'all-%s.atom.xml'),
|
||||||
|
'FEED_MAX_ITEMS': '',
|
||||||
|
'SITEURL': '',
|
||||||
|
'SITENAME': 'A Pelican Blog',
|
||||||
|
'DISPLAY_PAGES_ON_MENU': True,
|
||||||
|
'DISPLAY_CATEGORIES_ON_MENU': True,
|
||||||
|
'PDF_GENERATOR': False,
|
||||||
|
'OUTPUT_SOURCES': False,
|
||||||
|
'OUTPUT_SOURCES_EXTENSION': '.text',
|
||||||
|
'USE_FOLDER_AS_CATEGORY': True,
|
||||||
|
'DEFAULT_CATEGORY': 'misc',
|
||||||
|
'WITH_FUTURE_DATES': True,
|
||||||
|
'CSS_FILE': 'main.css',
|
||||||
|
'NEWEST_FIRST_ARCHIVES': True,
|
||||||
|
'REVERSE_CATEGORY_ORDER': False,
|
||||||
|
'DELETE_OUTPUT_DIRECTORY': False,
|
||||||
|
'OUTPUT_RETENTION': (),
|
||||||
|
'ARTICLE_URL': '{slug}.html',
|
||||||
|
'ARTICLE_SAVE_AS': '{slug}.html',
|
||||||
|
'ARTICLE_LANG_URL': '{slug}-{lang}.html',
|
||||||
|
'ARTICLE_LANG_SAVE_AS': '{slug}-{lang}.html',
|
||||||
|
'PAGE_URL': 'pages/{slug}.html',
|
||||||
|
'PAGE_SAVE_AS': os.path.join('pages', '{slug}.html'),
|
||||||
|
'PAGE_LANG_URL': 'pages/{slug}-{lang}.html',
|
||||||
|
'PAGE_LANG_SAVE_AS': os.path.join('pages', '{slug}-{lang}.html'),
|
||||||
|
'STATIC_URL': '{path}',
|
||||||
|
'STATIC_SAVE_AS': '{path}',
|
||||||
|
'PDF_STYLE_PATH': '',
|
||||||
|
'PDF_STYLE': 'twelvepoint',
|
||||||
|
'CATEGORY_URL': 'category/{slug}.html',
|
||||||
|
'CATEGORY_SAVE_AS': os.path.join('category', '{slug}.html'),
|
||||||
|
'TAG_URL': 'tag/{slug}.html',
|
||||||
|
'TAG_SAVE_AS': os.path.join('tag', '{slug}.html'),
|
||||||
|
'AUTHOR_URL': 'author/{slug}.html',
|
||||||
|
'AUTHOR_SAVE_AS': os.path.join('author', '{slug}.html'),
|
||||||
|
'YEAR_ARCHIVE_SAVE_AS': False,
|
||||||
|
'MONTH_ARCHIVE_SAVE_AS': False,
|
||||||
|
'DAY_ARCHIVE_SAVE_AS': False,
|
||||||
|
'RELATIVE_URLS': False,
|
||||||
|
'DEFAULT_LANG': 'en',
|
||||||
|
'TAG_CLOUD_STEPS': 4,
|
||||||
|
'TAG_CLOUD_MAX_ITEMS': 100,
|
||||||
|
'DIRECT_TEMPLATES': ('index', 'tags', 'categories', 'archives'),
|
||||||
|
'EXTRA_TEMPLATES_PATHS': [],
|
||||||
|
'PAGINATED_DIRECT_TEMPLATES': ('index', ),
|
||||||
|
'PELICAN_CLASS': 'pelican.Pelican',
|
||||||
|
'DEFAULT_DATE_FORMAT': '%a %d %B %Y',
|
||||||
|
'DATE_FORMATS': {},
|
||||||
|
'ASCIIDOC_OPTIONS': [],
|
||||||
|
'MD_EXTENSIONS': ['codehilite(css_class=highlight)', 'extra'],
|
||||||
|
'JINJA_EXTENSIONS': [],
|
||||||
|
'JINJA_FILTERS': {},
|
||||||
|
'LOCALE': [], # defaults to user locale
|
||||||
|
'DEFAULT_PAGINATION': False,
|
||||||
|
'DEFAULT_ORPHANS': 0,
|
||||||
|
'DEFAULT_METADATA': (),
|
||||||
|
'FILENAME_METADATA': '(?P<date>\d{4}-\d{2}-\d{2}).*',
|
||||||
|
'PATH_METADATA': '',
|
||||||
|
'EXTRA_PATH_METADATA': {},
|
||||||
|
'DEFAULT_STATUS': 'published',
|
||||||
|
'ARTICLE_PERMALINK_STRUCTURE': '',
|
||||||
|
'TYPOGRIFY': False,
|
||||||
|
'SUMMARY_MAX_LENGTH': 50,
|
||||||
|
'PLUGIN_PATH': '',
|
||||||
|
'PLUGINS': [],
|
||||||
|
'TEMPLATE_PAGES': {},
|
||||||
|
'IGNORE_FILES': ['.#*'],
|
||||||
|
}
|
||||||
|
|
||||||
|
def read_settings(path=None, override=None):
|
||||||
|
if path:
|
||||||
|
local_settings = get_settings_from_file(path)
|
||||||
|
# Make the paths relative to the settings file
|
||||||
|
for p in ['PATH', 'OUTPUT_PATH', 'THEME', 'PLUGIN_PATH']:
|
||||||
|
if p in local_settings and local_settings[p] is not None \
|
||||||
|
and not isabs(local_settings[p]):
|
||||||
|
absp = os.path.abspath(os.path.normpath(os.path.join(
|
||||||
|
os.path.dirname(path), local_settings[p])))
|
||||||
|
if p not in ('THEME', 'PLUGIN_PATH') or os.path.exists(absp):
|
||||||
|
local_settings[p] = absp
|
||||||
|
else:
|
||||||
|
local_settings = copy.deepcopy(DEFAULT_CONFIG)
|
||||||
|
|
||||||
|
if override:
|
||||||
|
local_settings.update(override)
|
||||||
|
|
||||||
|
return configure_settings(local_settings)
|
||||||
|
|
||||||
|
|
||||||
|
def get_settings_from_module(module=None, default_settings=DEFAULT_CONFIG):
|
||||||
|
"""Loads settings from a module, returns a dictionary."""
|
||||||
|
|
||||||
|
context = copy.deepcopy(default_settings)
|
||||||
|
if module is not None:
|
||||||
|
context.update(
|
||||||
|
(k, v) for k, v in inspect.getmembers(module) if k.isupper())
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
def get_settings_from_file(path, default_settings=DEFAULT_CONFIG):
|
||||||
|
"""Loads settings from a file path, returning a dict."""
|
||||||
|
|
||||||
|
name, ext = os.path.splitext(os.path.basename(path))
|
||||||
|
module = load_source(name, path)
|
||||||
|
return get_settings_from_module(module, default_settings=default_settings)
|
||||||
|
|
||||||
|
|
||||||
|
def configure_settings(settings):
|
||||||
|
"""Provide optimizations, error checking and warnings for the given
|
||||||
|
settings.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not 'PATH' in settings or not os.path.isdir(settings['PATH']):
|
||||||
|
raise Exception('You need to specify a path containing the content'
|
||||||
|
' (see pelican --help for more information)')
|
||||||
|
|
||||||
|
# lookup the theme in "pelican/themes" if the given one doesn't exist
|
||||||
|
if not os.path.isdir(settings['THEME']):
|
||||||
|
theme_path = os.path.join(
|
||||||
|
os.path.dirname(os.path.abspath(__file__)),
|
||||||
|
'themes',
|
||||||
|
settings['THEME'])
|
||||||
|
if os.path.exists(theme_path):
|
||||||
|
settings['THEME'] = theme_path
|
||||||
|
else:
|
||||||
|
raise Exception("Could not find the theme %s"
|
||||||
|
% settings['THEME'])
|
||||||
|
|
||||||
|
# standardize strings to lowercase strings
|
||||||
|
for key in [
|
||||||
|
'DEFAULT_LANG',
|
||||||
|
]:
|
||||||
|
if key in settings:
|
||||||
|
settings[key] = settings[key].lower()
|
||||||
|
|
||||||
|
# standardize strings to lists
|
||||||
|
for key in [
|
||||||
|
'LOCALE',
|
||||||
|
]:
|
||||||
|
if key in settings and isinstance(settings[key], six.string_types):
|
||||||
|
settings[key] = [settings[key]]
|
||||||
|
|
||||||
|
# check settings that must be a particular type
|
||||||
|
for key, types in [
|
||||||
|
('OUTPUT_SOURCES_EXTENSION', six.string_types),
|
||||||
|
('FILENAME_METADATA', six.string_types),
|
||||||
|
]:
|
||||||
|
if key in settings and not isinstance(settings[key], types):
|
||||||
|
value = settings.pop(key)
|
||||||
|
logger.warn(
|
||||||
|
'Detected misconfigured {} ({}), '
|
||||||
|
'falling back to the default ({})'.format(
|
||||||
|
key, value, DEFAULT_CONFIG[key]))
|
||||||
|
|
||||||
|
# try to set the different locales, fallback on the default.
|
||||||
|
locales = settings.get('LOCALE', DEFAULT_CONFIG['LOCALE'])
|
||||||
|
|
||||||
|
for locale_ in locales:
|
||||||
|
try:
|
||||||
|
locale.setlocale(locale.LC_ALL, str(locale_))
|
||||||
|
break # break if it is successful
|
||||||
|
except locale.Error:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
logger.warning("LOCALE option doesn't contain a correct value")
|
||||||
|
|
||||||
|
if ('SITEURL' in settings):
|
||||||
|
# If SITEURL has a trailing slash, remove it and provide a warning
|
||||||
|
siteurl = settings['SITEURL']
|
||||||
|
if (siteurl.endswith('/')):
|
||||||
|
settings['SITEURL'] = siteurl[:-1]
|
||||||
|
logger.warning("Removed extraneous trailing slash from SITEURL.")
|
||||||
|
# If SITEURL is defined but FEED_DOMAIN isn't,
|
||||||
|
# set FEED_DOMAIN to SITEURL
|
||||||
|
if not 'FEED_DOMAIN' in settings:
|
||||||
|
settings['FEED_DOMAIN'] = settings['SITEURL']
|
||||||
|
|
||||||
|
# Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined
|
||||||
|
feed_keys = ['FEED_ATOM', 'FEED_RSS',
|
||||||
|
'FEED_ALL_ATOM', 'FEED_ALL_RSS',
|
||||||
|
'CATEGORY_FEED_ATOM', 'CATEGORY_FEED_RSS',
|
||||||
|
'TAG_FEED_ATOM', 'TAG_FEED_RSS',
|
||||||
|
'TRANSLATION_FEED_ATOM', 'TRANSLATION_FEED_RSS',
|
||||||
|
]
|
||||||
|
|
||||||
|
if any(settings.get(k) for k in feed_keys):
|
||||||
|
if not settings.get('SITEURL'):
|
||||||
|
logger.warning('Feeds generated without SITEURL set properly may not'
|
||||||
|
' be valid')
|
||||||
|
|
||||||
|
if not 'TIMEZONE' in settings:
|
||||||
|
logger.warning(
|
||||||
|
'No timezone information specified in the settings. Assuming'
|
||||||
|
' your timezone is UTC for feed generation. Check '
|
||||||
|
'http://docs.getpelican.com/en/latest/settings.html#timezone '
|
||||||
|
'for more information')
|
||||||
|
|
||||||
|
# Save people from accidentally setting a string rather than a list
|
||||||
|
path_keys = (
|
||||||
|
'ARTICLE_EXCLUDES',
|
||||||
|
'DEFAULT_METADATA',
|
||||||
|
'DIRECT_TEMPLATES',
|
||||||
|
'EXTRA_TEMPLATES_PATHS',
|
||||||
|
'FILES_TO_COPY',
|
||||||
|
'IGNORE_FILES',
|
||||||
|
'JINJA_EXTENSIONS',
|
||||||
|
'MARKUP',
|
||||||
|
'PAGINATED_DIRECT_TEMPLATES',
|
||||||
|
'PLUGINS',
|
||||||
|
'STATIC_PATHS',
|
||||||
|
'THEME_STATIC_PATHS',)
|
||||||
|
for PATH_KEY in filter(lambda k: k in settings, path_keys):
|
||||||
|
if isinstance(settings[PATH_KEY], six.string_types):
|
||||||
|
logger.warning("Detected misconfiguration with %s setting (must "
|
||||||
|
"be a list), falling back to the default"
|
||||||
|
% PATH_KEY)
|
||||||
|
settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY]
|
||||||
|
|
||||||
|
for old,new,doc in [
|
||||||
|
('LESS_GENERATOR', 'the Webassets plugin', None),
|
||||||
|
('FILES_TO_COPY', 'STATIC_PATHS and EXTRA_PATH_METADATA',
|
||||||
|
'https://github.com/getpelican/pelican/blob/master/docs/settings.rst#path-metadata'),
|
||||||
|
]:
|
||||||
|
if old in settings:
|
||||||
|
message = 'The {} setting has been removed in favor of {}'.format(
|
||||||
|
old, new)
|
||||||
|
if doc:
|
||||||
|
message += ', see {} for details'.format(doc)
|
||||||
|
logger.warning(message)
|
||||||
|
|
||||||
|
return settings
|
||||||
35
pelican/signals.py
Normal file
35
pelican/signals.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
from blinker import signal
|
||||||
|
|
||||||
|
# Run-level signals:
|
||||||
|
|
||||||
|
initialized = signal('pelican_initialized')
|
||||||
|
get_generators = signal('get_generators')
|
||||||
|
finalized = signal('pelican_finalized')
|
||||||
|
|
||||||
|
# Generator-level signals
|
||||||
|
|
||||||
|
generator_init = signal('generator_init')
|
||||||
|
|
||||||
|
article_generator_init = signal('article_generator_init')
|
||||||
|
article_generator_finalized = signal('article_generator_finalized')
|
||||||
|
|
||||||
|
page_generator_init = signal('page_generator_init')
|
||||||
|
page_generator_finalized = signal('page_generator_finalized')
|
||||||
|
|
||||||
|
static_generator_init = signal('static_generator_init')
|
||||||
|
static_generator_finalized = signal('static_generator_finalized')
|
||||||
|
|
||||||
|
# Page-level signals
|
||||||
|
|
||||||
|
article_generator_preread = signal('article_generator_preread')
|
||||||
|
article_generator_context = signal('article_generator_context')
|
||||||
|
|
||||||
|
page_generator_preread = signal('page_generator_preread')
|
||||||
|
page_generator_context = signal('page_generator_context')
|
||||||
|
|
||||||
|
static_generator_preread = signal('static_generator_preread')
|
||||||
|
static_generator_context = signal('static_generator_context')
|
||||||
|
|
||||||
|
content_object_init = signal('content_object_init')
|
||||||
8
pelican/tests/TestPages/bad_page.rst
Normal file
8
pelican/tests/TestPages/bad_page.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
This is a test bad page
|
||||||
|
#######################
|
||||||
|
|
||||||
|
:status: invalid
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
|
|
||||||
|
The status here is invalid, the page should not render.
|
||||||
8
pelican/tests/TestPages/hidden_page.rst
Normal file
8
pelican/tests/TestPages/hidden_page.rst
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
This is a test hidden page
|
||||||
|
##########################
|
||||||
|
|
||||||
|
:status: hidden
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
|
|
||||||
|
This page is hidden
|
||||||
12
pelican/tests/TestPages/hidden_page_markdown.md
Normal file
12
pelican/tests/TestPages/hidden_page_markdown.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
title: This is a markdown test hidden page
|
||||||
|
status: hidden
|
||||||
|
|
||||||
|
Test Markdown File Header
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
|
|
||||||
|
This page is hidden
|
||||||
11
pelican/tests/TestPages/hidden_page_with_template.rst
Normal file
11
pelican/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
|
||||||
4
pelican/tests/TestPages/page.rst
Normal file
4
pelican/tests/TestPages/page.rst
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
This is a test page
|
||||||
|
###################
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
9
pelican/tests/TestPages/page_markdown.md
Normal file
9
pelican/tests/TestPages/page_markdown.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
title: This is a markdown test page
|
||||||
|
|
||||||
|
Test Markdown File Header
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
8
pelican/tests/TestPages/page_with_template.rst
Normal file
8
pelican/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
|
||||||
2
pelican/tests/__init__.py
Normal file
2
pelican/tests/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
import logging
|
||||||
|
logging.getLogger().addHandler(logging.NullHandler())
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
Rst with filename metadata
|
||||||
|
##########################
|
||||||
|
|
||||||
|
:category: yeah
|
||||||
|
:author: Alexis Métaireau
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
category: yeah
|
||||||
|
author: Alexis Métaireau
|
||||||
|
|
||||||
|
Markdown with filename metadata
|
||||||
|
===============================
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
This is an article with category !
|
||||||
|
##################################
|
||||||
|
|
||||||
|
:category: yeah
|
||||||
|
:date: 1970-01-01
|
||||||
|
|
||||||
|
This article should be in 'yeah' category.
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
This is an article without category !
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
This article should be in 'TestCategory' category.
|
||||||
6
pelican/tests/content/article.rst
Normal file
6
pelican/tests/content/article.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
Article title
|
||||||
|
#############
|
||||||
|
|
||||||
|
This is some content. With some stuff to "typogrify".
|
||||||
|
|
||||||
|
Now with added support for :abbr:`TLA (three letter acronym)`.
|
||||||
12
pelican/tests/content/article_with_asc_extension.asc
Normal file
12
pelican/tests/content/article_with_asc_extension.asc
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
Test AsciiDoc File Header
|
||||||
|
=========================
|
||||||
|
:Author: Author O. Article
|
||||||
|
:Email: <author@nowhere.com>
|
||||||
|
:Date: 2011-09-15 09:05
|
||||||
|
:Category: Blog
|
||||||
|
:Tags: Linux, Python, Pelican
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
9
pelican/tests/content/article_with_asc_options.asc
Normal file
9
pelican/tests/content/article_with_asc_options.asc
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
Test AsciiDoc File Header
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
version {revision}
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
8
pelican/tests/content/article_with_comments.html
Normal file
8
pelican/tests/content/article_with_comments.html
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Body content
|
||||||
|
<!-- This comment is included (including extra whitespace) -->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
pelican/tests/content/article_with_keywords.html
Normal file
6
pelican/tests/content/article_with_keywords.html
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>This is a super article !</title>
|
||||||
|
<meta name="keywords" contents="foo, bar, foobar" />
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
Title: Article with markdown containing footnotes
|
||||||
|
Date: 2012-10-31
|
||||||
|
Summary: Summary with **inline** markup *should* be supported.
|
||||||
|
|
||||||
|
This is some content[^1] with some footnotes[^footnote]
|
||||||
|
|
||||||
|
[^1]: Numbered footnote
|
||||||
|
[^footnote]: Named footnote
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
Title: マックOS X 10.8でパイソンとVirtualenvをインストールと設定
|
||||||
|
Slug: python-virtualenv-on-mac-osx-mountain-lion-10.8
|
||||||
|
Date: 2012-12-20
|
||||||
|
Tags: パイソン, マック
|
||||||
|
Category: 指導書
|
||||||
|
Summary: パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。
|
||||||
|
|
||||||
|
Writing unicode is certainly fun.
|
||||||
|
|
||||||
|
パイソンとVirtualenvをまっくでインストールする方法について明確に説明します。
|
||||||
|
|
||||||
|
And let's mix languages.
|
||||||
|
|
||||||
|
первый пост
|
||||||
|
|
||||||
|
Now another.
|
||||||
|
|
||||||
|
İlk yazı çok özel değil.
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
Title: Article with markdown and summary metadata multi
|
||||||
|
Date: 2012-10-31
|
||||||
|
Summary:
|
||||||
|
A multi-line summary should be supported
|
||||||
|
as well as **inline markup**.
|
||||||
|
|
||||||
|
This is some content.
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
Title: Article with markdown and summary metadata single
|
||||||
|
Date: 2012-10-30
|
||||||
|
Summary: A single-line summary should be supported as well as **inline markup**.
|
||||||
|
|
||||||
|
This is some content.
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
title: Test markdown File
|
||||||
|
category: test
|
||||||
|
|
||||||
|
Test Markdown File Header
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
This is another markdown test file. Uses the markdown extension.
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
Title: Test Markdown extensions
|
||||||
|
|
||||||
|
[TOC]
|
||||||
|
|
||||||
|
## Level1
|
||||||
|
|
||||||
|
### Level2
|
||||||
|
|
||||||
13
pelican/tests/content/article_with_md_extension.md
Normal file
13
pelican/tests/content/article_with_md_extension.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
Title: Test md File
|
||||||
|
Category: test
|
||||||
|
Tags: foo, bar, foobar
|
||||||
|
Date: 2010-12-02 10:14
|
||||||
|
Summary: I have a lot to test
|
||||||
|
|
||||||
|
Test Markdown File Header
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
The quick brown fox jumped over the lazy dog's back.
|
||||||
10
pelican/tests/content/article_with_mdown_extension.mdown
Normal file
10
pelican/tests/content/article_with_mdown_extension.mdown
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
title: Test mdown File
|
||||||
|
category: test
|
||||||
|
|
||||||
|
Test Markdown File Header
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
This is another markdown test file. Uses the mdown extension.
|
||||||
15
pelican/tests/content/article_with_metadata.html
Normal file
15
pelican/tests/content/article_with_metadata.html
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>This is a super article !</title>
|
||||||
|
<meta name="tags" contents="foo, bar, foobar" />
|
||||||
|
<meta name="date" contents="2010-12-02 10:14" />
|
||||||
|
<meta name="category" contents="yeah" />
|
||||||
|
<meta name="author" contents="Alexis Métaireau" />
|
||||||
|
<meta name="summary" contents="Summary and stuff" />
|
||||||
|
<meta name="custom_field" contents="http://notmyidea.org" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Multi-line metadata should be supported
|
||||||
|
as well as <strong>inline markup</strong>.
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
12
pelican/tests/content/article_with_metadata.rst
Normal file
12
pelican/tests/content/article_with_metadata.rst
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
This is a super article !
|
||||||
|
#########################
|
||||||
|
|
||||||
|
:tags: foo, bar, foobar
|
||||||
|
:date: 2010-12-02 10:14
|
||||||
|
:category: yeah
|
||||||
|
:author: Alexis Métaireau
|
||||||
|
:summary:
|
||||||
|
Multi-line metadata should be supported
|
||||||
|
as well as **inline markup**.
|
||||||
|
:custom_field: http://notmyidea.org
|
||||||
10
pelican/tests/content/article_with_mkd_extension.mkd
Normal file
10
pelican/tests/content/article_with_mkd_extension.mkd
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
title: Test mkd File
|
||||||
|
category: test
|
||||||
|
|
||||||
|
Test Markdown File Header
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Used for pelican test
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
This is another markdown test file. Uses the mkd extension.
|
||||||
8
pelican/tests/content/article_with_null_attributes.html
Normal file
8
pelican/tests/content/article_with_null_attributes.html
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
Ensure that empty attributes are copied properly.
|
||||||
|
<input name="test" disabled style="" />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
8
pelican/tests/content/article_with_template.rst
Normal file
8
pelican/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".
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>This is a super article !</title>
|
||||||
|
<meta name="Category" contents="Yeah" />
|
||||||
|
</head>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
This is a super article !
|
||||||
|
#########################
|
||||||
|
|
||||||
|
:Category: Yeah
|
||||||
|
|
||||||
6
pelican/tests/content/article_without_category.rst
Normal file
6
pelican/tests/content/article_without_category.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
This is an article without category !
|
||||||
|
#####################################
|
||||||
|
|
||||||
|
This article should be in the DEFAULT_CATEGORY.
|
||||||
|
|
||||||
48
pelican/tests/content/wordpress_content_decoded
Normal file
48
pelican/tests/content/wordpress_content_decoded
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
||||||
|
<p><object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/XSrW-wAWZe4"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/XSrW-wAWZe4" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object></p>
|
||||||
|
<blockquote><p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p></blockquote>
|
||||||
|
<ul>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
</ul>
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
a = [1, 2, 3]
|
||||||
|
b = [4, 5, 6]
|
||||||
|
for i in zip(a, b):
|
||||||
|
print i
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
||||||
55
pelican/tests/content/wordpress_content_encoded
Normal file
55
pelican/tests/content/wordpress_content_encoded
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
|
<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/XSrW-wAWZe4"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/XSrW-wAWZe4" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
</blockquote>
|
||||||
|
<ul>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
a = [1, 2, 3]
|
||||||
|
b = [4, 5, 6]
|
||||||
|
for i in zip(a, b):
|
||||||
|
print i
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
686
pelican/tests/content/wordpressexport.xml
Normal file
686
pelican/tests/content/wordpressexport.xml
Normal file
|
|
@ -0,0 +1,686 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. -->
|
||||||
|
<!-- It contains information about your site's posts, pages, comments, categories, and other content. -->
|
||||||
|
<!-- You may use this file to transfer that content from one site to another. -->
|
||||||
|
<!-- This file is not intended to serve as a complete backup of your site. -->
|
||||||
|
|
||||||
|
<!-- To import this information into a WordPress site follow these steps: -->
|
||||||
|
<!-- 1. Log in to that site as an administrator. -->
|
||||||
|
<!-- 2. Go to Tools: Import in the WordPress admin panel. -->
|
||||||
|
<!-- 3. Install the "WordPress" importer from the list. -->
|
||||||
|
<!-- 4. Activate & Run Importer. -->
|
||||||
|
<!-- 5. Upload this file using the form provided on that page. -->
|
||||||
|
<!-- 6. You will first be asked to map the authors in this export file to users -->
|
||||||
|
<!-- on the site. For each author, you may choose to map to an -->
|
||||||
|
<!-- existing user on the site or to create a new user. -->
|
||||||
|
<!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. -->
|
||||||
|
<!-- contained in this file into your site. -->
|
||||||
|
|
||||||
|
<!-- generator="WordPress/3.3.1" created="2012-05-13 01:13" -->
|
||||||
|
<rss version="2.0"
|
||||||
|
xmlns:excerpt="http://wordpress.org/export/1.1/excerpt/"
|
||||||
|
xmlns:content="http://purl.org/rss/1.0/modules/content/"
|
||||||
|
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:wp="http://wordpress.org/export/1.1/"
|
||||||
|
>
|
||||||
|
|
||||||
|
<channel>
|
||||||
|
<title>Pelican test channel</title>
|
||||||
|
<link>http://thisisa.test</link>
|
||||||
|
<description>Not a real feed, just for test</description>
|
||||||
|
<pubDate>Sun, 13 May 2012 01:13:52 +0000</pubDate>
|
||||||
|
<language>en</language>
|
||||||
|
<wp:wxr_version>1.1</wp:wxr_version>
|
||||||
|
<wp:base_site_url>http://thisisa.test</wp:base_site_url>
|
||||||
|
<wp:base_blog_url>http://thisisa.test</wp:base_blog_url>
|
||||||
|
|
||||||
|
<wp:author><wp:author_id>2</wp:author_id><wp:author_login>Bob</wp:author_login><wp:author_email>bob@thisisa.test</wp:author_email><wp:author_display_name><![CDATA[Bob]]></wp:author_display_name><wp:author_first_name><![CDATA[Bob]]></wp:author_first_name><wp:author_last_name><![CDATA[]]></wp:author_last_name></wp:author>
|
||||||
|
<wp:author><wp:author_id>3</wp:author_id><wp:author_login>Jonh</wp:author_login><wp:author_email>jonh@thisisa.test</wp:author_email><wp:author_display_name><![CDATA[Jonh]]></wp:author_display_name><wp:author_first_name><![CDATA[Jonh]]></wp:author_first_name><wp:author_last_name><![CDATA[]]></wp:author_last_name></wp:author>
|
||||||
|
|
||||||
|
<wp:category><wp:term_id>7</wp:term_id><wp:category_nicename>categ-1</wp:category_nicename><wp:category_parent></wp:category_parent><wp:cat_name><![CDATA[Category 1]]></wp:cat_name></wp:category>
|
||||||
|
<wp:category><wp:term_id>11</wp:term_id><wp:category_nicename>categ-2</wp:category_nicename><wp:category_parent></wp:category_parent><wp:cat_name><![CDATA[Category 2]]></wp:cat_name></wp:category>
|
||||||
|
<wp:category><wp:term_id>1</wp:term_id><wp:category_nicename>uncategorized</wp:category_nicename><wp:category_parent></wp:category_parent><wp:cat_name><![CDATA[Uncategorized]]></wp:cat_name></wp:category>
|
||||||
|
<wp:category><wp:term_id>15</wp:term_id><wp:category_nicename>categ-3</wp:category_nicename><wp:category_parent></wp:category_parent><wp:cat_name><![CDATA[Category 3]]></wp:cat_name></wp:category>
|
||||||
|
<wp:tag><wp:term_id>25</wp:term_id><wp:tag_slug>tag-1</wp:tag_slug><wp:tag_name><![CDATA[tag 1]]></wp:tag_name></wp:tag>
|
||||||
|
<wp:tag><wp:term_id>122</wp:term_id><wp:tag_slug>tag2</wp:tag_slug><wp:tag_name><![CDATA[Tag2]]></wp:tag_name></wp:tag>
|
||||||
|
<wp:tag><wp:term_id>68</wp:term_id><wp:tag_slug>tag-3</wp:tag_slug><wp:tag_name><![CDATA[Tag 3]]></wp:tag_name></wp:tag>
|
||||||
|
|
||||||
|
<generator>http://wordpress.org/?v=3.3.1</generator>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<title>Empty post</title>
|
||||||
|
<link>http://thisisa.test/?attachment_id=24</link>
|
||||||
|
<pubDate>Sat, 04 Feb 2012 03:17:33 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Pelican_lakes_entrance02.jpg/240px-Pelican_lakes_entrance02.jpg</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>24</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-04 03:17:33</wp:post_date>
|
||||||
|
<wp:post_date_gmt>2012-02-04 03:17:33</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>empty-post</wp:post_name>
|
||||||
|
<wp:status>inherit</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>attachment</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<wp:attachment_url>https://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Pelican_lakes_entrance02.jpg/240px-Pelican_lakes_entrance02.jpg</wp:attachment_url>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_wp_attachment_metadata</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:5:{s:5:"width";s:3:"150";s:6:"height";s:3:"186";s:14:"hwstring_small";s:22:"height='96' width='77'";s:4:"file";s:20:"2012/02/pelican.png";s:10:"image_meta";a:10:{s:8:"aperture";s:1:"0";s:6:"credit";s:0:"";s:6:"camera";s:0:"";s:7:"caption";s:0:"";s:17:"created_timestamp";s:1:"0";s:9:"copyright";s:0:"";s:12:"focal_length";s:1:"0";s:3:"iso";s:1:"0";s:13:"shutter_speed";s:1:"0";s:5:"title";s:0:"";}}]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_wp_attached_file</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[2012/02/stuff.png]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_wp_attachment_image_alt</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[Stuff]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title></title>
|
||||||
|
<link>http://thisisa.test/?p=168</link>
|
||||||
|
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=168</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[This is a draft with no title]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>168</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-15 21:23:57</wp:post_date>
|
||||||
|
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name></wp:post_name>
|
||||||
|
<wp:status>draft</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="categ-1"><![CDATA[Category 1]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>A normal post</title>
|
||||||
|
<link>http://thisisa.test/?p=174</link>
|
||||||
|
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=174</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>174</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-16 15:52:55</wp:post_date>
|
||||||
|
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name></wp:post_name>
|
||||||
|
<wp:status>draft</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-2"><![CDATA[Category 2]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Complete draft</title>
|
||||||
|
<link>http://thisisa.test/?p=176</link>
|
||||||
|
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=176</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>176</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-17 15:11:55</wp:post_date>
|
||||||
|
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name></wp:post_name>
|
||||||
|
<wp:status>draft</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-3"><![CDATA[Category 3]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Page</title>
|
||||||
|
<link>http://thisisa.test/contact/</link>
|
||||||
|
<pubDate>Wed, 11 Apr 2012 11:38:08 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?page_id=334</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>334</wp:post_id>
|
||||||
|
<wp:post_date>2012-04-11 06:38:08</wp:post_date>
|
||||||
|
<wp:post_date_gmt>2012-04-11 11:38:08</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>contact</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>page</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>sharing_disabled</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[1]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_wp_page_template</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[default]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Empty Page</title>
|
||||||
|
<link>http://thisisa.test/empty/</link>
|
||||||
|
<pubDate>Wed, 11 Apr 2012 11:38:08 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?page_id=334</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>334</wp:post_id>
|
||||||
|
<wp:post_date>2012-04-11 06:38:08</wp:post_date>
|
||||||
|
<wp:post_date_gmt>2012-04-11 11:38:08</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>empty</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>page</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>sharing_disabled</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[1]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_wp_page_template</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[default]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Special chars: l'é</title>
|
||||||
|
<link>http://thisisa.test/?p=471</link>
|
||||||
|
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=471</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[l'é]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>471</wp:post_id>
|
||||||
|
<wp:post_date>2012-04-29 09:44:27</wp:post_date>
|
||||||
|
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name></wp:post_name>
|
||||||
|
<wp:status>draft</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-1"><![CDATA[Category 1]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<title>With excerpt</title>
|
||||||
|
<link>http://thisisa.test/with-excerpt/</link>
|
||||||
|
<pubDate>Sat, 04 Feb 2012 02:03:06 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=8</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></excerpt:encoded>
|
||||||
|
<wp:post_id>8</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-04 02:03:06</wp:post_date>
|
||||||
|
<wp:post_date_gmt>2012-02-04 02:03:06</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>with-excerpt</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="Category 1"><![CDATA[Category 1]]></category>
|
||||||
|
<category domain="post_tag" nicename="tag-1"><![CDATA[tag 1]]></category>
|
||||||
|
<category domain="post_tag" nicename="tag2"><![CDATA[Tag2]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>et_bigpost</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[0]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_thumbnail_id</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[32]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>With tags</title>
|
||||||
|
<link>http://thisisa.test/tags/</link>
|
||||||
|
<pubDate>Sat, 04 Feb 2012 21:05:25 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=25</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>25</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-04 21:05:25</wp:post_date>
|
||||||
|
<wp:post_date_gmt>2012-02-04 21:05:25</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>with-tags</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-3"><![CDATA[Category 3]]></category>
|
||||||
|
<category domain="post_tag" nicename="tag-1"><![CDATA[tag 1]]></category>
|
||||||
|
<category domain="post_tag" nicename="tag-2"><![CDATA[Tag2]]></category>
|
||||||
|
<category domain="post_tag" nicename="tag-3"><![CDATA[Tag 3]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>et_bigpost</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[0]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_thumbnail_id</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[29]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>With comments</title>
|
||||||
|
<link>http://thisisa.test/with-comments/</link>
|
||||||
|
<pubDate>Wed, 18 Apr 2012 08:36:26 +0000</pubDate>
|
||||||
|
<dc:creator>john</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=422</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>422</wp:post_id>
|
||||||
|
<wp:post_date>2012-04-18 03:36:26</wp:post_date>
|
||||||
|
<wp:post_date_gmt>2012-04-18 08:36:26</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>with-comments</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-1"><![CDATA[Category 1]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[2]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_thumbnail_id</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[423]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
<wp:comment>
|
||||||
|
<wp:comment_id>116</wp:comment_id>
|
||||||
|
<wp:comment_author><![CDATA[User2]]></wp:comment_author>
|
||||||
|
<wp:comment_author_email>User2@mail.test</wp:comment_author_email>
|
||||||
|
<wp:comment_author_url></wp:comment_author_url>
|
||||||
|
<wp:comment_author_IP>127.0.0.1</wp:comment_author_IP>
|
||||||
|
<wp:comment_date>2012-05-06 15:46:06</wp:comment_date>
|
||||||
|
<wp:comment_date_gmt>2012-05-06 20:46:06</wp:comment_date_gmt>
|
||||||
|
<wp:comment_content><![CDATA[Comment content.]]></wp:comment_content>
|
||||||
|
<wp:comment_approved>1</wp:comment_approved>
|
||||||
|
<wp:comment_type></wp:comment_type>
|
||||||
|
<wp:comment_parent>0</wp:comment_parent>
|
||||||
|
<wp:comment_user_id>0</wp:comment_user_id>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_result</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[false]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_history</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:4:{s:4:"time";s:15:"1336337189.7974";s:7:"message";s:28:"Akismet cleared this comment";s:5:"event";s:9:"check-ham";s:4:"user";s:0:"";}]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_as_submitted</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:64:{s:15:"comment_post_ID";s:3:"422";s:14:"comment_author";s:8:"Baronsed";s:20:"comment_author_email";s:15:"User2@mail.test";s:18:"comment_author_url";s:0:"";s:15:"comment_content";s:118:"Dans les listes d'articles où celui-ci apparaît, l'image est trop grande et ralentit le chargement de toute la page.";s:12:"comment_type";s:0:"";s:14:"comment_parent";s:1:"0";s:7:"user_ID";s:1:"0";s:7:"user_ip";s:14:"127.0.0.1";s:10:"user_agent";s:74:"Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0";s:8:"referrer";s:0:"";s:4:"blog";s:19:"http://thisisa.test";s:9:"blog_lang";s:5:"en_US";s:12:"blog_charset";s:5:"UTF-8";s:9:"permalink";s:62:"http://thisisa.test/htop-un-visualiseur-interactif-de-process/";s:9:"user_role";s:0:"";s:21:"akismet_comment_nonce";s:6:"passed";s:11:"POST_author";s:8:"Baronsed";s:10:"POST_email";s:15:"User2@mail.test";s:8:"POST_url";s:0:"";s:12:"POST_comment";s:118:"Dans les listes d'articles où celui-ci apparaît, l'image est trop grande et ralentit le chargement de toute la page.";s:11:"POST_submit";s:14:"Submit Comment";s:20:"POST_comment_post_ID";s:3:"422";s:19:"POST_comment_parent";s:1:"0";s:26:"POST_akismet_comment_nonce";s:10:"96b66769dc";s:15:"SERVER_SOFTWARE";s:12:"nginx/0.8.55";s:11:"REQUEST_URI";s:21:"/wp-comments-post.php";s:4:"TERM";s:5:"xterm";s:17:"PHP_FCGI_CHILDREN";s:1:"4";s:4:"PATH";s:29:"/sbin:/usr/sbin:/bin:/usr/bin";s:1:"_";s:25:"/usr/local/bin/spawn-fcgi";s:3:"PWD";s:1:"/";s:4:"LANG";s:11:"en_US.UTF-8";s:5:"SHLVL";s:1:"2";s:21:"PHP_FCGI_MAX_REQUESTS";s:4:"1000";s:9:"FCGI_ROLE";s:9:"RESPONDER";s:12:"QUERY_STRING";s:0:"";s:14:"REQUEST_METHOD";s:4:"POST";s:12:"CONTENT_TYPE";s:33:"application/x-www-form-urlencoded";s:14:"CONTENT_LENGTH";s:3:"277";s:11:"SCRIPT_NAME";s:21:"/wp-comments-post.php";s:12:"DOCUMENT_URI";s:21:"/wp-comments-post.php";s:13:"DOCUMENT_ROOT";s:14:"/home/blog";s:15:"SERVER_PROTOCOL";s:8:"HTTP/1.1";s:17:"GATEWAY_INTERFACE";s:7:"CGI/1.1";s:11:"REMOTE_ADDR";s:14:"127.0.0.1";s:11:"REMOTE_PORT";s:5:"52826";s:11:"SERVER_ADDR";s:13:"127.0.0.1";s:11:"SERVER_PORT";s:2:"80";s:11:"SERVER_NAME";s:12:"thisisa.test";s:15:"REDIRECT_STATUS";s:3:"200";s:15:"SCRIPT_FILENAME";s:35:"/home/blog/wp-comments-post.php";s:9:"HTTP_HOST";s:12:"thisisa.test";s:15:"HTTP_USER_AGENT";s:74:"Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:12.0) Gecko/20100101 Firefox/12.0";s:11:"HTTP_ACCEPT";s:63:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";s:20:"HTTP_ACCEPT_LANGUAGE";s:35:"fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3";s:20:"HTTP_ACCEPT_ENCODING";s:13:"gzip, deflate";s:8:"HTTP_DNT";s:1:"1";s:15:"HTTP_CONNECTION";s:10:"keep-alive";s:11:"HTTP_COOKIE";s:0:"";s:17:"HTTP_CONTENT_TYPE";s:33:"application/x-www-form-urlencoded";s:19:"HTTP_CONTENT_LENGTH";s:3:"277";s:8:"PHP_SELF";s:21:"/wp-comments-post.php";s:12:"REQUEST_TIME";s:10:"1336337164";}]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
</wp:comment>
|
||||||
|
<wp:comment>
|
||||||
|
<wp:comment_id>117</wp:comment_id>
|
||||||
|
<wp:comment_author><![CDATA[Bob]]></wp:comment_author>
|
||||||
|
<wp:comment_author_email>bob@thisisa.test</wp:comment_author_email>
|
||||||
|
<wp:comment_author_url></wp:comment_author_url>
|
||||||
|
<wp:comment_author_IP>127.0.0.1</wp:comment_author_IP>
|
||||||
|
<wp:comment_date>2012-05-06 17:44:06</wp:comment_date>
|
||||||
|
<wp:comment_date_gmt>2012-05-06 22:44:06</wp:comment_date_gmt>
|
||||||
|
<wp:comment_content><![CDATA[Comment content.]]></wp:comment_content>
|
||||||
|
<wp:comment_approved>1</wp:comment_approved>
|
||||||
|
<wp:comment_type></wp:comment_type>
|
||||||
|
<wp:comment_parent>116</wp:comment_parent>
|
||||||
|
<wp:comment_user_id>3</wp:comment_user_id>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_result</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[false]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_history</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:4:{s:4:"time";s:15:"1336344263.8658";s:7:"message";s:28:"Akismet cleared this comment";s:5:"event";s:9:"check-ham";s:4:"user";s:3:"bob";}]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_as_submitted</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:74:{s:15:"comment_post_ID";s:3:"422";s:14:"comment_author";s:3:"bob";s:20:"comment_author_email";s:25:"bob@thisisa.test";s:18:"comment_author_url";s:0:"";s:15:"comment_content";s:26:"Merci de l'avoir signalé.";s:14:"comment_parent";s:3:"116";s:7:"user_ID";s:1:"3";s:7:"user_ip";s:14:"127.0.0.1";s:10:"user_agent";s:139:"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/12.04 Chromium/127.0.0.1 Chrome/127.0.0.1 Safari/535.19";s:8:"referrer";s:29:"http://thisisa.test/wp-admin/";s:4:"blog";s:19:"http://thisisa.test";s:9:"blog_lang";s:5:"en_US";s:12:"blog_charset";s:5:"UTF-8";s:9:"permalink";s:62:"http://thisisa.test/htop-un-visualiseur-interactif-de-process/";s:9:"user_role";s:13:"administrator";s:21:"akismet_comment_nonce";s:6:"passed";s:22:"POST_newcomment_author";s:0:"";s:28:"POST_newcomment_author_email";s:0:"";s:26:"POST_newcomment_author_url";s:0:"";s:12:"POST_user_ID";s:1:"3";s:11:"POST_action";s:15:"replyto-comment";s:15:"POST_comment_ID";s:3:"116";s:20:"POST_comment_post_ID";s:3:"422";s:11:"POST_status";s:0:"";s:13:"POST_position";s:2:"-1";s:13:"POST_checkbox";s:1:"0";s:9:"POST_mode";s:9:"dashboard";s:32:"POST__ajax_nonce-replyto-comment";s:10:"d1ad3bd917";s:32:"POST__wp_unfiltered_html_comment";s:10:"fc11aee860";s:12:"POST_content";s:26:"Merci de l'avoir signalé.";s:7:"POST_id";s:3:"422";s:21:"POST_comments_listing";s:0:"";s:15:"SERVER_SOFTWARE";s:12:"nginx/0.8.55";s:11:"REQUEST_URI";s:24:"/wp-admin/admin-ajax.php";s:4:"TERM";s:5:"xterm";s:17:"PHP_FCGI_CHILDREN";s:1:"4";s:4:"PATH";s:29:"/sbin:/usr/sbin:/bin:/usr/bin";s:1:"_";s:25:"/usr/local/bin/spawn-fcgi";s:3:"PWD";s:1:"/";s:4:"LANG";s:11:"en_US.UTF-8";s:5:"SHLVL";s:1:"2";s:21:"PHP_FCGI_MAX_REQUESTS";s:4:"1000";s:9:"FCGI_ROLE";s:9:"RESPONDER";s:12:"QUERY_STRING";s:0:"";s:14:"REQUEST_METHOD";s:4:"POST";s:12:"CONTENT_TYPE";s:33:"application/x-www-form-urlencoded";s:14:"CONTENT_LENGTH";s:3:"322";s:11:"SCRIPT_NAME";s:24:"/wp-admin/admin-ajax.php";s:12:"DOCUMENT_URI";s:24:"/wp-admin/admin-ajax.php";s:13:"DOCUMENT_ROOT";s:14:"/home/blog";s:15:"SERVER_PROTOCOL";s:8:"HTTP/1.1";s:17:"GATEWAY_INTERFACE";s:7:"CGI/1.1";s:11:"REMOTE_ADDR";s:14:"127.0.0.1";s:11:"REMOTE_PORT";s:5:"10252";s:11:"SERVER_ADDR";s:13:"127.0.0.1";s:11:"SERVER_PORT";s:2:"80";s:11:"SERVER_NAME";s:12:"thisisa.test";s:15:"REDIRECT_STATUS";s:3:"200";s:15:"SCRIPT_FILENAME";s:38:"/home/blog/wp-admin/admin-ajax.php";s:9:"HTTP_HOST";s:12:"thisisa.test";s:15:"HTTP_CONNECTION";s:10:"keep-alive";s:19:"HTTP_CONTENT_LENGTH";s:3:"322";s:11:"HTTP_ORIGIN";s:19:"http://thisisa.test";s:21:"HTTP_X_REQUESTED_WITH";s:14:"XMLHttpRequest";s:15:"HTTP_USER_AGENT";s:139:"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/12.04 Chromium/127.0.0.1 Chrome/127.0.0.1 Safari/535.19";s:17:"HTTP_CONTENT_TYPE";s:33:"application/x-www-form-urlencoded";s:11:"HTTP_ACCEPT";s:3:"*/*";s:12:"HTTP_REFERER";s:29:"http://thisisa.test/wp-admin/";s:20:"HTTP_ACCEPT_ENCODING";s:17:"gzip,deflate,sdch";s:20:"HTTP_ACCEPT_LANGUAGE";s:35:"fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4";s:19:"HTTP_ACCEPT_CHARSET";s:30:"ISO-8859-1,utf-8;q=0.7,*;q=0.3";s:11:"HTTP_COOKIE";s:0:"";s:8:"PHP_SELF";s:24:"/wp-admin/admin-ajax.php";s:12:"REQUEST_TIME";s:10:"1336344246";}]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
</wp:comment>
|
||||||
|
<wp:comment>
|
||||||
|
<wp:comment_id>156</wp:comment_id>
|
||||||
|
<wp:comment_author><![CDATA[Ping back comment author]]></wp:comment_author>
|
||||||
|
<wp:comment_author_email></wp:comment_author_email>
|
||||||
|
<wp:comment_author_url>http://thisisa.test/to-article-you-ping-back/</wp:comment_author_url>
|
||||||
|
<wp:comment_author_IP>127.0.0.1</wp:comment_author_IP>
|
||||||
|
<wp:comment_date>2012-05-09 19:30:19</wp:comment_date>
|
||||||
|
<wp:comment_date_gmt>2012-05-10 00:30:19</wp:comment_date_gmt>
|
||||||
|
<wp:comment_content><![CDATA[[...]this is a ping pack [...] ]]></wp:comment_content>
|
||||||
|
<wp:comment_approved>trash</wp:comment_approved>
|
||||||
|
<wp:comment_type>pingback</wp:comment_type>
|
||||||
|
<wp:comment_parent>0</wp:comment_parent>
|
||||||
|
<wp:comment_user_id>0</wp:comment_user_id>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_history</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:4:{s:4:"time";s:15:"1336610793.7343";s:7:"message";s:39:"bob changed the comment status to trash";s:5:"event";s:12:"status-trash";s:4:"user";s:3:"bob";}]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>_wp_trash_meta_status</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[0]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>_wp_trash_meta_time</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[1336610793]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
</wp:comment>
|
||||||
|
<wp:comment>
|
||||||
|
<wp:comment_id>122</wp:comment_id>
|
||||||
|
<wp:comment_author><![CDATA[bob]]></wp:comment_author>
|
||||||
|
<wp:comment_author_email>bob@thisisa.test</wp:comment_author_email>
|
||||||
|
<wp:comment_author_url></wp:comment_author_url>
|
||||||
|
<wp:comment_author_IP>127.0.0.1</wp:comment_author_IP>
|
||||||
|
<wp:comment_date>2012-05-07 14:11:34</wp:comment_date>
|
||||||
|
<wp:comment_date_gmt>2012-05-07 19:11:34</wp:comment_date_gmt>
|
||||||
|
<wp:comment_content><![CDATA[Comment content.]]></wp:comment_content>
|
||||||
|
<wp:comment_approved>1</wp:comment_approved>
|
||||||
|
<wp:comment_type></wp:comment_type>
|
||||||
|
<wp:comment_parent>121</wp:comment_parent>
|
||||||
|
<wp:comment_user_id>3</wp:comment_user_id>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_result</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[false]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_history</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:4:{s:4:"time";s:15:"1336417895.1821";s:7:"message";s:28:"Akismet cleared this comment";s:5:"event";s:9:"check-ham";s:4:"user";s:3:"bob";}]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
<wp:commentmeta>
|
||||||
|
<wp:meta_key>akismet_as_submitted</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[a:65:{s:15:"comment_post_ID";s:3:"422";s:14:"comment_author";s:3:"bob";s:20:"comment_author_email";s:25:"bob@thisisa.test";s:18:"comment_author_url";s:0:"";s:15:"comment_content";s:832:"Comment content";s:12:"comment_type";s:0:"";s:14:"comment_parent";s:3:"121";s:7:"user_ID";s:1:"3";s:7:"user_ip";s:14:"127.0.0.1";s:10:"user_agent";s:139:"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/12.04 Chromium/127.0.0.1 Chrome/127.0.0.1 Safari/535.19";s:8:"referrer";s:62:"http://thisisa.test/htop-un-visualiseur-interactif-de-process/";s:4:"blog";s:19:"http://thisisa.test";s:9:"blog_lang";s:5:"en_US";s:12:"blog_charset";s:5:"UTF-8";s:9:"permalink";s:62:"http://thisisa.test/htop-un-visualiseur-interactif-de-process/";s:9:"user_role";s:13:"administrator";s:21:"akismet_comment_nonce";s:6:"passed";s:12:"POST_comment";s:832:"Comment content.";s:11:"POST_submit";s:14:"Submit Comment";s:20:"POST_comment_post_ID";s:3:"422";s:19:"POST_comment_parent";s:3:"121";s:32:"POST__wp_unfiltered_html_comment";s:10:"9dacc22ee8";s:26:"POST_akismet_comment_nonce";s:10:"b9cbdae553";s:15:"SERVER_SOFTWARE";s:12:"nginx/0.8.55";s:11:"REQUEST_URI";s:21:"/wp-comments-post.php";s:4:"TERM";s:5:"xterm";s:17:"PHP_FCGI_CHILDREN";s:1:"4";s:4:"PATH";s:29:"/sbin:/usr/sbin:/bin:/usr/bin";s:1:"_";s:25:"/usr/local/bin/spawn-fcgi";s:3:"PWD";s:1:"/";s:4:"LANG";s:11:"en_US.UTF-8";s:5:"SHLVL";s:1:"2";s:21:"PHP_FCGI_MAX_REQUESTS";s:4:"1000";s:9:"FCGI_ROLE";s:9:"RESPONDER";s:12:"QUERY_STRING";s:0:"";s:14:"REQUEST_METHOD";s:4:"POST";s:12:"CONTENT_TYPE";s:33:"application/x-www-form-urlencoded";s:14:"CONTENT_LENGTH";s:4:"1143";s:11:"SCRIPT_NAME";s:21:"/wp-comments-post.php";s:12:"DOCUMENT_URI";s:21:"/wp-comments-post.php";s:13:"DOCUMENT_ROOT";s:14:"/home/blog";s:15:"SERVER_PROTOCOL";s:8:"HTTP/1.1";s:17:"GATEWAY_INTERFACE";s:7:"CGI/1.1";s:11:"REMOTE_ADDR";s:14:"127.0.0.1";s:11:"REMOTE_PORT";s:5:"10834";s:11:"SERVER_ADDR";s:13:"127.0.0.1";s:11:"SERVER_PORT";s:2:"80";s:11:"SERVER_NAME";s:12:"thisisa.test";s:15:"REDIRECT_STATUS";s:3:"200";s:15:"SCRIPT_FILENAME";s:35:"/home/blog/wp-comments-post.php";s:9:"HTTP_HOST";s:12:"thisisa.test";s:15:"HTTP_CONNECTION";s:10:"keep-alive";s:19:"HTTP_CONTENT_LENGTH";s:4:"1143";s:18:"HTTP_CACHE_CONTROL";s:9:"john-age=0";s:11:"HTTP_ORIGIN";s:19:"http://thisisa.test";s:15:"HTTP_USER_AGENT";s:139:"Mozilla/5.0 (X11; Linux i686) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/12.04 Chromium/127.0.0.1 Chrome/127.0.0.1 Safari/535.19";s:17:"HTTP_CONTENT_TYPE";s:33:"application/x-www-form-urlencoded";s:11:"HTTP_ACCEPT";s:63:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";s:12:"HTTP_REFERER";s:62:"http://thisisa.test/htop-un-visualiseur-interactif-de-process/";s:20:"HTTP_ACCEPT_ENCODING";s:17:"gzip,deflate,sdch";s:20:"HTTP_ACCEPT_LANGUAGE";s:35:"fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4";s:19:"HTTP_ACCEPT_CHARSET";s:30:"ISO-8859-1,utf-8;q=0.7,*;q=0.3";s:11:"HTTP_COOKIE";s:0:"";s:8:"PHP_SELF";s:21:"/wp-comments-post.php";s:12:"REQUEST_TIME";s:10:"1336417893";}]]></wp:meta_value>
|
||||||
|
</wp:commentmeta>
|
||||||
|
</wp:comment>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Post with raw data</title>
|
||||||
|
<link>http://thisisa.test/?p=173</link>
|
||||||
|
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=173</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[<h1>Pelicans are scary</h1>
|
||||||
|
|
||||||
|
Pelicans are supposed to eat fish, damn it!
|
||||||
|
|
||||||
|
<iframe width="420" height="315" src="http://www.youtube.com/embed/QNNl_uWmQXE" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
||||||
|
Bottom line: don't mess up with birds]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>173</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-16 15:52:55</wp:post_date>
|
||||||
|
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>post-with-raw-data</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-2"><![CDATA[Category 2]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>A normal post with some <html> entities in the title. You can't miss them.</title>
|
||||||
|
<link>http://thisisa.test/?p=175</link>
|
||||||
|
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=175</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
<li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>175</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-16 15:52:55</wp:post_date>
|
||||||
|
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>html-entity-test</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-2"><![CDATA[Category 2]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<title>Code in List</title>
|
||||||
|
<link>http://thisisa.test/?p=175</link>
|
||||||
|
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
|
||||||
|
<dc:creator>bob</dc:creator>
|
||||||
|
<guid isPermaLink="false">http://thisisa.test/?p=175</guid>
|
||||||
|
<description></description>
|
||||||
|
<content:encoded><![CDATA[Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>List Item One!</li>
|
||||||
|
<li>List Item Two!</li>
|
||||||
|
<li>This is a code sample
|
||||||
|
<pre>
|
||||||
|
<code>
|
||||||
|
a = [1, 2, 3]
|
||||||
|
b = [4, 5, 6]
|
||||||
|
for i in zip(a, b):
|
||||||
|
print i
|
||||||
|
</code>
|
||||||
|
</pre></li>
|
||||||
|
<li>List Item Four!</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
||||||
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
||||||
|
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
||||||
|
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
||||||
|
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
||||||
|
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.]]></content:encoded>
|
||||||
|
<excerpt:encoded><![CDATA[]]></excerpt:encoded>
|
||||||
|
<wp:post_id>175</wp:post_id>
|
||||||
|
<wp:post_date>2012-02-16 15:52:55</wp:post_date>
|
||||||
|
<wp:post_date_gmt>0000-00-00 00:00:00</wp:post_date_gmt>
|
||||||
|
<wp:comment_status>open</wp:comment_status>
|
||||||
|
<wp:ping_status>open</wp:ping_status>
|
||||||
|
<wp:post_name>code-in-list-test</wp:post_name>
|
||||||
|
<wp:status>publish</wp:status>
|
||||||
|
<wp:post_parent>0</wp:post_parent>
|
||||||
|
<wp:menu_order>0</wp:menu_order>
|
||||||
|
<wp:post_type>post</wp:post_type>
|
||||||
|
<wp:post_password></wp:post_password>
|
||||||
|
<wp:is_sticky>0</wp:is_sticky>
|
||||||
|
<category domain="category" nicename="category-2"><![CDATA[Category 2]]></category>
|
||||||
|
<wp:postmeta>
|
||||||
|
<wp:meta_key>_edit_last</wp:meta_key>
|
||||||
|
<wp:meta_value><![CDATA[3]]></wp:meta_value>
|
||||||
|
</wp:postmeta>
|
||||||
|
</item>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
45
pelican/tests/default_conf.py
Normal file
45
pelican/tests/default_conf.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import unicode_literals, print_function
|
||||||
|
AUTHOR = 'Alexis Métaireau'
|
||||||
|
SITENAME = "Alexis' log"
|
||||||
|
SITEURL = 'http://blog.notmyidea.org'
|
||||||
|
TIMEZONE = 'UTC'
|
||||||
|
|
||||||
|
GITHUB_URL = 'http://github.com/ametaireau/'
|
||||||
|
DISQUS_SITENAME = "blog-notmyidea"
|
||||||
|
PDF_GENERATOR = False
|
||||||
|
REVERSE_CATEGORY_ORDER = True
|
||||||
|
LOCALE = ""
|
||||||
|
DEFAULT_PAGINATION = 2
|
||||||
|
|
||||||
|
FEED_RSS = 'feeds/all.rss.xml'
|
||||||
|
CATEGORY_FEED_RSS = 'feeds/%s.rss.xml'
|
||||||
|
|
||||||
|
LINKS = (('Biologeek', 'http://biologeek.org'),
|
||||||
|
('Filyb', "http://filyb.info/"),
|
||||||
|
('Libert-fr', "http://www.libert-fr.com"),
|
||||||
|
('N1k0', "http://prendreuncafe.com/blog/"),
|
||||||
|
('Tarek Ziadé', "http://ziade.org/blog"),
|
||||||
|
('Zubin Mithra', "http://zubin71.wordpress.com/"),)
|
||||||
|
|
||||||
|
SOCIAL = (('twitter', 'http://twitter.com/ametaireau'),
|
||||||
|
('lastfm', 'http://lastfm.com/user/akounet'),
|
||||||
|
('github', 'http://github.com/ametaireau'),)
|
||||||
|
|
||||||
|
# global metadata to all the contents
|
||||||
|
DEFAULT_METADATA = (('yeah', 'it is'),)
|
||||||
|
|
||||||
|
# path-specific metadata
|
||||||
|
EXTRA_PATH_METADATA = {
|
||||||
|
'extra/robots.txt': {'path': 'robots.txt'},
|
||||||
|
}
|
||||||
|
|
||||||
|
# static paths will be copied without parsing their contents
|
||||||
|
STATIC_PATHS = [
|
||||||
|
'pictures',
|
||||||
|
'extra/robots.txt',
|
||||||
|
]
|
||||||
|
|
||||||
|
# foobar will not be used, because it's not in caps. All configuration keys
|
||||||
|
# have to be in caps
|
||||||
|
foobar = "barbaz"
|
||||||
68
pelican/tests/output/basic/a-markdown-powered-article.html
Normal file
68
pelican/tests/output/basic/a-markdown-powered-article.html
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>A markdown powered article</title>
|
||||||
|
<link rel="stylesheet" href="/theme/css/main.css">
|
||||||
|
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
|
||||||
|
|
||||||
|
<!--[if IE]>
|
||||||
|
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body id="index" class="home">
|
||||||
|
<header id="banner" class="body">
|
||||||
|
<h1><a href="/">A Pelican Blog </a></h1>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/override/">Override url/save_as</a></li>
|
||||||
|
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
|
||||||
|
<li ><a href="/category/bar.html">bar</a></li>
|
||||||
|
<li class="active"><a href="/category/cat1.html">cat1</a></li>
|
||||||
|
<li ><a href="/category/misc.html">misc</a></li>
|
||||||
|
<li ><a href="/category/yeah.html">yeah</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
</header><!-- /#banner -->
|
||||||
|
<section id="content" class="body">
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1 class="entry-title">
|
||||||
|
<a href="/a-markdown-powered-article.html" rel="bookmark"
|
||||||
|
title="Permalink to A markdown powered article">A markdown powered article</a></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="entry-content">
|
||||||
|
<footer class="post-info">
|
||||||
|
<abbr class="published" title="2011-04-20T00:00:00">
|
||||||
|
Wed 20 April 2011
|
||||||
|
</abbr>
|
||||||
|
|
||||||
|
<p>In <a href="/category/cat1.html">cat1</a>. </p>
|
||||||
|
|
||||||
|
</footer><!-- /.post-info --> <p>You're mutually oblivious.</p>
|
||||||
|
<p><a href="/unbelievable.html">a root-relative link to unbelievable</a>
|
||||||
|
<a href="/unbelievable.html">a file-relative link to unbelievable</a></p>
|
||||||
|
</div><!-- /.entry-content -->
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
<section id="extras" class="body">
|
||||||
|
<div class="social">
|
||||||
|
<h2>social</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.social -->
|
||||||
|
</section><!-- /#extras -->
|
||||||
|
|
||||||
|
<footer id="contentinfo" class="body">
|
||||||
|
<address id="about" class="vcard body">
|
||||||
|
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||||
|
</address><!-- /#about -->
|
||||||
|
|
||||||
|
<p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
|
||||||
|
</footer><!-- /#contentinfo -->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
69
pelican/tests/output/basic/archives.html
Normal file
69
pelican/tests/output/basic/archives.html
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>A Pelican Blog</title>
|
||||||
|
<link rel="stylesheet" href="/theme/css/main.css">
|
||||||
|
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
|
||||||
|
|
||||||
|
<!--[if IE]>
|
||||||
|
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body id="index" class="home">
|
||||||
|
<header id="banner" class="body">
|
||||||
|
<h1><a href="/">A Pelican Blog </a></h1>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/override/">Override url/save_as</a></li>
|
||||||
|
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
|
||||||
|
<li ><a href="/category/bar.html">bar</a></li>
|
||||||
|
<li ><a href="/category/cat1.html">cat1</a></li>
|
||||||
|
<li ><a href="/category/misc.html">misc</a></li>
|
||||||
|
<li ><a href="/category/yeah.html">yeah</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
</header><!-- /#banner -->
|
||||||
|
<section id="content" class="body">
|
||||||
|
<h1>Archives for A Pelican Blog</h1>
|
||||||
|
|
||||||
|
<dl>
|
||||||
|
<dt>Fri 30 November 2012</dt>
|
||||||
|
<dd><a href="/filename_metadata-example.html">FILENAME_METADATA example</a></dd>
|
||||||
|
<dt>Wed 29 February 2012</dt>
|
||||||
|
<dd><a href="/second-article.html">Second article</a></dd>
|
||||||
|
<dt>Wed 20 April 2011</dt>
|
||||||
|
<dd><a href="/a-markdown-powered-article.html">A markdown powered article</a></dd>
|
||||||
|
<dt>Thu 17 February 2011</dt>
|
||||||
|
<dd><a href="/article-1.html">Article 1</a></dd>
|
||||||
|
<dt>Thu 17 February 2011</dt>
|
||||||
|
<dd><a href="/article-2.html">Article 2</a></dd>
|
||||||
|
<dt>Thu 17 February 2011</dt>
|
||||||
|
<dd><a href="/article-3.html">Article 3</a></dd>
|
||||||
|
<dt>Thu 02 December 2010</dt>
|
||||||
|
<dd><a href="/this-is-a-super-article.html">This is a super article !</a></dd>
|
||||||
|
<dt>Wed 20 October 2010</dt>
|
||||||
|
<dd><a href="/oh-yeah.html">Oh yeah !</a></dd>
|
||||||
|
<dt>Fri 15 October 2010</dt>
|
||||||
|
<dd><a href="/unbelievable.html">Unbelievable !</a></dd>
|
||||||
|
</dl>
|
||||||
|
</section>
|
||||||
|
<section id="extras" class="body">
|
||||||
|
<div class="social">
|
||||||
|
<h2>social</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.social -->
|
||||||
|
</section><!-- /#extras -->
|
||||||
|
|
||||||
|
<footer id="contentinfo" class="body">
|
||||||
|
<address id="about" class="vcard body">
|
||||||
|
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||||
|
</address><!-- /#about -->
|
||||||
|
|
||||||
|
<p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
|
||||||
|
</footer><!-- /#contentinfo -->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
67
pelican/tests/output/basic/article-1.html
Normal file
67
pelican/tests/output/basic/article-1.html
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Article 1</title>
|
||||||
|
<link rel="stylesheet" href="/theme/css/main.css">
|
||||||
|
<link href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate" title="A Pelican Blog Atom Feed" />
|
||||||
|
|
||||||
|
<!--[if IE]>
|
||||||
|
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body id="index" class="home">
|
||||||
|
<header id="banner" class="body">
|
||||||
|
<h1><a href="/">A Pelican Blog </a></h1>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/override/">Override url/save_as</a></li>
|
||||||
|
<li><a href="/pages/this-is-a-test-page.html">This is a test page</a></li>
|
||||||
|
<li ><a href="/category/bar.html">bar</a></li>
|
||||||
|
<li class="active"><a href="/category/cat1.html">cat1</a></li>
|
||||||
|
<li ><a href="/category/misc.html">misc</a></li>
|
||||||
|
<li ><a href="/category/yeah.html">yeah</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
</header><!-- /#banner -->
|
||||||
|
<section id="content" class="body">
|
||||||
|
<article>
|
||||||
|
<header>
|
||||||
|
<h1 class="entry-title">
|
||||||
|
<a href="/article-1.html" rel="bookmark"
|
||||||
|
title="Permalink to Article 1">Article 1</a></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="entry-content">
|
||||||
|
<footer class="post-info">
|
||||||
|
<abbr class="published" title="2011-02-17T00:00:00">
|
||||||
|
Thu 17 February 2011
|
||||||
|
</abbr>
|
||||||
|
|
||||||
|
<p>In <a href="/category/cat1.html">cat1</a>. </p>
|
||||||
|
|
||||||
|
</footer><!-- /.post-info --> <p>Article 1</p>
|
||||||
|
|
||||||
|
</div><!-- /.entry-content -->
|
||||||
|
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
<section id="extras" class="body">
|
||||||
|
<div class="social">
|
||||||
|
<h2>social</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/feeds/all.atom.xml" type="application/atom+xml" rel="alternate">atom feed</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div><!-- /.social -->
|
||||||
|
</section><!-- /#extras -->
|
||||||
|
|
||||||
|
<footer id="contentinfo" class="body">
|
||||||
|
<address id="about" class="vcard body">
|
||||||
|
Proudly powered by <a href="http://getpelican.com/">Pelican</a>, which takes great advantage of <a href="http://python.org">Python</a>.
|
||||||
|
</address><!-- /#about -->
|
||||||
|
|
||||||
|
<p>The theme is by <a href="http://coding.smashingmagazine.com/2009/08/04/designing-a-html-5-layout-from-scratch/">Smashing Magazine</a>, thanks!</p>
|
||||||
|
</footer><!-- /#contentinfo -->
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue