forked from github/pelican
This also updates the Tumblr API to use HTTPS as documented in the current Tumblr API docs.
355 lines
12 KiB
Python
Executable file
355 lines
12 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import argparse
|
|
import locale
|
|
import os
|
|
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
import pytz
|
|
|
|
try:
|
|
import readline # NOQA
|
|
except ImportError:
|
|
pass
|
|
|
|
try:
|
|
import tzlocal
|
|
_DEFAULT_TIMEZONE = tzlocal.get_localzone().zone
|
|
except ImportError:
|
|
_DEFAULT_TIMEZONE = 'Europe/Paris'
|
|
|
|
from pelican import __version__
|
|
|
|
locale.setlocale(locale.LC_ALL, '')
|
|
try:
|
|
_DEFAULT_LANGUAGE = locale.getlocale()[0]
|
|
except ValueError:
|
|
# Don't fail on macosx: "unknown locale: UTF-8"
|
|
_DEFAULT_LANGUAGE = None
|
|
if _DEFAULT_LANGUAGE is None:
|
|
_DEFAULT_LANGUAGE = 'en'
|
|
else:
|
|
_DEFAULT_LANGUAGE = _DEFAULT_LANGUAGE.split('_')[0]
|
|
|
|
_TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
"templates")
|
|
_jinja_env = Environment(
|
|
loader=FileSystemLoader(_TEMPLATES_DIR),
|
|
trim_blocks=True,
|
|
)
|
|
|
|
|
|
_GITHUB_PAGES_BRANCHES = {
|
|
'personal': 'master',
|
|
'project': 'gh-pages'
|
|
}
|
|
|
|
CONF = {
|
|
'pelican': 'pelican',
|
|
'pelicanopts': '',
|
|
'basedir': os.curdir,
|
|
'ftp_host': 'localhost',
|
|
'ftp_user': 'anonymous',
|
|
'ftp_target_dir': '/',
|
|
'ssh_host': 'localhost',
|
|
'ssh_port': 22,
|
|
'ssh_user': 'root',
|
|
'ssh_target_dir': '/var/www',
|
|
's3_bucket': 'my_s3_bucket',
|
|
'cloudfiles_username': 'my_rackspace_username',
|
|
'cloudfiles_api_key': 'my_rackspace_api_key',
|
|
'cloudfiles_container': 'my_cloudfiles_container',
|
|
'dropbox_dir': '~/Dropbox/Public/',
|
|
'github_pages_branch': _GITHUB_PAGES_BRANCHES['project'],
|
|
'default_pagination': 10,
|
|
'siteurl': '',
|
|
'lang': _DEFAULT_LANGUAGE,
|
|
'timezone': _DEFAULT_TIMEZONE
|
|
}
|
|
|
|
# url for list of valid timezones
|
|
_TZ_URL = 'https://en.wikipedia.org/wiki/List_of_tz_database_time_zones'
|
|
|
|
|
|
# Create a 'marked' default path, to determine if someone has supplied
|
|
# a path on the command-line.
|
|
class _DEFAULT_PATH_TYPE(str):
|
|
is_default_path = True
|
|
|
|
|
|
_DEFAULT_PATH = _DEFAULT_PATH_TYPE(os.curdir)
|
|
|
|
|
|
def ask(question, answer=str, default=None, length=None):
|
|
if answer == str:
|
|
r = ''
|
|
while True:
|
|
if default:
|
|
r = input('> {0} [{1}] '.format(question, default))
|
|
else:
|
|
r = 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 length and len(r) != length:
|
|
print('Entry must be {0} characters long'.format(length))
|
|
else:
|
|
break
|
|
|
|
return r
|
|
|
|
elif answer == bool:
|
|
r = None
|
|
while True:
|
|
if default is True:
|
|
r = input('> {0} (Y/n) '.format(question))
|
|
elif default is False:
|
|
r = input('> {0} (y/N) '.format(question))
|
|
else:
|
|
r = 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 = input('> {0} [{1}] '.format(question, default))
|
|
else:
|
|
r = input('> {0} '.format(question))
|
|
|
|
r = r.strip()
|
|
|
|
if not r:
|
|
r = default
|
|
break
|
|
|
|
try:
|
|
r = int(r)
|
|
break
|
|
except ValueError:
|
|
print('You must enter an integer')
|
|
return r
|
|
else:
|
|
raise NotImplementedError(
|
|
'Argument `answer` must be str, bool, or integer')
|
|
|
|
|
|
def ask_timezone(question, default, tzurl):
|
|
"""Prompt for time zone and validate input"""
|
|
lower_tz = [tz.lower() for tz in pytz.all_timezones]
|
|
while True:
|
|
r = ask(question, str, default)
|
|
r = r.strip().replace(' ', '_').lower()
|
|
if r in lower_tz:
|
|
r = pytz.all_timezones[lower_tz.index(r)]
|
|
break
|
|
else:
|
|
print('Please enter a valid time zone:\n'
|
|
' (check [{0}])'.format(tzurl))
|
|
return r
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="A kickstarter for Pelican",
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
parser.add_argument('-p', '--path', default=_DEFAULT_PATH,
|
|
help="The path to generate the blog into")
|
|
parser.add_argument('-t', '--title', metavar="title",
|
|
help='Set the title of the website')
|
|
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 web site language')
|
|
|
|
args = parser.parse_args()
|
|
|
|
print('''Welcome to pelican-quickstart v{v}.
|
|
|
|
This script will help you create a new Pelican-based website.
|
|
|
|
Please answer the following questions so this script can generate the files
|
|
needed by Pelican.
|
|
|
|
'''.format(v=__version__))
|
|
|
|
project = os.path.join(
|
|
os.environ.get('VIRTUAL_ENV', os.curdir), '.project')
|
|
no_path_was_specified = hasattr(args.path, 'is_default_path')
|
|
if os.path.isfile(project) and no_path_was_specified:
|
|
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(os.path.expanduser(
|
|
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)
|
|
|
|
if ask('Do you want to specify a URL prefix? e.g., https://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
|
|
|
|
CONF['timezone'] = ask_timezone('What is your time zone?',
|
|
CONF['timezone'], _TZ_URL)
|
|
|
|
automation = ask('Do you want to generate a tasks.py/Makefile '
|
|
'to automate generation and publishing?', bool, True)
|
|
|
|
if automation:
|
|
if ask('Do you want to upload your website using FTP?',
|
|
answer=bool, default=False):
|
|
CONF['ftp'] = True,
|
|
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'] = True,
|
|
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'] = True,
|
|
CONF['dropbox_dir'] = ask('Where is your Dropbox directory?',
|
|
str, CONF['dropbox_dir'])
|
|
|
|
if ask('Do you want to upload your website using S3?',
|
|
answer=bool, default=False):
|
|
CONF['s3'] = True,
|
|
CONF['s3_bucket'] = ask('What is the name of your S3 bucket?',
|
|
str, CONF['s3_bucket'])
|
|
|
|
if ask('Do you want to upload your website using '
|
|
'Rackspace Cloud Files?', answer=bool, default=False):
|
|
CONF['cloudfiles'] = True,
|
|
CONF['cloudfiles_username'] = ask('What is your Rackspace '
|
|
'Cloud username?', str,
|
|
CONF['cloudfiles_username'])
|
|
CONF['cloudfiles_api_key'] = ask('What is your Rackspace '
|
|
'Cloud API key?', str,
|
|
CONF['cloudfiles_api_key'])
|
|
CONF['cloudfiles_container'] = ask('What is the name of your '
|
|
'Cloud Files container?',
|
|
str,
|
|
CONF['cloudfiles_container'])
|
|
|
|
if ask('Do you want to upload your website using GitHub Pages?',
|
|
answer=bool, default=False):
|
|
CONF['github'] = True,
|
|
if ask('Is this your personal page (username.github.io)?',
|
|
answer=bool, default=False):
|
|
CONF['github_pages_branch'] = \
|
|
_GITHUB_PAGES_BRANCHES['personal']
|
|
else:
|
|
CONF['github_pages_branch'] = \
|
|
_GITHUB_PAGES_BRANCHES['project']
|
|
|
|
try:
|
|
os.makedirs(os.path.join(CONF['basedir'], 'content'))
|
|
except OSError as e:
|
|
print('Error: {0}'.format(e))
|
|
|
|
try:
|
|
os.makedirs(os.path.join(CONF['basedir'], 'output'))
|
|
except OSError as e:
|
|
print('Error: {0}'.format(e))
|
|
|
|
try:
|
|
with open(os.path.join(CONF['basedir'], 'pelicanconf.py'),
|
|
'w', encoding='utf-8') as fd:
|
|
conf_python = dict()
|
|
for key, value in CONF.items():
|
|
conf_python[key] = repr(value)
|
|
|
|
_template = _jinja_env.get_template('pelicanconf.py.jinja2')
|
|
fd.write(_template.render(**conf_python))
|
|
fd.close()
|
|
except OSError as e:
|
|
print('Error: {0}'.format(e))
|
|
|
|
try:
|
|
with open(os.path.join(CONF['basedir'], 'publishconf.py'),
|
|
'w', encoding='utf-8') as fd:
|
|
_template = _jinja_env.get_template('publishconf.py.jinja2')
|
|
fd.write(_template.render(**CONF))
|
|
fd.close()
|
|
except OSError as e:
|
|
print('Error: {0}'.format(e))
|
|
|
|
if automation:
|
|
try:
|
|
with open(os.path.join(CONF['basedir'], 'tasks.py'),
|
|
'w', encoding='utf-8') as fd:
|
|
_template = _jinja_env.get_template('tasks.py.jinja2')
|
|
fd.write(_template.render(**CONF))
|
|
fd.close()
|
|
except OSError as e:
|
|
print('Error: {0}'.format(e))
|
|
try:
|
|
with open(os.path.join(CONF['basedir'], 'Makefile'),
|
|
'w', encoding='utf-8') as fd:
|
|
py_v = 'python3'
|
|
_template = _jinja_env.get_template('Makefile.jinja2')
|
|
fd.write(_template.render(py_v=py_v, **CONF))
|
|
fd.close()
|
|
except OSError as e:
|
|
print('Error: {0}'.format(e))
|
|
|
|
print('Done. Your new project is available at %s' % CONF['basedir'])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|