From 387e5c1ab987feaecfad6e6383e94130d6a085f8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 25 Jun 2012 08:57:09 -0400 Subject: [PATCH 01/19] Add upgrade ability to pelican-themes. Fix typos. I disliked having to do: $ pelican-theme -r -i So I modified install() to handle an upgrade of an existing theme. While doing so, I noticed that in install() and symlink() the script would error with 'no a directory' instead of 'not a directory'. So I fixed that for you as well. --- pelican/tools/pelican_themes.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/pelican/tools/pelican_themes.py b/pelican/tools/pelican_themes.py index 3d35bb5d..a7e0470f 100755 --- a/pelican/tools/pelican_themes.py +++ b/pelican/tools/pelican_themes.py @@ -48,9 +48,11 @@ def main(): parser.add_argument('-i', '--install', dest='to_install', nargs='+', metavar="theme path", - help='The themes to install ') + help='The themes to install') parser.add_argument('-r', '--remove', dest='to_remove', nargs='+', metavar="theme name", help='The themes to remove') + parser.add_argument('-U', '--upgrade', dest='to_upgrade', nargs='+', + metavar="theme path", help='The themes to upgrade') parser.add_argument('-s', '--symlink', dest='to_symlink', nargs='+', metavar="theme path", help="Same as `--install', but create a symbolic link instead of copying the theme. Useful for theme development") parser.add_argument('-c', '--clean', dest='clean', action="store_true", @@ -85,6 +87,13 @@ def main(): for i in args.to_install: install(i, v=args.verbose) + if args.to_upgrade: + if args.verbose: + print('Upgrading themes...') + + for i in args.to_upgrade: + install(i, v=args.verbose, u=True) + if args.to_symlink: if args.verbose: print('Linking themes...') @@ -149,17 +158,21 @@ def remove(theme_name, v=False): err(target + ' : no such file or directory') -def install(path, v=False): +def install(path, v=False, u=False): """Installs a theme""" if not os.path.exists(path): err(path + ' : no such file or directory') elif not os.path.isdir(path): - err(path + ' : no a directory') + err(path + ' : not a directory') else: theme_name = os.path.basename(os.path.normpath(path)) theme_path = os.path.join(_THEMES_PATH, theme_name) - if os.path.exists(theme_path): + exists = os.path.exists(theme_path) + if exists and not u: err(path + ' : already exists') + elif exists and u: + remove(theme_name, v) + install(path, v) else: if v: print("Copying `{p}' to `{t}' ...".format(p=path, t=theme_path)) @@ -174,7 +187,7 @@ def symlink(path, v=False): if not os.path.exists(path): err(path + ' : no such file or directory') elif not os.path.isdir(path): - err(path + ' : no a directory') + err(path + ' : not a directory') else: theme_name = os.path.basename(os.path.normpath(path)) theme_path = os.path.join(_THEMES_PATH, theme_name) From 707536725da13df8ed7b167447039c738068b1c8 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 25 Jun 2012 11:43:12 -0400 Subject: [PATCH 02/19] Failed to commit some important changes. --- pelican/tools/pelican_themes.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pelican/tools/pelican_themes.py b/pelican/tools/pelican_themes.py index a7e0470f..6a021ecc 100755 --- a/pelican/tools/pelican_themes.py +++ b/pelican/tools/pelican_themes.py @@ -64,6 +64,9 @@ def main(): args = parser.parse_args() + + to_install = args.to_install or args.to_upgrade + to_sym = args.to_symlink or args.clean if args.action: @@ -71,8 +74,7 @@ def main(): list_themes(args.verbose) elif args.action is 'path': print(_THEMES_PATH) - elif args.to_install or args.to_remove or args.to_symlink or args.clean: - + elif to_install or args.to_remove or to_sym: if args.to_remove: if args.verbose: print('Removing themes...') From b2ff07d58cc0949cba20da5b4ceffe8979a6c479 Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Tue, 26 Jun 2012 16:28:00 +0200 Subject: [PATCH 03/19] we need jinja >= 2.4 --- dev_requirements.txt | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev_requirements.txt b/dev_requirements.txt index ef1dbf31..ec3245d1 100644 --- a/dev_requirements.txt +++ b/dev_requirements.txt @@ -1,4 +1,4 @@ -Jinja2 +Jinja2>=2.4 Pygments docutils feedgenerator diff --git a/setup.py b/setup.py index a8a8fbd9..1603746e 100755 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python from setuptools import setup -requires = ['feedgenerator', 'jinja2', 'pygments', 'docutils', 'pytz', 'blinker'] +requires = ['feedgenerator', 'jinja2 >= 2.4', 'pygments', 'docutils', 'pytz', 'blinker'] try: import argparse From a0e46c91066bd8338d0e067875d6e040fec88477 Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Tue, 26 Jun 2012 19:26:43 -0700 Subject: [PATCH 04/19] Add support for `status: hidden` in pages Resolves #380 If the status metadata is set to 'hidden' on a page it is translated and rendered but not linked anywhere in the site. --- docs/getting_started.rst | 4 ++++ pelican/generators.py | 17 +++++++++++++++-- samples/content/pages/hidden_page.rst | 9 +++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 samples/content/pages/hidden_page.rst diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 8accf658..580c43a1 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -136,6 +136,10 @@ generate static pages. Then, use the `DISPLAY_PAGES_ON_MENU` setting, which will add all the pages to the menu. +If you want to exclude any pages from being linked to or listed in the menu +then add a ``status: hidden`` attribute to it's metadata. This is useful for +things like making error pages that fit the generated theme of your site. + Importing an existing blog -------------------------- diff --git a/pelican/generators.py b/pelican/generators.py index 1ddc13c2..6790fcd6 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -357,10 +357,13 @@ class PagesGenerator(Generator): def __init__(self, *args, **kwargs): self.pages = [] + self.hidden_pages = [] + self.hidden_translations = [] super(PagesGenerator, self).__init__(*args, **kwargs) def generate_context(self): all_pages = [] + hidden_pages = [] for f in self.get_files( os.path.join(self.path, self.settings['PAGE_DIR']), exclude=self.settings['PAGE_EXCLUDES']): @@ -373,15 +376,25 @@ class PagesGenerator(Generator): filename=f) if not is_valid_content(page, f): continue - all_pages.append(page) + if page.status == "published": + all_pages.append(page) + elif page.status == "hidden": + hidden_pages.append(page) + else: + logger.warning(u"Unknown status %s for file %s, skipping it." % + (repr(unicode.encode(article.status, 'utf-8')), + 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 def generate_output(self, writer): - for page in chain(self.translations, self.pages): + for page in chain(self.translations, self.pages, + self.hidden_translations, self.hidden_pages): writer.write_file(page.save_as, self.get_template('page'), self.context, page=page, relative_urls=self.settings.get('RELATIVE_URLS')) diff --git a/samples/content/pages/hidden_page.rst b/samples/content/pages/hidden_page.rst new file mode 100644 index 00000000..ab8704ed --- /dev/null +++ b/samples/content/pages/hidden_page.rst @@ -0,0 +1,9 @@ +This is a test hidden page +########################## + +:category: test +:status: hidden + +This is great for things like error(404) pages +Anyone can see this page but it's not linked to anywhere! + From de251bc9998b1245238e69707c21a0dd5143756b Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Tue, 26 Jun 2012 19:51:48 -0700 Subject: [PATCH 05/19] Fixes typo in error message for bad status Bugfix #380 We want the bad status of page, not article. --- pelican/generators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pelican/generators.py b/pelican/generators.py index 6790fcd6..4e9312cc 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -382,7 +382,7 @@ class PagesGenerator(Generator): hidden_pages.append(page) else: logger.warning(u"Unknown status %s for file %s, skipping it." % - (repr(unicode.encode(article.status, 'utf-8')), + (repr(unicode.encode(page.status, 'utf-8')), repr(f))) From c2993c4d4e19b1eceb3c367c38005dd89d04b53c Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 27 Jun 2012 07:02:25 -0700 Subject: [PATCH 06/19] Documentation typo --- docs/getting_started.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 580c43a1..96038c2a 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -137,7 +137,7 @@ Then, use the `DISPLAY_PAGES_ON_MENU` setting, which will add all the pages to the menu. If you want to exclude any pages from being linked to or listed in the menu -then add a ``status: hidden`` attribute to it's metadata. This is useful for +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. Importing an existing blog From 9ad93d36a0cff5e684bff5f4ca9f6b7080ea42d7 Mon Sep 17 00:00:00 2001 From: Justin Mayer Date: Sun, 1 Jul 2012 10:52:39 -0700 Subject: [PATCH 07/19] Convert code in docs to inline literals Most of the references to code and settings in the docs were wrapped in single tickmarks (`), while reStructuredText syntax actually calls for double tickmarks for inline literals, which are normally rendered as monospaced text with spaces preserved. Converted the relevant instances to inline literals, along with some other minor fixes. --- docs/faq.rst | 6 +-- docs/getting_started.rst | 36 +++++++-------- docs/internals.rst | 40 ++++++++-------- docs/plugins.rst | 26 +++++------ docs/report.rst | 99 ++++++++++++++++++++-------------------- docs/themes.rst | 9 ++-- docs/tips.rst | 26 +++++------ 7 files changed, 119 insertions(+), 123 deletions(-) diff --git a/docs/faq.rst b/docs/faq.rst index b3dbca87..a3829d65 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -8,14 +8,14 @@ Is it mandatory to have a configuration file? No, it's not. Configuration files 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. +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 `.codehilite pre` +customize the appearance of your syntax highlighting via the ``.codehilite pre`` class in your theme's CSS file. To see how various styles can be used to render Django code, for example, you can use the demo `on the project website `_. @@ -30,7 +30,7 @@ How can I help? There are several ways to help out. First, you can use Pelican and report any suggestions or problems you might have on `the bugtracker -`_. +`_. If you want to contribute, please fork `the git repository `_, make your changes, and issue diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 8accf658..cd186a1c 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -38,7 +38,7 @@ 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 +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 @@ -55,7 +55,7 @@ At this time, Pelican is dependent on the following Python packages: * jinja2, for templating support * docutils, for supporting reStructuredText as an input format -If you're not using Python 2.7, you will also need `argparse`. +If you're not using Python 2.7, you will also need the ``argparse`` package. Optionally: @@ -73,7 +73,7 @@ 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. You can provide this metadata in reStructuredText text files via the -following syntax (give your file the `.rst` extension):: +following syntax (give your file the ``.rst`` extension):: My super title ############## @@ -84,9 +84,9 @@ following syntax (give your file the `.rst` extension):: :author: Alexis Metaireau -You can also use Markdown syntax (with a file ending in `.md`). -Markdown generation will not work until you explicitly install the `Markdown` -package, which can be done via `pip install Markdown`. Metadata syntax for +You can also use Markdown syntax (with a file ending in ``.md``). +Markdown generation will not work until you explicitly install the ``Markdown`` +package, which can be done via ``pip install Markdown``. Metadata syntax for Markdown posts should follow this pattern:: Date: 2010-12-03 @@ -99,17 +99,17 @@ Markdown posts should follow this pattern:: Note that, aside from the title, none of this metadata is mandatory: if the date is not specified, 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`. +example, a file located at ``python/foobar/myfoobar.rst`` will have a category of +``foobar``. Generate your blog ------------------ -To launch Pelican, just use the `pelican` command:: +To launch Pelican, just use the ``pelican`` command:: $ pelican /path/to/your/content/ [-s path/to/your/settings.py] -And… that's all! Your weblog will be generated and saved in the `content/` +And… that's all! Your weblog will be generated and saved in the ``content/`` folder. The above command will use the default theme to produce a simple site. It's not @@ -123,17 +123,17 @@ the options you can use:: Kickstart a blog ---------------- -You also can use the `pelican-quickstart` script to start a new blog in -seconds by just answering a few questions. Just run `pelican-quickstart` and +You also can use the ``pelican-quickstart`` script to start a new blog in +seconds by just answering a few questions. Just run ``pelican-quickstart`` and you're done! (Added in Pelican 3.0) Pages ----- -If you create a folder named `pages`, all the files in it will be used to +If you create a folder named ``pages``, all the files in it will be used to generate static pages. -Then, use the `DISPLAY_PAGES_ON_MENU` setting, which will add all the pages to +Then, use the ``DISPLAY_PAGES_ON_MENU`` setting, which will add all the pages to the menu. Importing an existing blog @@ -145,8 +145,8 @@ 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 +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. @@ -210,7 +210,7 @@ Auto-reload It's possible to tell Pelican to watch for your modifications, instead of manually re-running it every time you want to see your changes. To enable this, -run the `pelican` command with the `-r` or `--autoreload` option. +run the ``pelican`` command with the ``-r`` or ``--autoreload`` option. Publishing drafts ----------------- @@ -235,4 +235,4 @@ Or run a simple web server using Python:: cd output && python -m SimpleHTTPServer (Tip: If using the latter method in conjunction with the auto-reload feature, -ensure that `DELETE_OUTPUT_DIRECTORY` is set to `False` in your settings file.) +ensure that ``DELETE_OUTPUT_DIRECTORY`` is set to ``False`` in your settings file.) diff --git a/docs/internals.rst b/docs/internals.rst index f0934825..6b6f991f 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -12,34 +12,34 @@ original author wrote with some software design information. Overall structure ================= -What `pelican` does is take a list of files and process them into some +What Pelican does is take a list of files and process them into some sort of output. Usually, the input files are reStructuredText and Markdown 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 +* **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 (Markdown and +* **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 - `ArticlesGenerator` and `PageGenerator`. Given a configuration, they can do +* **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`, and, trust me, really easy to learn, so don't hesitate - to jump in and build your own theme. +* Pelican also uses templates, so it's easy to write your own theme. The + syntax is `Jinja2 `_ 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` +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:: @@ -65,8 +65,8 @@ Take a look at the Markdown reader:: 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. +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. @@ -76,17 +76,17 @@ 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. +* ``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. + 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, +* ``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 + 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. + the disk (using the writer method ``write_file``) for each page encountered. diff --git a/docs/plugins.rst b/docs/plugins.rst index db5a4bfc..3e009e33 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -3,14 +3,14 @@ Plugins ####### -Since version 3.0, pelican manages plugins. Plugins are a way to add features -to pelican without having to directly hack pelican code. +Since version 3.0, Pelican manages plugins. Plugins are a way to add features +to Pelican without having to directly hack Pelican code. Pelican is shipped with a set of core plugins, but you can easily implement your own (and this page describes how). -How to use plugins? -==================== +How to use plugins +================== To load plugins, you have to specify them in your settings file. You have two ways to do so. @@ -23,21 +23,21 @@ Or by importing them and adding them to the list:: from pelican.plugins import gravatar PLUGINS = [gravatar, ] -If your plugins are not in an importable path, you can specify a `PLUGIN_PATH` +If your plugins are not in an importable path, you can specify a ``PLUGIN_PATH`` in the settings:: PLUGIN_PATH = "plugins" PLUGINS = ["list", "of", "plugins"] -How to create plugins? -====================== +How to create plugins +===================== -Plugins are based on the concept of signals. Pelican sends signals and 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 following 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 exemple:: +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 @@ -68,7 +68,7 @@ List of plugins =============== Not all the list are described here, but a few of them have been extracted from -pelican core and provided in pelican.plugins. They are described here: +the Pelican core and provided in ``pelican.plugins``. They are described here: Tag cloud --------- @@ -82,7 +82,7 @@ Github Activity This plugin makes use of the ``feedparser`` library that you'll need to install. -Set the GITHUB_ACTIVITY_FEED parameter to your github activity feed. +Set the ``GITHUB_ACTIVITY_FEED`` parameter to your Github activity feed. For example, my setting would look like:: GITHUB_ACTIVITY_FEED = 'https://github.com/kpanic.atom' @@ -105,4 +105,4 @@ variable, as in the example:: ``github_activity`` is a list of lists. The first element is the title -and the second element is the raw html from github. +and the second element is the raw HTML from Github. diff --git a/docs/report.rst b/docs/report.rst index 7e0432e2..f12f3048 100644 --- a/docs/report.rst +++ b/docs/report.rst @@ -1,40 +1,40 @@ -Some history about pelican +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. + 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 restructured text for now), and generate a HTML folder +(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 +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. +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 +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. +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. +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 +language you want, and then generate a static HTML weblog. .. image:: _static/overall.png -To be flexible enough, pelican have a template support, so you can -easily write you own themes if you want to. +To be flexible enough, Pelican has template support, so you can easily write +your own themes if you want to. Design process ============== @@ -42,19 +42,18 @@ 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 have created the content I wanted to parse (the restructured -text 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. +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 +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 +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: @@ -64,59 +63,59 @@ I’ve separated the logic in different classes and concepts: 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 - Restructured Text for now, but the system is extensible). Given a - file, they return metadata (author, tags, category etc) and - content (HTML formated). +* *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 +* *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 + 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. +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 details -=============== +In more detail +============== -Here is an overview of the classes involved in pelican. +Here is an overview of the classes involved in Pelican. .. image:: _static/uml.jpg -The interface do not really exists, and I have added it only to clarify the -whole picture. I do use duck typing, and not interfaces. +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 are used to initialize the different generator objects. + the user is used to initialize the different generator objects. -* A `context` is created. It contains the settings from the command +* 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 ``generate_context`` method of each generator is called, updating the context. -* The writer is created, and given to the `generate_output` method of +* 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. +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` +``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. + 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 +Then, the ``generate_content`` method uses the ``context`` and the ``writer`` to +generate the wanted output. diff --git a/docs/themes.rst b/docs/themes.rst index e0583882..8e432a95 100644 --- a/docs/themes.rst +++ b/docs/themes.rst @@ -3,11 +3,10 @@ How to create themes for Pelican ################################ -Pelican uses the great `jinja2 `_ templating engine to -generate its HTML output. The jinja2 syntax is really simple. If you want to -create your own theme, feel free to take inspiration from the "simple" theme, -which is available `here -`_ +Pelican uses the great `Jinja2 `_ 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 +`_. Structure ========= diff --git a/docs/tips.rst b/docs/tips.rst index 14a79a5e..8905103b 100644 --- a/docs/tips.rst +++ b/docs/tips.rst @@ -12,16 +12,16 @@ file generator, we can take advantage of this. User Pages ---------- -Github allows you to create user pages in the form of ``username.github.com``. -Whatever is created in master branch will be published. For this purposes just -the output generated by pelican needs to pushed at github. +GitHub allows you to create user pages in the form of ``username.github.com``. +Whatever is created in the master branch will be published. For this purpose, +just the output generated by Pelican needs to pushed to GitHub. -So given a repository containing your articles, just run pelican over the posts -and deploy the master branch at github:: +So given a repository containing your articles, just run Pelican over the posts +and deploy the master branch to GitHub:: $ pelican -s pelican.conf.py ./path/to/posts -o /path/to/output -Now add all the files in the output directory generated by pelican:: +Now add all the files in the output directory generated by Pelican:: $ git add /path/to/output/* $ git commit -am "Your Message" @@ -31,12 +31,12 @@ Project Pages ------------- For creating Project pages, a branch called ``gh-pages`` is used for publishing. The excellent `ghp-import `_ makes this -really easy. You will have to install it:: +really easy, which can be installed via:: $ pip install ghp-import -Then, given a repository containing your articles, you would simply have -to run Pelican and upload the output to GitHub:: +Then, given a repository containing your articles, you would simply run +Pelican and upload the output to GitHub:: $ pelican -s pelican.conf.py . $ ghp-import output @@ -45,10 +45,8 @@ to run Pelican and upload the output to GitHub:: And that's it. If you want, you can put that directly into a post-commit hook, so each time you -commit, your blog is up to date on GitHub! +commit, your blog is up-to-date on GitHub! -Put the following into `.git/hooks/post-commit`:: - - pelican -s pelican.conf.py . && ghp-import output && git push origin - gh-pages +Put the following into ``.git/hooks/post-commit``:: + pelican -s pelican.conf.py . && ghp-import output && git push origin gh-pages From 8a53ee1ad36e88604f976ab176ab309fb852eb79 Mon Sep 17 00:00:00 2001 From: Alexandre RODIERE Date: Tue, 3 Jul 2012 15:19:38 +0200 Subject: [PATCH 08/19] Fix typo on debug logger calls. --- pelican/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pelican/__init__.py b/pelican/__init__.py index 6dc7dd36..d42526a3 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -68,10 +68,10 @@ class Pelican(object): for plugin in self.plugins: # if it's a string, then import it if isinstance(plugin, basestring): - log.debug("Loading plugin `{0}' ...".format(plugin)) + logger.debug("Loading plugin `{0}' ...".format(plugin)) plugin = __import__(plugin, globals(), locals(), 'module') - log.debug("Registering plugin `{0}' ...".format(plugin.__name__)) + logger.debug("Registering plugin `{0}' ...".format(plugin.__name__)) plugin.register() def _handle_deprecation(self): From cf696939f8c49d54c8b6f5e6fa13422e3278734e Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 4 Jul 2012 10:06:53 -0700 Subject: [PATCH 09/19] Added tests for page generation. Currently tests rst & markdown generation, ignoring pages w/ bad status, and status hidden vs published --- tests/TestPages/bad_page.rst | 8 +++++ tests/TestPages/hidden_page.rst | 8 +++++ tests/TestPages/hidden_page_markdown.md | 12 +++++++ tests/TestPages/page.rst | 4 +++ tests/TestPages/page_markdown.md | 9 +++++ tests/test_generators.py | 44 ++++++++++++++++++++++++- 6 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 tests/TestPages/bad_page.rst create mode 100644 tests/TestPages/hidden_page.rst create mode 100644 tests/TestPages/hidden_page_markdown.md create mode 100644 tests/TestPages/page.rst create mode 100644 tests/TestPages/page_markdown.md diff --git a/tests/TestPages/bad_page.rst b/tests/TestPages/bad_page.rst new file mode 100644 index 00000000..bc62948b --- /dev/null +++ b/tests/TestPages/bad_page.rst @@ -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. diff --git a/tests/TestPages/hidden_page.rst b/tests/TestPages/hidden_page.rst new file mode 100644 index 00000000..57ca329c --- /dev/null +++ b/tests/TestPages/hidden_page.rst @@ -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 diff --git a/tests/TestPages/hidden_page_markdown.md b/tests/TestPages/hidden_page_markdown.md new file mode 100644 index 00000000..1e532fe7 --- /dev/null +++ b/tests/TestPages/hidden_page_markdown.md @@ -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 diff --git a/tests/TestPages/page.rst b/tests/TestPages/page.rst new file mode 100644 index 00000000..2d13976d --- /dev/null +++ b/tests/TestPages/page.rst @@ -0,0 +1,4 @@ +This is a test page +################### + +The quick brown fox jumped over the lazy dog's back. diff --git a/tests/TestPages/page_markdown.md b/tests/TestPages/page_markdown.md new file mode 100644 index 00000000..d5416a6f --- /dev/null +++ b/tests/TestPages/page_markdown.md @@ -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. diff --git a/tests/test_generators.py b/tests/test_generators.py index e62551fa..cc84c80f 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -4,7 +4,7 @@ from mock import MagicMock import os import re -from pelican.generators import ArticlesGenerator, LessCSSGenerator +from pelican.generators import ArticlesGenerator, LessCSSGenerator, PagesGenerator from pelican.settings import _DEFAULT_CONFIG from .support import unittest, temporary_folder, skipIfNoExecutable @@ -94,6 +94,48 @@ class TestArticlesGenerator(unittest.TestCase): write.assert_called_count == 0 +class TestPageGenerator(unittest.TestCase): + """ + Every time you want to test for a new field; + Make sure the test pages in "TestPages" have all the fields + Add it to distilled in distill_pages_for_test + Then update the assertItemsEqual in test_generate_context to match expected + """ + + def distill_pages_for_test(self, pages): + distilled = [] + for page in pages: + distilled.append([ + page.title, + page.status + ] + ) + return distilled + + def test_generate_context(self): + settings = _DEFAULT_CONFIG.copy() + + settings['PAGE_DIR'] = 'TestPages' + generator = PagesGenerator(settings.copy(), settings, CUR_DIR, + _DEFAULT_CONFIG['THEME'], None, + _DEFAULT_CONFIG['MARKUP']) + generator.generate_context() + pages = self.distill_pages_for_test(generator.pages) + hidden_pages = self.distill_pages_for_test(generator.hidden_pages) + + pages_expected = [ + [u'This is a test page', 'published'], + [u'This is a markdown test page', 'published'] + ] + hidden_pages_expected = [ + [u'This is a test hidden page', 'hidden'], + [u'This is a markdown test hidden page', 'hidden'] + ] + + self.assertItemsEqual(pages_expected,pages) + self.assertItemsEqual(hidden_pages_expected,hidden_pages) + + class TestLessCSSGenerator(unittest.TestCase): LESS_CONTENT = """ From d589450200c1ce9e14eefad63dc099767af64ada Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 4 Jul 2012 12:32:20 -0700 Subject: [PATCH 10/19] Change behavior of DELETE_OUTPUT_DIRECTORY to purge contents of the directory, not the directory itself. Added Debug level logging for each deletion Added error level logging when a delete has an exception Built a test case for clean_output_directory in tests.utils.py Updated `settings` in documentation to reflect new behavior Removed the tip from the bottom of getting started since this setting should no longer break web servers pointing to the output directory. --- docs/getting_started.rst | 2 -- docs/settings.rst | 4 ++-- pelican/utils.py | 20 ++++++++++++++++---- tests/test_utils.py | 11 +++++++++++ 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index cd186a1c..a0975bd5 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -234,5 +234,3 @@ Or run a simple web server using Python:: cd output && python -m SimpleHTTPServer -(Tip: If using the latter method in conjunction with the auto-reload feature, -ensure that ``DELETE_OUTPUT_DIRECTORY`` is set to ``False`` in your settings file.) diff --git a/docs/settings.rst b/docs/settings.rst index 65561d5d..c5aa7f4e 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -37,8 +37,8 @@ Setting name (default value) What doe timestamp information (mtime) if it can't get date information from the metadata. `JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use. -`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the output directory as well as - the generated files. +`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the contents of the output directory before + generating new files. `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 diff --git a/pelican/utils.py b/pelican/utils.py index 0940bf72..a1c40077 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -92,10 +92,22 @@ def clean_output_dir(path): """Remove all the files from the output directory""" # remove all the existing content from the output folder - try: - shutil.rmtree(path) - except Exception: - pass + for filename in os.listdir(path): + file = os.path.join(path, filename) + if os.path.isdir(file): + logger.debug("Deleting directory %s" % file) + try: + shutil.rmtree(file) + except Exception, e: + logger.error("Unable to delete directory %s; %e" % file, e) + elif os.path.isfile(file) or os.path.islink(file): + logger.debug("Deleting file/link %s" % file) + try: + os.remove(file) + except Exception, e: + logger.error("Unable to delete file %s; %e" % file, e) + else: + logger.error("Unable to delete %s, file type unknown" % file) def get_relative_path(filename): diff --git a/tests/test_utils.py b/tests/test_utils.py index e738e295..d2f44131 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import shutil import os import datetime import time @@ -86,3 +87,13 @@ class TestUtils(unittest.TestCase): changed = utils.files_changed(path, 'rst') self.assertEquals(changed, True) self.assertAlmostEqual(utils.LAST_MTIME, t, delta=1) + + def test_clean_output_dir(self): + test_directory = os.path.join(os.path.dirname(__file__), 'clean_output') + content = os.path.join(os.path.dirname(__file__), 'content') + shutil.copytree(content, test_directory) + utils.clean_output_dir(test_directory) + self.assertTrue(os.path.isdir(test_directory)) + self.assertListEqual([], os.listdir(test_directory)) + shutil.rmtree(test_directory) + From 2b062ce384c5e75e4af0d137351d97aea8c5ed39 Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 4 Jul 2012 14:55:39 -0700 Subject: [PATCH 11/19] Documentation typo --- docs/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index c5aa7f4e..78ede790 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -37,7 +37,7 @@ Setting name (default value) What doe timestamp information (mtime) if it can't get date information from the metadata. `JINJA_EXTENSIONS` (``[]``) A list of any Jinja2 extensions you want to use. -`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the contents of the output directory before +`DELETE_OUTPUT_DIRECTORY` (``False``) Delete the content of the output directory before generating new files. `LOCALE` (''[#]_) Change the locale. A list of locales can be provided here or a single string representing one locale. From c07821e8a210c70eef91067223cebe388481ad71 Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 4 Jul 2012 14:56:52 -0700 Subject: [PATCH 12/19] Too many empty lines at end of file --- tests/test_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index d2f44131..2e3f714b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -96,4 +96,3 @@ class TestUtils(unittest.TestCase): self.assertTrue(os.path.isdir(test_directory)) self.assertListEqual([], os.listdir(test_directory)) shutil.rmtree(test_directory) - From 4427424db39c95890a30d2a6293d129002e2dc04 Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 4 Jul 2012 15:20:15 -0700 Subject: [PATCH 13/19] Changed debugging reporting to post file deletion instead of pre file deletion per request. --- pelican/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pelican/utils.py b/pelican/utils.py index a1c40077..f0f742db 100644 --- a/pelican/utils.py +++ b/pelican/utils.py @@ -95,15 +95,15 @@ def clean_output_dir(path): for filename in os.listdir(path): file = os.path.join(path, filename) if os.path.isdir(file): - logger.debug("Deleting directory %s" % file) try: shutil.rmtree(file) + logger.debug("Deleted directory %s" % file) except Exception, e: logger.error("Unable to delete directory %s; %e" % file, e) elif os.path.isfile(file) or os.path.islink(file): - logger.debug("Deleting file/link %s" % file) try: os.remove(file) + logger.debug("Deleted file/link %s" % file) except Exception, e: logger.error("Unable to delete file %s; %e" % file, e) else: From 886a1d94b957ac4f79b2a40a0438f69b1bf1ce5c Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 4 Jul 2012 17:09:42 -0700 Subject: [PATCH 14/19] Changed name of the page helper method to prevent nose from running it as a test --- tests/test_generators.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_generators.py b/tests/test_generators.py index cc84c80f..61f31696 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -98,11 +98,11 @@ class TestPageGenerator(unittest.TestCase): """ Every time you want to test for a new field; Make sure the test pages in "TestPages" have all the fields - Add it to distilled in distill_pages_for_test + Add it to distilled in distill_pages Then update the assertItemsEqual in test_generate_context to match expected """ - def distill_pages_for_test(self, pages): + def distill_pages(self, pages): distilled = [] for page in pages: distilled.append([ @@ -120,8 +120,8 @@ class TestPageGenerator(unittest.TestCase): _DEFAULT_CONFIG['THEME'], None, _DEFAULT_CONFIG['MARKUP']) generator.generate_context() - pages = self.distill_pages_for_test(generator.pages) - hidden_pages = self.distill_pages_for_test(generator.hidden_pages) + pages = self.distill_pages(generator.pages) + hidden_pages = self.distill_pages(generator.hidden_pages) pages_expected = [ [u'This is a test page', 'published'], From 72421d443844e8bf7e79d76baa8766d0a7a59c8a Mon Sep 17 00:00:00 2001 From: Justin Mayer Date: Thu, 5 Jul 2012 11:34:45 -0700 Subject: [PATCH 15/19] Support arbitrary SSH ports in pelican-quickstart Some folks choose non-standard SSH ports for security reasons, so it makes sense to try to support that in the pelican-quickstart script. --- pelican/tools/pelican_quickstart.py | 2 ++ pelican/tools/templates/Makefile.in | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pelican/tools/pelican_quickstart.py b/pelican/tools/pelican_quickstart.py index cfd9bb4c..b5da8926 100755 --- a/pelican/tools/pelican_quickstart.py +++ b/pelican/tools/pelican_quickstart.py @@ -19,6 +19,7 @@ CONF = { 'ftp_user': 'anonymous', 'ftp_target_dir': '/', 'ssh_host': 'locahost', + 'ssh_port': 22, 'ssh_user': 'root', 'ssh_target_dir': '/var/www', 'dropbox_dir' : '~/Dropbox/Public/', @@ -159,6 +160,7 @@ Please answer the following questions so this script can generate the files need if ask('Do you want to upload your website using SSH ?', answer=bool, default=False): CONF['ssh_host'] = ask('What is the hostname of your SSH server ?', str, CONF['ssh_host']) + CONF['ssh_port'] = ask('What is the port of your SSH server?', int, CONF['ssh_port']) CONF['ssh_user'] = ask('What is your username on this server ?', str, CONF['ssh_user']) CONF['ssh_target_dir'] = ask('Where do you want to put your website on this server ?', str, CONF['ssh_target_dir']) diff --git a/pelican/tools/templates/Makefile.in b/pelican/tools/templates/Makefile.in index 998d8c97..392336d7 100644 --- a/pelican/tools/templates/Makefile.in +++ b/pelican/tools/templates/Makefile.in @@ -11,6 +11,7 @@ FTP_USER=$ftp_user FTP_TARGET_DIR=$ftp_target_dir SSH_HOST=$ssh_host +SSH_PORT=$ssh_port SSH_USER=$ssh_user SSH_TARGET_DIR=$ssh_target_dir @@ -43,10 +44,10 @@ dropbox_upload: $$(OUTPUTDIR)/index.html cp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR) ssh_upload: $$(OUTPUTDIR)/index.html - scp -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR) + scp -P $$(SSH_PORT) -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR) rsync_upload: $$(OUTPUTDIR)/index.html - rsync -e ssh -P -rvz --delete $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) + rsync -e "ssh -p $(SSH_PORT)" -P -rvz --delete $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) ftp_upload: $$(OUTPUTDIR)/index.html lftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUTDIR) $$(FTP_TARGET_DIR) ; quit" From d8b85580dc8eb32a718a1e7331b47c4c26061bf0 Mon Sep 17 00:00:00 2001 From: Justin Mayer Date: Thu, 5 Jul 2012 12:15:55 -0700 Subject: [PATCH 16/19] Minor syntactical improvements to quickstart --- pelican/tools/pelican_quickstart.py | 30 ++++++++++------------ pelican/tools/templates/pelican.conf.py.in | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/pelican/tools/pelican_quickstart.py b/pelican/tools/pelican_quickstart.py index b5da8926..0e713fe8 100755 --- a/pelican/tools/pelican_quickstart.py +++ b/pelican/tools/pelican_quickstart.py @@ -18,7 +18,7 @@ CONF = { 'ftp_host': 'localhost', 'ftp_user': 'anonymous', 'ftp_target_dir': '/', - 'ssh_host': 'locahost', + 'ssh_host': 'localhost', 'ssh_port': 22, 'ssh_user': 'root', 'ssh_target_dir': '/var/www', @@ -89,7 +89,7 @@ def ask(question, answer=str, default=None, l=None): r = default break else: - print("You must answer `yes' or `no'") + print("You must answer 'yes' or 'no'") return r elif answer == int: r = None @@ -112,12 +112,12 @@ def ask(question, answer=str, default=None, l=None): print('You must enter an integer') return r else: - raise NotImplemented('Arguent `answer` must be str, bool or integer') + raise NotImplemented('Argument `answer` must be str, bool, or integer') def main(): parser = argparse.ArgumentParser( - description="A kickstarter for pelican", + description="A kickstarter for Pelican", formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument('-p', '--path', default=".", help="The path to generate the blog into") @@ -126,7 +126,7 @@ def main(): parser.add_argument('-a', '--author', metavar="author", help='Set the author name of the website') parser.add_argument('-l', '--lang', metavar="lang", - help='Set the default lang of the website') + help='Set the default web site language') args = parser.parse_args() @@ -138,15 +138,15 @@ Please answer the following questions so this script can generate the files need '''.format(v=__version__)) - CONF['basedir'] = os.path.abspath(ask('Where do you want to create your new Web site ?', answer=str, default=args.path)) - CONF['sitename'] = ask('What will be the title of this Web site ?', answer=str, default=args.title) - CONF['author'] = ask('Who will be the author of this Web site ?', answer=str, default=args.author) - CONF['lang'] = ask('What will be the default language of this Web site ?', str, args.lang or CONF['lang'], 2) + CONF['basedir'] = os.path.abspath(ask('Where do you want to create your new web site?', answer=str, default=args.path)) + CONF['sitename'] = ask('What will be the title of this web site?', answer=str, default=args.title) + CONF['author'] = ask('Who will be the author of this web site?', answer=str, default=args.author) + CONF['lang'] = ask('What will be the default language of this web site ?', str, args.lang or CONF['lang'], 2) CONF['with_pagination'] = ask('Do you want to enable article pagination ?', bool, bool(CONF['default_pagination'])) if CONF['with_pagination']: - CONF['default_pagination'] = ask('So how many articles per page do you want ?', int, CONF['default_pagination']) + CONF['default_pagination'] = ask('How many articles per page do you want?', int, CONF['default_pagination']) else: CONF['default_pagination'] = False @@ -155,15 +155,13 @@ Please answer the following questions so this script can generate the files need if mkfile: if ask('Do you want to upload your website using FTP ?', answer=bool, default=False): CONF['ftp_host'] = ask('What is the hostname of your FTP server ?', str, CONF['ftp_host']) - CONF['ftp_user'] = ask('What is your username on this server ?', str, CONF['ftp_user']) - CONF['ftp_target_dir'] = ask('Where do you want to put your website on this server ?', str, CONF['ftp_target_dir']) - + CONF['ftp_user'] = ask('What is your username on that server?', str, CONF['ftp_user']) + CONF['ftp_target_dir'] = ask('Where do you want to put your web site on that server?', str, CONF['ftp_target_dir']) if ask('Do you want to upload your website using SSH ?', answer=bool, default=False): CONF['ssh_host'] = ask('What is the hostname of your SSH server ?', str, CONF['ssh_host']) CONF['ssh_port'] = ask('What is the port of your SSH server?', int, CONF['ssh_port']) - CONF['ssh_user'] = ask('What is your username on this server ?', str, CONF['ssh_user']) - CONF['ssh_target_dir'] = ask('Where do you want to put your website on this server ?', str, CONF['ssh_target_dir']) - + CONF['ssh_user'] = ask('What is your username on that server?', str, CONF['ssh_user']) + CONF['ssh_target_dir'] = ask('Where do you want to put your web site on that server?', str, CONF['ssh_target_dir']) if ask('Do you want to upload your website using Dropbox ?', answer=bool, default=False): CONF['dropbox_dir'] = ask('Where is your Dropbox directory ?', str, CONF['dropbox_dir']) diff --git a/pelican/tools/templates/pelican.conf.py.in b/pelican/tools/templates/pelican.conf.py.in index ee56048e..095a7e7d 100644 --- a/pelican/tools/templates/pelican.conf.py.in +++ b/pelican/tools/templates/pelican.conf.py.in @@ -3,7 +3,7 @@ AUTHOR = u"$author" SITENAME = u"$sitename" -SITEURL = '/' +SITEURL = '' TIMEZONE = 'Europe/Paris' From 764a2cfa5100d1cd70699e33d328c1203e201a00 Mon Sep 17 00:00:00 2001 From: Justin Mayer Date: Sat, 7 Jul 2012 07:41:12 -0700 Subject: [PATCH 17/19] Add dual dev/publish modes to quickstart script Certain configuration options are more useful in production than they are in development. Some examples might be absolute URLs, external analytics service identifiers, Disqus comments, etc. This version of the quickstart script creates two configuration files: one for development and the other for use when publishing. In addition, the related docs have been expanded considerably. Last but not least, the quickstart script will now detect whether there is a project folder associated with the currently active virtualenv (if any) and use it by default. --- docs/getting_started.rst | 109 +++++++++++++----- docs/settings.rst | 25 ++-- pelican/tools/pelican_quickstart.py | 45 +++++--- pelican/tools/templates/Makefile.in | 38 +++--- .../{pelican.conf.py.in => pelicanconf.py.in} | 0 pelican/tools/templates/publishconf.py.in | 17 +++ 6 files changed, 170 insertions(+), 64 deletions(-) rename pelican/tools/templates/{pelican.conf.py.in => pelicanconf.py.in} (100%) create mode 100644 pelican/tools/templates/publishconf.py.in diff --git a/docs/getting_started.rst b/docs/getting_started.rst index aa04dd03..954dac3d 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -1,15 +1,70 @@ Getting started ############### -Installing -========== +Kickstart a blog +================ -You're ready? Let's go! You can install Pelican via several different methods. +You're ready? Let's go! Following is a brief tutorial for those who want to get +started right away. Subsequent sections below will cover individual topics in +greater detail. To get started, here are some recommended install steps for +Pelican:: + + $ sudo pip install --upgrade virtualenv virtualenvwrapper + $ mkvirtualenv pelican + $ pip install pelican Markdown + $ mkdir ~/code/yoursitename # (where you want your new site code to be saved) + $ cd ~/code/yoursitename + $ setvirtualenvproject + $ pelican-quickstart + +Once you've run that last ``pelican-quickstart`` command, you'll be asked some +questions about your site. Once you finish answering all the questions, you can +begin adding content to the *content* folder that has been created for you. +(See *Writing articles using Pelican* section below for more information +about how to format your content.) Once you have some content to generate, you +can convert it to HTML via the following command:: + + $ make html + +If you'd prefer to have Pelican automatically regenerate your site every time a +change is detected (handy when testing locally), use the following command +instead:: + + $ make regenerate + +To preview the site in your browser, open a new terminal tab and enter:: + + $ workon yoursitename + $ make serve + +Visit http://localhost:8000 in your browser to see your site. + +When you're ready to publish your site, you can upload it via the method(s) you +chose during the ``pelican-quickstart`` questionnaire. For this example, we'll +use rsync over ssh:: + + $ make rsync_upload + +That's it! Your site should now be live. + +Closing the current terminal session will also close the virtual environment in +which we installed Pelican. In the future, when you want to work on your site, +you can activate its virtual environment via:: + + $ workon yoursitename + +Not only will that command activate your new site's virtual environment, but it +will also automatically change your working directory to your site project. + +Installing Pelican +================== + +You can install Pelican via several different methods. The simplest is via `pip `_:: $ pip install pelican -If you don't have pip installed, an alternative method is easy_install:: +If you don't have ``pip`` installed, an alternative method is ``easy_install``:: $ easy_install pelican @@ -18,12 +73,12 @@ a virtual environment for Pelican via `virtualenv `_ and `virtualenvwrapper `_ before installing Pelican:: - $ pip install virtualenvwrapper + $ sudo pip install --upgrade virtualenv virtualenvwrapper $ mkvirtualenv pelican Once the virtual environment has been created and activated, Pelican can be -be installed via pip or easy_install as noted above. Alternatively, if you -have the project source, you can install Pelican using the distutils +be installed via ``pip`` or ``easy_install`` as noted above. Alternatively, if +you have the project source, you can install Pelican using the distutils method:: $ cd path-to-Pelican-source @@ -34,6 +89,11 @@ version of Pelican rather than a stable release, use the following command:: $ pip install -e git://github.com/ametaireau/pelican#egg=pelican +If you plan on using Markdown as a markup format, you'll need to install the +Markdown library as well:: + + $ pip install Markdown + Upgrading --------- @@ -83,7 +143,6 @@ following syntax (give your file the ``.rst`` extension):: :category: yeah :author: Alexis Metaireau - You can also use Markdown syntax (with a file ending in ``.md``). Markdown generation will not work until you explicitly install the ``Markdown`` package, which can be done via ``pip install Markdown``. Metadata syntax for @@ -105,27 +164,28 @@ example, a file located at ``python/foobar/myfoobar.rst`` will have a category o Generate your blog ------------------ -To launch Pelican, just use the ``pelican`` command:: +The ``make`` shortcut commands mentioned in the ``Kickstart a blog`` section +are mostly wrappers around the ``pelican`` command that generates the HTML from +the content. The ``pelican`` command can also be run directly:: $ pelican /path/to/your/content/ [-s path/to/your/settings.py] -And… that's all! Your weblog will be generated and saved in the ``content/`` -folder. +The above command will generate your weblog and save it in the ``content/`` +folder, using the default theme to produce a simple site. It's not +very sexy, as it's just simple HTML output (without any style). You can create +your own style if you want. -The above command will use the default theme to produce a simple site. It's not -very sexy, as it's just simple HTML output (without any style). - -You can create your own style if you want. Have a look at the help to see all -the options you can use:: +Pelican has other command-line switches available. Have a look at the help to +see all the options you can use:: $ pelican --help -Kickstart a blog ----------------- +Auto-reload +----------- -You also can use the ``pelican-quickstart`` script to start a new blog in -seconds by just answering a few questions. Just run ``pelican-quickstart`` and -you're done! (Added in Pelican 3.0) +It's possible to tell Pelican to watch for your modifications, instead of +manually re-running it every time you want to see your changes. To enable this, +run the ``pelican`` command with the ``-r`` or ``--autoreload`` option. Pages ----- @@ -209,13 +269,6 @@ For Markdown, format your code blocks thusly:: The specified identifier should be one that appears on the `list of available lexers `_. -Auto-reload ------------ - -It's possible to tell Pelican to watch for your modifications, instead of -manually re-running it every time you want to see your changes. To enable this, -run the ``pelican`` command with the ``-r`` or ``--autoreload`` option. - Publishing drafts ----------------- diff --git a/docs/settings.rst b/docs/settings.rst index 78ede790..3c557e87 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -59,18 +59,16 @@ Setting name (default value) What doe `PDF_GENERATOR` (``False``) Set to True if you want to have PDF versions of your documents. You will need to install `rst2pdf`. -`RELATIVE_URLS` (``True``) Defines whether Pelican should use relative URLs or - not. +`RELATIVE_URLS` (``True``) Defines whether Pelican should use document-relative URLs or + not. If set to ``False``, Pelican will use the SITEURL + setting to construct absolute URLs. `PLUGINS` (``[]``) The list of plugins to load. See :ref:`plugins`. `SITENAME` (``'A Pelican Blog'``) Your site name `SITEURL` Base URL of your website. Not defined by default, - which means the base URL is assumed to be "/" with a - root-relative URL structure. If `SITEURL` is specified - explicitly, there should be no trailing slash at the end, - and URLs will be generated with an absolute URL structure - (including the domain). If you want to use relative URLs - instead of root-relative or absolute URLs, you should - instead use the `RELATIVE_URL` setting. + 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'`` `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 @@ -107,6 +105,15 @@ Setting name (default value) What doe 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` 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 diff --git a/pelican/tools/pelican_quickstart.py b/pelican/tools/pelican_quickstart.py index 0e713fe8..f747d048 100755 --- a/pelican/tools/pelican_quickstart.py +++ b/pelican/tools/pelican_quickstart.py @@ -24,6 +24,7 @@ CONF = { 'ssh_target_dir': '/var/www', 'dropbox_dir' : '~/Dropbox/Public/', 'default_pagination' : 10, + 'siteurl': '', 'lang': 'en' } @@ -138,35 +139,44 @@ Please answer the following questions so this script can generate the files need '''.format(v=__version__)) - CONF['basedir'] = os.path.abspath(ask('Where do you want to create your new web site?', answer=str, default=args.path)) + project = os.path.join(os.environ['VIRTUAL_ENV'], '.project') + if os.path.isfile(project): + CONF['basedir'] = open(project, 'r').read().rstrip("\n") + print('Using project associated with current virtual environment. Will save to:\n%s\n' % CONF['basedir']) + else: + CONF['basedir'] = os.path.abspath(ask('Where do you want to create your new web site?', answer=str, default=args.path)) + CONF['sitename'] = ask('What will be the title of this web site?', answer=str, default=args.title) CONF['author'] = ask('Who will be the author of this web site?', answer=str, default=args.author) - CONF['lang'] = ask('What will be the default language of this web site ?', str, args.lang or CONF['lang'], 2) + CONF['lang'] = ask('What will be the default language of this web site?', str, args.lang or CONF['lang'], 2) - CONF['with_pagination'] = ask('Do you want to enable article pagination ?', bool, bool(CONF['default_pagination'])) + if ask('Do you want to specify a URL prefix? e.g., http://example.com ', answer=bool, default=True): + CONF['siteurl'] = ask('What is your URL prefix? (see above example; no trailing slash)', str, CONF['siteurl']) + + CONF['with_pagination'] = ask('Do you want to enable article pagination?', bool, bool(CONF['default_pagination'])) if CONF['with_pagination']: CONF['default_pagination'] = ask('How many articles per page do you want?', int, CONF['default_pagination']) else: CONF['default_pagination'] = False - mkfile = ask('Do you want to generate a Makefile to easily manage your website ?', bool, True) + mkfile = ask('Do you want to generate a Makefile to easily manage your website?', bool, True) if mkfile: - if ask('Do you want to upload your website using FTP ?', answer=bool, default=False): - CONF['ftp_host'] = ask('What is the hostname of your FTP server ?', str, CONF['ftp_host']) + if ask('Do you want to upload your website using FTP?', answer=bool, default=False): + CONF['ftp_host'] = ask('What is the hostname of your FTP server?', str, CONF['ftp_host']) CONF['ftp_user'] = ask('What is your username on that server?', str, CONF['ftp_user']) CONF['ftp_target_dir'] = ask('Where do you want to put your web site on that server?', str, CONF['ftp_target_dir']) - if ask('Do you want to upload your website using SSH ?', answer=bool, default=False): - CONF['ssh_host'] = ask('What is the hostname of your SSH server ?', str, CONF['ssh_host']) + if ask('Do you want to upload your website using SSH?', answer=bool, default=False): + CONF['ssh_host'] = ask('What is the hostname of your SSH server?', str, CONF['ssh_host']) CONF['ssh_port'] = ask('What is the port of your SSH server?', int, CONF['ssh_port']) CONF['ssh_user'] = ask('What is your username on that server?', str, CONF['ssh_user']) CONF['ssh_target_dir'] = ask('Where do you want to put your web site on that server?', str, CONF['ssh_target_dir']) - if ask('Do you want to upload your website using Dropbox ?', answer=bool, default=False): - CONF['dropbox_dir'] = ask('Where is your Dropbox directory ?', str, CONF['dropbox_dir']) + if ask('Do you want to upload your website using Dropbox?', answer=bool, default=False): + CONF['dropbox_dir'] = ask('Where is your Dropbox directory?', str, CONF['dropbox_dir']) try: - os.makedirs(os.path.join(CONF['basedir'], 'src')) + os.makedirs(os.path.join(CONF['basedir'], 'content')) except OSError, e: print('Error: {0}'.format(e)) @@ -176,8 +186,17 @@ Please answer the following questions so this script can generate the files need print('Error: {0}'.format(e)) try: - with open(os.path.join(CONF['basedir'], 'pelican.conf.py'), 'w') as fd: - for line in get_template('pelican.conf.py'): + with open(os.path.join(CONF['basedir'], 'pelicanconf.py'), 'w') as fd: + for line in get_template('pelicanconf.py'): + template = string.Template(line) + fd.write(template.safe_substitute(CONF)) + fd.close() + except OSError, e: + print('Error: {0}'.format(e)) + + try: + with open(os.path.join(CONF['basedir'], 'publishconf.py'), 'w') as fd: + for line in get_template('publishconf.py'): template = string.Template(line) fd.write(template.safe_substitute(CONF)) fd.close() diff --git a/pelican/tools/templates/Makefile.in b/pelican/tools/templates/Makefile.in index 392336d7..3a3fe74c 100644 --- a/pelican/tools/templates/Makefile.in +++ b/pelican/tools/templates/Makefile.in @@ -2,9 +2,10 @@ PELICAN=$pelican PELICANOPTS=$pelicanopts BASEDIR=$$(PWD) -INPUTDIR=$$(BASEDIR)/src +INPUTDIR=$$(BASEDIR)/content OUTPUTDIR=$$(BASEDIR)/output -CONFFILE=$$(BASEDIR)/pelican.conf.py +CONFFILE=$$(BASEDIR)/pelicanconf.py +PUBLISHCONF=$$(BASEDIR)/publishconf.py FTP_HOST=$ftp_host FTP_USER=$ftp_user @@ -23,10 +24,11 @@ help: @echo 'Usage: ' @echo ' make html (re)generate the web site ' @echo ' make clean remove the generated files ' - @echo ' ftp_upload upload the web site using FTP ' - @echo ' ssh_upload upload the web site using SSH ' - @echo ' dropbox_upload upload the web site using Dropbox ' - @echo ' rsync_upload upload the web site using rsync/ssh' + @echo ' make publish generate using production settings ' + @echo ' ftp_upload upload the web site via FTP ' + @echo ' ssh_upload upload the web site via SSH ' + @echo ' dropbox_upload upload the web site via Dropbox ' + @echo ' rsync_upload upload the web site via rsync/ssh ' @echo ' ' @@ -37,23 +39,31 @@ $$(OUTPUTDIR)/%.html: $$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS) clean: - rm -fr $$(OUTPUTDIR) - mkdir $$(OUTPUTDIR) + find $$(OUTPUTDIR) -mindepth 1 -delete -dropbox_upload: $$(OUTPUTDIR)/index.html +regenerate: clean + $$(PELICAN) -r $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS) + +serve: + cd $$(OUTPUTDIR) && python -m SimpleHTTPServer + +publish: + $$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(PUBLISHCONF) $$(PELICANOPTS) + +dropbox_upload: publish cp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR) -ssh_upload: $$(OUTPUTDIR)/index.html +ssh_upload: publish scp -P $$(SSH_PORT) -r $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST):$$(SSH_TARGET_DIR) -rsync_upload: $$(OUTPUTDIR)/index.html +rsync_upload: publish rsync -e "ssh -p $(SSH_PORT)" -P -rvz --delete $(OUTPUTDIR)/* $(SSH_USER)@$(SSH_HOST):$(SSH_TARGET_DIR) -ftp_upload: $$(OUTPUTDIR)/index.html +ftp_upload: publish lftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUTDIR) $$(FTP_TARGET_DIR) ; quit" -github: $$(OUTPUTDIR)/index.html +github: publish ghp-import $$(OUTPUTDIR) git push origin gh-pages -.PHONY: html help clean ftp_upload ssh_upload rsync_upload dropbox_upload github +.PHONY: html help clean regenerate serve publish ftp_upload ssh_upload rsync_upload dropbox_upload github diff --git a/pelican/tools/templates/pelican.conf.py.in b/pelican/tools/templates/pelicanconf.py.in similarity index 100% rename from pelican/tools/templates/pelican.conf.py.in rename to pelican/tools/templates/pelicanconf.py.in diff --git a/pelican/tools/templates/publishconf.py.in b/pelican/tools/templates/publishconf.py.in new file mode 100644 index 00000000..391eb9fa --- /dev/null +++ b/pelican/tools/templates/publishconf.py.in @@ -0,0 +1,17 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- # + +from pelicanconf import * + +SITEURL = '$siteurl' + +DELETE_OUTPUT_DIRECTORY = True + +# Following items are often useful when publishing + +# Uncomment following line for absolute URLs in production: +#RELATIVE_URLS = False + +#DISQUS_SITENAME = "" +#GOOGLE_ANALYTICS = "" + From 18b4d65c4eefcc020e7094b1886a105d8fc107e0 Mon Sep 17 00:00:00 2001 From: Justin Mayer Date: Sat, 7 Jul 2012 08:45:50 -0700 Subject: [PATCH 18/19] Clarify quickstart docs and remove spurious line --- docs/getting_started.rst | 117 +++++++++++----------- pelican/tools/templates/publishconf.py.in | 1 - 2 files changed, 58 insertions(+), 60 deletions(-) diff --git a/docs/getting_started.rst b/docs/getting_started.rst index 954dac3d..93d578a0 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -1,65 +1,10 @@ Getting started ############### -Kickstart a blog -================ - -You're ready? Let's go! Following is a brief tutorial for those who want to get -started right away. Subsequent sections below will cover individual topics in -greater detail. To get started, here are some recommended install steps for -Pelican:: - - $ sudo pip install --upgrade virtualenv virtualenvwrapper - $ mkvirtualenv pelican - $ pip install pelican Markdown - $ mkdir ~/code/yoursitename # (where you want your new site code to be saved) - $ cd ~/code/yoursitename - $ setvirtualenvproject - $ pelican-quickstart - -Once you've run that last ``pelican-quickstart`` command, you'll be asked some -questions about your site. Once you finish answering all the questions, you can -begin adding content to the *content* folder that has been created for you. -(See *Writing articles using Pelican* section below for more information -about how to format your content.) Once you have some content to generate, you -can convert it to HTML via the following command:: - - $ make html - -If you'd prefer to have Pelican automatically regenerate your site every time a -change is detected (handy when testing locally), use the following command -instead:: - - $ make regenerate - -To preview the site in your browser, open a new terminal tab and enter:: - - $ workon yoursitename - $ make serve - -Visit http://localhost:8000 in your browser to see your site. - -When you're ready to publish your site, you can upload it via the method(s) you -chose during the ``pelican-quickstart`` questionnaire. For this example, we'll -use rsync over ssh:: - - $ make rsync_upload - -That's it! Your site should now be live. - -Closing the current terminal session will also close the virtual environment in -which we installed Pelican. In the future, when you want to work on your site, -you can activate its virtual environment via:: - - $ workon yoursitename - -Not only will that command activate your new site's virtual environment, but it -will also automatically change your working directory to your site project. - Installing Pelican ================== -You can install Pelican via several different methods. +You're ready? Let's go! You can install Pelican via several different methods. The simplest is via `pip `_:: $ pip install pelican @@ -75,6 +20,7 @@ before installing Pelican:: $ sudo pip install --upgrade virtualenv virtualenvwrapper $ mkvirtualenv pelican + $ pip install pelican Once the virtual environment has been created and activated, Pelican can be be installed via ``pip`` or ``easy_install`` as noted above. Alternatively, if @@ -122,6 +68,59 @@ Optionally: * pygments, for syntax highlighting * Markdown, for supporting Markdown as an input format +Kickstart a blog +================ + +Following is a brief tutorial for those who want to get started right away. +We're going to assume Pelican was installed in a virtual environment via the +following steps (if you're not using a virtual environment for Pelican, you can +skip to the ``pelican-quickstart`` command):: + + $ sudo pip install --upgrade virtualenv virtualenvwrapper + $ mkvirtualenv pelican + $ pip install pelican Markdown + +Next we'll create a directory to house our site content and configuration files, +which can be located any place you prefer, and associate this new project with +the currently-active virtual environment:: + + $ mkdir ~/code/yoursitename + $ cd ~/code/yoursitename + $ setvirtualenvproject + +Now we can run the ``pelican-quickstart`` command, which will ask some questions +about your site:: + + $ pelican-quickstart + +Once you finish answering all the questions, you can begin adding content to the +*content* folder that has been created for you. (See *Writing articles using +Pelican* section below for more information about how to format your content.) +Once you have some content to generate, you can convert it to HTML via the +following command:: + + $ make html + +If you'd prefer to have Pelican automatically regenerate your site every time a +change is detected (handy when testing locally), use the following command +instead:: + + $ make regenerate + +To serve the site so it can be previewed in your browser:: + + $ make serve + +Visit http://localhost:8000 in your browser to see your site. + +When you're ready to publish your site, you can upload it via the method(s) you +chose during the ``pelican-quickstart`` questionnaire. For this example, we'll +use rsync over ssh:: + + $ make rsync_upload + +That's it! Your site should now be live. + Writing articles using Pelican ============================== @@ -171,9 +170,9 @@ the content. The ``pelican`` command can also be run directly:: $ pelican /path/to/your/content/ [-s path/to/your/settings.py] The above command will generate your weblog and save it in the ``content/`` -folder, using the default theme to produce a simple site. It's not -very sexy, as it's just simple HTML output (without any style). You can create -your own style if you want. +folder, using the default theme to produce a simple site. The default theme is +simple HTML without styling and is provided so folks may use it as a basis for +creating their own themes. Pelican has other command-line switches available. Have a look at the help to see all the options you can use:: diff --git a/pelican/tools/templates/publishconf.py.in b/pelican/tools/templates/publishconf.py.in index 391eb9fa..113a7318 100644 --- a/pelican/tools/templates/publishconf.py.in +++ b/pelican/tools/templates/publishconf.py.in @@ -14,4 +14,3 @@ DELETE_OUTPUT_DIRECTORY = True #DISQUS_SITENAME = "" #GOOGLE_ANALYTICS = "" - From dc21efbe10dc6552f882bdf69e4a210da100977a Mon Sep 17 00:00:00 2001 From: Justin Mayer Date: Sat, 7 Jul 2012 10:33:47 -0700 Subject: [PATCH 19/19] Improved quickstart config formatting. Fixes #401. --- pelican/tools/templates/pelicanconf.py.in | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/pelican/tools/templates/pelicanconf.py.in b/pelican/tools/templates/pelicanconf.py.in index 095a7e7d..07e286cd 100644 --- a/pelican/tools/templates/pelicanconf.py.in +++ b/pelican/tools/templates/pelicanconf.py.in @@ -7,19 +7,16 @@ SITEURL = '' TIMEZONE = 'Europe/Paris' -DEFAULT_LANG='$lang' +DEFAULT_LANG = '$lang' # Blogroll -LINKS = ( - ('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'), - ('Python.org', 'http://python.org'), - ('Jinja2', 'http://jinja.pocoo.org'), - ('You can modify those links in your config file', '#') - ) +LINKS = (('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'), + ('Python.org', 'http://python.org'), + ('Jinja2', 'http://jinja.pocoo.org'), + ('You can modify those links in your config file', '#'),) # Social widget -SOCIAL = ( - ('You can add links in your config file', '#'), - ) +SOCIAL = (('You can add links in your config file', '#'), + ('Another social link', '#'),) DEFAULT_PAGINATION = $default_pagination