From 886a1d94b957ac4f79b2a40a0438f69b1bf1ce5c Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Wed, 4 Jul 2012 17:09:42 -0700 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 6/7] 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 From dff5b3589bf4d437cc6c250423066049f3ec1adc Mon Sep 17 00:00:00 2001 From: tBunnyMan Date: Sat, 7 Jul 2012 12:15:35 -0700 Subject: [PATCH 7/7] Add per page templates. Closes #376 Also set up helper classes in test_generators.py for cleaner tests --- docs/faq.rst | 11 ++++ pelican/contents.py | 11 ++++ pelican/generators.py | 15 +++--- tests/TestPages/hidden_page_with_template.rst | 11 ++++ tests/TestPages/page_with_template.rst | 8 +++ tests/content/article_with_template.rst | 8 +++ tests/test_contents.py | 25 ++++++++- tests/test_generators.py | 54 +++++++++++++++++-- 8 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 tests/TestPages/hidden_page_with_template.rst create mode 100644 tests/TestPages/page_with_template.rst create mode 100644 tests/content/article_with_template.rst diff --git a/docs/faq.rst b/docs/faq.rst index a3829d65..3eec6e84 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -49,3 +49,14 @@ install it. You can do so by typing:: In case you don't have pip installed, consider installing it via:: $ (sudo) easy_install pip + +How do I assign custom templates on a per page basis? +===================================================== + +It's as simple as adding an extra line of metadata to any pages or articles you +want to have it's own template. + + :template: template_name + +Then just make sure to have the template installed in to your theme as +``template_name.html``. \ No newline at end of file diff --git a/pelican/contents.py b/pelican/contents.py index b8bb0993..a5e3be8f 100644 --- a/pelican/contents.py +++ b/pelican/contents.py @@ -21,6 +21,7 @@ class Page(object): :param content: the string to parse, containing the original content. """ mandatory_properties = ('title',) + default_template = 'page' def __init__(self, content, metadata=None, settings=None, filename=None): @@ -44,6 +45,9 @@ class Page(object): # 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() + # default author to the one in settings if not defined if not hasattr(self, 'author'): if 'AUTHOR' in settings: @@ -153,9 +157,16 @@ class Page(object): 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 + class Article(Page): mandatory_properties = ('title', 'date', 'category') + default_template = 'article' class Quote(Page): diff --git a/pelican/generators.py b/pelican/generators.py index 4e9312cc..8526a56d 100644 --- a/pelican/generators.py +++ b/pelican/generators.py @@ -167,11 +167,9 @@ class ArticlesGenerator(Generator): def generate_articles(self, write): """Generate the articles.""" - article_template = self.get_template('article') for article in chain(self.translations, self.articles): - write(article.save_as, - article_template, self.context, article=article, - category=article.category) + write(article.save_as, self.get_template(article.template), + self.context, article=article, category=article.category) def generate_direct_templates(self, write): """Generate direct templates pages""" @@ -222,10 +220,10 @@ class ArticlesGenerator(Generator): def generate_drafts(self, write): """Generate drafts pages.""" - article_template = self.get_template('article') for article in self.drafts: - write('drafts/%s.html' % article.slug, article_template, - self.context, article=article, category=article.category) + write('drafts/%s.html' % article.slug, + self.get_template(article.template), self.context, + article=article, category=article.category) def generate_pages(self, writer): """Generate the pages on the disk""" @@ -385,7 +383,6 @@ class PagesGenerator(Generator): (repr(unicode.encode(page.status, 'utf-8')), repr(f))) - self.pages, self.translations = process_translations(all_pages) self.hidden_pages, self.hidden_translations = process_translations(hidden_pages) @@ -395,7 +392,7 @@ class PagesGenerator(Generator): 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'), + writer.write_file(page.save_as, self.get_template(page.template), self.context, page=page, relative_urls=self.settings.get('RELATIVE_URLS')) diff --git a/tests/TestPages/hidden_page_with_template.rst b/tests/TestPages/hidden_page_with_template.rst new file mode 100644 index 00000000..36104a09 --- /dev/null +++ b/tests/TestPages/hidden_page_with_template.rst @@ -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 diff --git a/tests/TestPages/page_with_template.rst b/tests/TestPages/page_with_template.rst new file mode 100644 index 00000000..9388dc2f --- /dev/null +++ b/tests/TestPages/page_with_template.rst @@ -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 diff --git a/tests/content/article_with_template.rst b/tests/content/article_with_template.rst new file mode 100644 index 00000000..eb55738c --- /dev/null +++ b/tests/content/article_with_template.rst @@ -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". diff --git a/tests/test_contents.py b/tests/test_contents.py index e7c9ad01..bc028ea8 100644 --- a/tests/test_contents.py +++ b/tests/test_contents.py @@ -2,7 +2,7 @@ from .support import unittest -from pelican.contents import Page +from pelican.contents import Page, Article from pelican.settings import _DEFAULT_CONFIG from pelican.utils import truncate_html_words @@ -135,6 +135,17 @@ class TestPage(unittest.TestCase): # will simply skip this test. unittest.skip("There is no locale %s in this system." % locale) + def test_template(self): + """ + Pages default to page, metadata overwrites + """ + default_page = Page(**self.page_kwargs) + self.assertEqual('page', default_page.template) + page_kwargs = self._copy_page_kwargs() + page_kwargs['metadata']['template'] = 'custom' + custom_page = Page(**page_kwargs) + self.assertEqual('custom', custom_page.template) + def _copy_page_kwargs(self): # make a deep copy of page_kwargs page_kwargs = dict([(key, self.page_kwargs[key]) for key in @@ -146,3 +157,15 @@ class TestPage(unittest.TestCase): for subkey in page_kwargs[key]]) return page_kwargs + +class TestArticle(TestPage): + def test_template(self): + """ + Articles default to article, metadata overwrites + """ + default_article = Article(**self.page_kwargs) + self.assertEqual('article', default_article.template) + article_kwargs = self._copy_page_kwargs() + article_kwargs['metadata']['template'] = 'custom' + custom_article = Article(**article_kwargs) + self.assertEqual('custom', custom_article.template) diff --git a/tests/test_generators.py b/tests/test_generators.py index 61f31696..3b0a4b46 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -13,6 +13,37 @@ CUR_DIR = os.path.dirname(__file__) class TestArticlesGenerator(unittest.TestCase): + def setUp(self): + super(TestArticlesGenerator, self).setUp() + self.generator = None + + def get_populated_generator(self): + """ + We only need to pull all the test articles once, but read from it + for each test. + """ + if self.generator is None: + settings = _DEFAULT_CONFIG.copy() + settings['ARTICLE_DIR'] = 'content' + settings['DEFAULT_CATEGORY'] = 'Default' + self.generator = ArticlesGenerator(settings.copy(), settings, + CUR_DIR, _DEFAULT_CONFIG['THEME'], None, + _DEFAULT_CONFIG['MARKUP']) + self.generator.generate_context() + return self.generator + + def distill_articles(self, articles): + distilled = [] + for page in articles: + distilled.append([ + page.title, + page.status, + page.category.name, + page.template + ] + ) + return distilled + def test_generate_feeds(self): generator = ArticlesGenerator(None, {'FEED': _DEFAULT_CONFIG['FEED']}, @@ -93,6 +124,16 @@ class TestArticlesGenerator(unittest.TestCase): generator.generate_direct_templates(write) write.assert_called_count == 0 + def test_per_article_template(self): + """ + Custom template articles get the field but standard/unset are None + """ + generator = self.get_populated_generator() + articles = self.distill_articles(generator.articles) + custom_template = ['Article with template', 'published', 'Default', 'custom'] + standard_template = ['This is a super article !', 'published', 'Yeah', 'article'] + self.assertIn(custom_template, articles) + self.assertIn(standard_template, articles) class TestPageGenerator(unittest.TestCase): """ @@ -107,7 +148,8 @@ class TestPageGenerator(unittest.TestCase): for page in pages: distilled.append([ page.title, - page.status + page.status, + page.template ] ) return distilled @@ -124,12 +166,14 @@ class TestPageGenerator(unittest.TestCase): hidden_pages = self.distill_pages(generator.hidden_pages) pages_expected = [ - [u'This is a test page', 'published'], - [u'This is a markdown test page', 'published'] + [u'This is a test page', 'published', 'page'], + [u'This is a markdown test page', 'published', 'page'], + [u'This is a test page with a preset template', 'published', 'custom'] ] hidden_pages_expected = [ - [u'This is a test hidden page', 'hidden'], - [u'This is a markdown test hidden page', 'hidden'] + [u'This is a test hidden page', 'hidden', 'page'], + [u'This is a markdown test hidden page', 'hidden', 'page'], + [u'This is a test hidden page with a custom template', 'hidden', 'custom'] ] self.assertItemsEqual(pages_expected,pages)