diff --git a/docs/getting_started.rst b/docs/getting_started.rst index a59bc8cf..f10afa68 100644 --- a/docs/getting_started.rst +++ b/docs/getting_started.rst @@ -83,6 +83,13 @@ the options you can use:: $ pelican --help +Kickstart a blog +---------------- + +You also can use the `pelican-quickstart` script to start a new blog in +seconds, by just answering few questions. Just run `pelican-quickstart` and +you're done! (Added in pelican 3) + Pages ----- @@ -95,16 +102,8 @@ the menu. Importing an existing blog -------------------------- -It is possible to import wordpress themes and RSS themes using a script which -is living in `tools`: importer. - -You can call it this way for a wordpress import:: - - $ python importer.py --wpfile /your/wordpress/export -o output_dir - -And like this for an import from an RSS feed:: - - $ python importer.py --feed http://your/rss/feed -o output_dir +It is possible to import your blog from dotclear, wordpress and an RSS feed using +a simple script. See :ref:`import`. Translations ------------ diff --git a/docs/importer.rst b/docs/importer.rst index 35cd095c..6e5734ae 100644 --- a/docs/importer.rst +++ b/docs/importer.rst @@ -1,3 +1,5 @@ +.. _import: + ================================= Import from other blog software ================================= @@ -5,7 +7,7 @@ Description =========== -``importer.py`` is a command line tool for converting articles from other +``pelican-import`` is a command line tool for converting articles from other software to ReStructuredText. The supported formats are: - Wordpress XML export @@ -20,9 +22,9 @@ supports Markdown). Usage """"" -| importer.py [-h] [--wpfile] [--dotclear] [--feed] [-o OUTPUT] -| [--dir-cat] -| input +| pelican-import [-h] [--wpfile] [--dotclear] [--feed] [-o OUTPUT] +| [--dir-cat] +| input Optional arguments: """"""""""""""""""" @@ -40,12 +42,11 @@ Examples for Wordpress:: - $ python2 tools/importer.py --wpfile -o ~/output ~/posts.xml + $ pelican-import --wpfile -o ~/output ~/posts.xml for Dotclear:: - $ python2 tools/importer.py --dotclear -o ~/output ~/backup.txt - + $ pelican-import --dotclear -o ~/output ~/backup.txt Tests ===== diff --git a/docs/settings.rst b/docs/settings.rst index d6b05cab..7cfb9442 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -200,7 +200,7 @@ Setting name (default value) what does it do? Theming ======= -Theming is addressed in a dedicated section (see :ref:`theming-pelican`). +Theming is addressed in a dedicated section (see :ref:`theming-pelican`). However, here are the settings that are related to theming. ================================================ ===================================================== diff --git a/pelican/__init__.py b/pelican/__init__.py index 4b743d52..b68d6aa9 100644 --- a/pelican/__init__.py +++ b/pelican/__init__.py @@ -9,7 +9,7 @@ from pelican.utils import clean_output_dir, files_changed from pelican.writers import Writer from pelican import log -VERSION = "2.7.2" +__version__ = "2.7.2" class Pelican(object): @@ -112,7 +112,7 @@ def main(): help='Show only critical errors') parser.add_argument('-D', '--debug', action='store_const', const=log.DEBUG, dest='verbosity', help='Show all message, including debug messages') - parser.add_argument('--version', action='version', version=VERSION, + parser.add_argument('--version', action='version', version=__version__, help='Print the pelican version and exit') parser.add_argument('-r', '--autoreload', dest='autoreload', action='store_true', help="Relaunch pelican each time a modification occurs on the content" diff --git a/setup.py b/setup.py index e2bd4c60..4574fdd6 100755 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ setup( packages = ['pelican'], include_package_data = True, install_requires = requires, - scripts = ['bin/pelican', 'tools/pelican-themes'], + scripts = ['bin/pelican', 'tools/pelican-themes', 'tools/pelican-import', 'tools/pelican-quickstart'], classifiers = ['Development Status :: 5 - Production/Stable', 'Environment :: Console', 'License :: OSI Approved :: GNU Affero General Public License v3', diff --git a/tools/importer.py b/tools/pelican-import similarity index 100% rename from tools/importer.py rename to tools/pelican-import diff --git a/tools/pelican-quickstart b/tools/pelican-quickstart new file mode 100755 index 00000000..fe7bb31a --- /dev/null +++ b/tools/pelican-quickstart @@ -0,0 +1,269 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- # + +import os, sys, argparse, string +from pelican import __version__ + +TEMPLATES={ + 'Makefile' : ''' +PELICAN=$pelican +PELICANOPTS=$pelicanopts + +BASEDIR=$basedir +INPUTDIR=$$(BASEDIR)/src +OUTPUTDIR=$$(BASEDIR)/output +CONFFILE=$$(BASEDIR)/pelican.conf.py + +FTP_HOST=$ftp_host +FTP_USER=$ftp_user +FTP_TARGET_DIR=$ftp_target_dir + +SSH_HOST=$ssh_host +SSH_USER=$ssh_user +SSH_TARGET_DIR=$ssh_target_dir + +DROPBOX_DIR=$dropbox_dir + +help: +\t@echo 'Makefile for a pelican Web site ' +\t@echo ' ' +\t@echo 'Usage: ' +\t@echo ' make html (re)generate the web site ' +\t@echo ' make clean remove the generated files ' +\t@echo ' ftp_upload upload the web site using FTP ' +\t@echo ' ssh_upload upload the web site using SSH ' +\t@echo ' dropbox_upload upload the web site using Dropbox ' +\t@echo ' ' + + +html: $$(OUTPUTDIR)/index.html +\t@echo 'Done' + +$$(OUTPUTDIR)/%.html: +\t$$(PELICAN) $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) + +clean: +\trm -r $$(OUTPUTDIR)/* + +dropbox_upload: $$(OUTPUTDIR)/index.html +\tcp -r $$(OUTPUTDIR)/* $$(DROPBOX_DIR) + +ssh_upload: $$(OUTPUTDIR)/index.html +\tscp -rv $$(OUTPUTDIR)/* $$(SSH_USER)@$$(SSH_HOST)/$$(SSH_TARGET_DIR) + +ftp_upload: $$(OUTPUTDIR)/index.html +\tlftp ftp://$$(FTP_USER)@$$(FTP_HOST) -e "mirror -R $$(OUTPUT_DIR)/* $$(FTP_TARGET_DIR) ; quit" + +.PHONY: html help clean ftp_upload ssh_upload dropbox_upload + ''', + + 'pelican.conf.py': '''#!/usr/bin/env python +# -*- coding: utf-8 -*- # + +AUTHOR = u"$author" +SITENAME = u"$sitename" +SITEURL = '/' + +DEFAULT_LANG='$lang' + +# Blogroll +LINKS = ( + ('Pelican', 'http://docs.notmyidea.org/alexis/pelican/'), + ('Python.org', 'http://python.org'), + ('Jinja2', 'http://jinja.pocoo.org'), + ('You can modify those links in your config file', '#') + ) + +# Social widget +SOCIAL = ( + ('You can add links in your config file', '#'), + ) + +WITH_PAGINATION = $with_pagination +DEFAULT_PAGINATION = $default_pagination + + + ''' +} + +CONF = { + 'pelican' : 'pelican', + 'pelicanopts' : None, + 'basedir': '.', + 'ftp_host': 'localhost', + 'ftp_user': 'anonymous', + 'ftp_target_dir': '/', + 'ssh_host': 'locahost', + 'ssh_user': 'root', + 'ssh_target_dir': '/var/www', + 'dropbox_dir' : '~/Dropbox/Public/', + 'with_pagination' : True, + 'default_pagination' : 7, + 'lang': 'en' +} + + +class _dict(dict): + def __init__(self, *args, **kwargs): + dict.__init__(self, *args, **kwargs) + + def __getitem__(self, i): + return dict.get(self,i,None) + + def has_key(k): + return True + + +def ask(question, answer=str, default=None, l=None): + if answer == str: + r = '' + while True: + if default: + r = raw_input('> {0} [{1}] '.format(question, default)) + else: + r = raw_input('> {0} '.format(question, default)) + + r = r.strip() + + if len(r) <= 0: + if default: + r = default + break + else: + print('You must enter something') + else: + if l and len(r) != l: + print('You must enter a {0} letters long string'.format(l)) + else: + break + + return r + + elif answer == bool: + r = None + while True: + if default is True: + r = raw_input('> {0} (Y/n) '.format(question)) + elif default is False: + r = raw_input('> {0} (y/N) '.format(question)) + else: + r = raw_input('> {0} (y/n) '.format(question)) + + r = r.strip().lower() + + if r in ('y', 'yes'): + r = True + break + elif r in ('n', 'no'): + r = False + break + elif not r: + r = default + break + else: + print("You must answer `yes' or `no'") + return r + elif answer == int: + r = None + while True: + if default: + r = raw_input('> {0} [{1}] '.format(question, default)) + else: + r = raw_input('> {0} '.format(question)) + + r = r.strip() + + if not r: + r = default + break + + try: + r = int(r) + break + except: + print('You must enter an integer') + return r + else: + raise NotImplemented('Arguent `answer` must be str, bool or integer') + + +def main(): + parser = argparse.ArgumentParser(description="A kickstarter for pelican") + parser.add_argument('-p', '--path', default=".", + help="The path to generate the blog into") + parser.add_argument('-t', '--title', default=None, metavar="title", + help='Set the title of the website') + parser.add_argument('-a', '--author', default=None, metavar="author", + help='Set the author name of the website') + parser.add_argument('-l', '--lang', default=None, metavar="lang", + help='Set the default lang of the website') + + args = parser.parse_args() + + + print('''Welcome to pelican-quickstart v{v}. + +This script will help you creating a new Pelican based website. + +Please answer the following questions so this script can generate the files needed by Pelican. + + '''.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('How will you call your 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, CONF['with_pagination']) + + if CONF['with_pagination']: + CONF['default_pagination'] = ask('So how many articles per page do you want ?', int, CONF['default_pagination']) + + 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']) + CONF['ftp_user'] = ask('What is your username on this server ?', str, CONF['ftp_user']) + CONF['ftp_traget_dir'] = ask('Where do you want to put your website on this 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_user'] = ask('What is your username on this server ?', str, CONF['ssh_user']) + CONF['ssh_traget_dir'] = ask('Where do you want to put your website on this 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']) + + try: + os.makedirs(os.path.join(CONF['basedir'], 'src')) + except OSError, e: + print('Error: {0}'.format(e)) + + try: + os.makedirs(os.path.join(CONF['basedir'], 'output')) + except OSError, e: + print('Error: {0}'.format(e)) + + conf = string.Template(TEMPLATES['pelican.conf.py']) + try: + with open(os.path.join(CONF['basedir'], 'pelican.conf.py'), 'w') as fd: + fd.write(conf.safe_substitute(CONF)) + fd.close() + except OSError, e: + print('Error: {0}'.format(e)) + + if mkfile: + Makefile = string.Template(TEMPLATES['Makefile']) + + try: + with open(os.path.join(CONF['basedir'], 'Makefile'), 'w') as fd: + fd.write(Makefile.safe_substitute(CONF)) + fd.close() + except OSError, e: + print('Error: {0}'.format(e)) + + print('Done. Your new project is available at %s' % CONF['basedir']) + +if __name__ == '__main__': + main()