mirror of
https://github.com/getpelican/pelican.git
synced 2025-10-15 20:28:56 +02:00
Port pelican to python 3.
Stays compatible with 2.x series, thanks to an unified codebase.
This commit is contained in:
parent
9847394e12
commit
71995d5e1b
43 changed files with 495 additions and 287 deletions
|
|
@ -1,7 +1,12 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals, print_function
|
||||
import argparse
|
||||
from HTMLParser import HTMLParser
|
||||
try:
|
||||
from html.parser import HTMLParser
|
||||
except ImportError:
|
||||
from HTMLParser import HTMLParser
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -15,14 +20,14 @@ from pelican.utils import slugify
|
|||
def wp2fields(xml):
|
||||
"""Opens a wordpress XML file, and yield pelican fields"""
|
||||
try:
|
||||
from BeautifulSoup import BeautifulStoneSoup
|
||||
from bs4 import BeautifulSoup
|
||||
except ImportError:
|
||||
error = ('Missing dependency '
|
||||
'"BeautifulSoup" required to import Wordpress XML files.')
|
||||
'"BeautifulSoup4" and "lxml" required to import Wordpress XML files.')
|
||||
sys.exit(error)
|
||||
|
||||
xmlfile = open(xml, encoding='utf-8').read()
|
||||
soup = BeautifulStoneSoup(xmlfile)
|
||||
soup = BeautifulSoup(xmlfile, "xml")
|
||||
items = soup.rss.channel.findAll('item')
|
||||
|
||||
for item in items:
|
||||
|
|
@ -54,10 +59,10 @@ def wp2fields(xml):
|
|||
def dc2fields(file):
|
||||
"""Opens a Dotclear export file, and yield pelican fields"""
|
||||
try:
|
||||
from BeautifulSoup import BeautifulStoneSoup
|
||||
from bs4 import BeautifulSoup
|
||||
except ImportError:
|
||||
error = ('Missing dependency '
|
||||
'"BeautifulSoup" required to import Dotclear files.')
|
||||
'"BeautifulSoup4" and "lxml" required to import Dotclear files.')
|
||||
sys.exit(error)
|
||||
|
||||
|
||||
|
|
@ -142,13 +147,27 @@ def dc2fields(file):
|
|||
if len(tag) > 1:
|
||||
if int(tag[:1]) == 1:
|
||||
newtag = tag.split('"')[1]
|
||||
tags.append(unicode(BeautifulStoneSoup(newtag,convertEntities=BeautifulStoneSoup.HTML_ENTITIES )))
|
||||
tags.append(
|
||||
BeautifulSoup(
|
||||
newtag
|
||||
, "xml"
|
||||
)
|
||||
# bs4 always outputs UTF-8
|
||||
.decode('utf-8')
|
||||
)
|
||||
else:
|
||||
i=1
|
||||
j=1
|
||||
while(i <= int(tag[:1])):
|
||||
newtag = tag.split('"')[j].replace('\\','')
|
||||
tags.append(unicode(BeautifulStoneSoup(newtag,convertEntities=BeautifulStoneSoup.HTML_ENTITIES )))
|
||||
tags.append(
|
||||
BeautifulSoup(
|
||||
newtag
|
||||
, "xml"
|
||||
)
|
||||
# bs4 always outputs UTF-8
|
||||
.decode('utf-8')
|
||||
)
|
||||
i=i+1
|
||||
if j < int(tag[:1])*2:
|
||||
j=j+2
|
||||
|
|
@ -244,7 +263,7 @@ def fields2pelican(fields, out_markup, output_path, dircat=False, strip_raw=Fals
|
|||
# Replace newlines with paragraphs wrapped with <p> so
|
||||
# HTML is valid before conversion
|
||||
paragraphs = content.splitlines()
|
||||
paragraphs = [u'<p>{0}</p>'.format(p) for p in paragraphs]
|
||||
paragraphs = ['<p>{0}</p>'.format(p) for p in paragraphs]
|
||||
new_content = ''.join(paragraphs)
|
||||
|
||||
fp.write(new_content)
|
||||
|
|
@ -264,7 +283,7 @@ def fields2pelican(fields, out_markup, output_path, dircat=False, strip_raw=Fals
|
|||
elif rc > 0:
|
||||
error = "Please, check your Pandoc installation."
|
||||
exit(error)
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
error = "Pandoc execution failed: %s" % e
|
||||
exit(error)
|
||||
|
||||
|
|
@ -284,7 +303,7 @@ def fields2pelican(fields, out_markup, output_path, dircat=False, strip_raw=Fals
|
|||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Transform feed, Wordpress or Dotclear files to reST (rst) "
|
||||
"or Markdown (md) files. Be sure to have pandoc installed.",
|
||||
"or Markdown (md) files. Be sure to have pandoc installed",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
|
||||
parser.add_argument(dest='input', help='The input file to read')
|
||||
|
|
@ -304,10 +323,10 @@ def main():
|
|||
help="Strip raw HTML code that can't be converted to "
|
||||
"markup such as flash embeds or iframes (wordpress import only)")
|
||||
parser.add_argument('--disable-slugs', action='store_true',
|
||||
dest='disable_slugs',
|
||||
help='Disable storing slugs from imported posts within output. '
|
||||
'With this disabled, your Pelican URLs may not be consistent '
|
||||
'with your original posts.')
|
||||
dest='disable_slugs',
|
||||
help='Disable storing slugs from imported posts within output. '
|
||||
'With this disabled, your Pelican URLs may not be consistent '
|
||||
'with your original posts.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
|
|
@ -339,4 +358,4 @@ def main():
|
|||
fields2pelican(fields, args.markup, args.output,
|
||||
dircat=args.dircat or False,
|
||||
strip_raw=args.strip_raw or False,
|
||||
disable_slugs=args.disable_slugs or False)
|
||||
strip_slugs=args.disable_slugs or False)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*- #
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals, print_function
|
||||
import six
|
||||
|
||||
import os
|
||||
import string
|
||||
|
|
@ -29,11 +32,22 @@ CONF = {
|
|||
'lang': 'en'
|
||||
}
|
||||
|
||||
def _input_compat(prompt):
|
||||
if six.PY3:
|
||||
r = input(prompt)
|
||||
else:
|
||||
r = raw_input(prompt).decode('utf-8')
|
||||
return r
|
||||
|
||||
if six.PY3:
|
||||
str_compat = str
|
||||
else:
|
||||
str_compat = unicode
|
||||
|
||||
def decoding_strings(f):
|
||||
def wrapper(*args, **kwargs):
|
||||
out = f(*args, **kwargs)
|
||||
if isinstance(out, basestring):
|
||||
if isinstance(out, six.string_types):
|
||||
# todo: make encoding configurable?
|
||||
return out.decode(sys.stdin.encoding)
|
||||
return out
|
||||
|
|
@ -55,14 +69,14 @@ def get_template(name, as_encoding='utf-8'):
|
|||
|
||||
|
||||
@decoding_strings
|
||||
def ask(question, answer=str, default=None, l=None):
|
||||
if answer == str:
|
||||
def ask(question, answer=str_compat, default=None, l=None):
|
||||
if answer == str_compat:
|
||||
r = ''
|
||||
while True:
|
||||
if default:
|
||||
r = raw_input('> {0} [{1}] '.format(question, default))
|
||||
r = _input_compat('> {0} [{1}] '.format(question, default))
|
||||
else:
|
||||
r = raw_input('> {0} '.format(question, default))
|
||||
r = _input_compat('> {0} '.format(question, default))
|
||||
|
||||
r = r.strip()
|
||||
|
||||
|
|
@ -84,11 +98,11 @@ def ask(question, answer=str, default=None, l=None):
|
|||
r = None
|
||||
while True:
|
||||
if default is True:
|
||||
r = raw_input('> {0} (Y/n) '.format(question))
|
||||
r = _input_compat('> {0} (Y/n) '.format(question))
|
||||
elif default is False:
|
||||
r = raw_input('> {0} (y/N) '.format(question))
|
||||
r = _input_compat('> {0} (y/N) '.format(question))
|
||||
else:
|
||||
r = raw_input('> {0} (y/n) '.format(question))
|
||||
r = _input_compat('> {0} (y/n) '.format(question))
|
||||
|
||||
r = r.strip().lower()
|
||||
|
||||
|
|
@ -108,9 +122,9 @@ def ask(question, answer=str, default=None, l=None):
|
|||
r = None
|
||||
while True:
|
||||
if default:
|
||||
r = raw_input('> {0} [{1}] '.format(question, default))
|
||||
r = _input_compat('> {0} [{1}] '.format(question, default))
|
||||
else:
|
||||
r = raw_input('> {0} '.format(question))
|
||||
r = _input_compat('> {0} '.format(question))
|
||||
|
||||
r = r.strip()
|
||||
|
||||
|
|
@ -125,7 +139,7 @@ def ask(question, answer=str, default=None, l=None):
|
|||
print('You must enter an integer')
|
||||
return r
|
||||
else:
|
||||
raise NotImplemented('Argument `answer` must be str, bool, or integer')
|
||||
raise NotImplemented('Argument `answer` must be str_compat, bool, or integer')
|
||||
|
||||
|
||||
def main():
|
||||
|
|
@ -158,14 +172,14 @@ needed by Pelican.
|
|||
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['basedir'] = os.path.abspath(ask('Where do you want to create your new web site?', answer=str_compat, 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['sitename'] = ask('What will be the title of this web site?', answer=str_compat, default=args.title)
|
||||
CONF['author'] = ask('Who will be the author of this web site?', answer=str_compat, default=args.author)
|
||||
CONF['lang'] = ask('What will be the default language of this web site?', str_compat, args.lang or CONF['lang'], 2)
|
||||
|
||||
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['siteurl'] = ask('What is your URL prefix? (see above example; no trailing slash)', str_compat, CONF['siteurl'])
|
||||
|
||||
CONF['with_pagination'] = ask('Do you want to enable article pagination?', bool, bool(CONF['default_pagination']))
|
||||
|
||||
|
|
@ -179,38 +193,38 @@ needed by Pelican.
|
|||
|
||||
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 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'])
|
||||
CONF['ftp_host'] = ask('What is the hostname of your FTP server?', str_compat, CONF['ftp_host'])
|
||||
CONF['ftp_user'] = ask('What is your username on that server?', str_compat, CONF['ftp_user'])
|
||||
CONF['ftp_target_dir'] = ask('Where do you want to put your web site on that server?', str_compat, 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_host'] = ask('What is the hostname of your SSH server?', str_compat, 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'])
|
||||
CONF['ssh_user'] = ask('What is your username on that server?', str_compat, CONF['ssh_user'])
|
||||
CONF['ssh_target_dir'] = ask('Where do you want to put your web site on that server?', str_compat, 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'])
|
||||
CONF['dropbox_dir'] = ask('Where is your Dropbox directory?', str_compat, CONF['dropbox_dir'])
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.join(CONF['basedir'], 'content'))
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
print('Error: {0}'.format(e))
|
||||
|
||||
try:
|
||||
os.makedirs(os.path.join(CONF['basedir'], 'output'))
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
print('Error: {0}'.format(e))
|
||||
|
||||
try:
|
||||
with codecs.open(os.path.join(CONF['basedir'], 'pelicanconf.py'), 'w', 'utf-8') as fd:
|
||||
conf_python = dict()
|
||||
for key, value in CONF.iteritems():
|
||||
for key, value in CONF.items():
|
||||
conf_python[key] = repr(value)
|
||||
|
||||
for line in get_template('pelicanconf.py'):
|
||||
template = string.Template(line)
|
||||
fd.write(template.safe_substitute(conf_python))
|
||||
fd.close()
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
print('Error: {0}'.format(e))
|
||||
|
||||
try:
|
||||
|
|
@ -219,7 +233,7 @@ needed by Pelican.
|
|||
template = string.Template(line)
|
||||
fd.write(template.safe_substitute(CONF))
|
||||
fd.close()
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
print('Error: {0}'.format(e))
|
||||
|
||||
if mkfile:
|
||||
|
|
@ -229,13 +243,13 @@ needed by Pelican.
|
|||
template = string.Template(line)
|
||||
fd.write(template.safe_substitute(CONF))
|
||||
fd.close()
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
print('Error: {0}'.format(e))
|
||||
|
||||
if develop:
|
||||
conf_shell = dict()
|
||||
for key, value in CONF.iteritems():
|
||||
if isinstance(value, basestring) and ' ' in value:
|
||||
for key, value in CONF.items():
|
||||
if isinstance(value, six.string_types) and ' ' in value:
|
||||
value = '"' + value.replace('"', '\\"') + '"'
|
||||
conf_shell[key] = value
|
||||
try:
|
||||
|
|
@ -244,8 +258,8 @@ needed by Pelican.
|
|||
template = string.Template(line)
|
||||
fd.write(template.safe_substitute(conf_shell))
|
||||
fd.close()
|
||||
os.chmod((os.path.join(CONF['basedir'], 'develop_server.sh')), 0755)
|
||||
except OSError, e:
|
||||
os.chmod((os.path.join(CONF['basedir'], 'develop_server.sh')), 493) # mode 0o755
|
||||
except OSError as e:
|
||||
print('Error: {0}'.format(e))
|
||||
|
||||
print('Done. Your new project is available at %s' % CONF['basedir'])
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
import six
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
|
@ -28,7 +31,7 @@ _BUILTIN_THEMES = ['simple', 'notmyidea']
|
|||
|
||||
def err(msg, die=None):
|
||||
"""Print an error message and exits if an exit code is given"""
|
||||
sys.stderr.write(str(msg) + '\n')
|
||||
sys.stderr.write(msg + '\n')
|
||||
if die:
|
||||
sys.exit((die if type(die) is int else 1))
|
||||
|
||||
|
|
@ -186,13 +189,13 @@ def install(path, v=False, u=False):
|
|||
for root, dirs, files in os.walk(theme_path):
|
||||
for d in dirs:
|
||||
dname = os.path.join(root, d)
|
||||
os.chmod(dname, 0755)
|
||||
os.chmod(dname, 493) # 0o755
|
||||
for f in files:
|
||||
fname = os.path.join(root, f)
|
||||
os.chmod(fname, 0644)
|
||||
except OSError, e:
|
||||
os.chmod(fname, 420) # 0o644
|
||||
except OSError as e:
|
||||
err("Cannot change permissions of files or directory in `{r}':\n{e}".format(r=theme_path, e=str(e)), die=False)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
err("Cannot copy `{p}' to `{t}':\n{e}".format(p=path, t=theme_path, e=str(e)))
|
||||
|
||||
|
||||
|
|
@ -212,7 +215,7 @@ def symlink(path, v=False):
|
|||
print("Linking `{p}' to `{t}' ...".format(p=path, t=theme_path))
|
||||
try:
|
||||
os.symlink(path, theme_path)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
err("Cannot link `{p}' to `{t}':\n{e}".format(p=path, t=theme_path, e=str(e)))
|
||||
|
||||
|
||||
|
|
@ -233,7 +236,7 @@ def clean(v=False):
|
|||
print('Removing {0}'.format(path))
|
||||
try:
|
||||
os.remove(path)
|
||||
except OSError, e:
|
||||
except OSError as e:
|
||||
print('Error: cannot remove {0}'.format(path))
|
||||
else:
|
||||
c+=1
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ regenerate: clean
|
|||
$$(PELICAN) -r $$(INPUTDIR) -o $$(OUTPUTDIR) -s $$(CONFFILE) $$(PELICANOPTS)
|
||||
|
||||
serve:
|
||||
cd $$(OUTPUTDIR) && python -m SimpleHTTPServer
|
||||
cd $$(OUTPUTDIR) && python -m pelican.server
|
||||
|
||||
devserver:
|
||||
$$(BASEDIR)/develop_server.sh restart
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ PELICAN_PID=$$BASEDIR/pelican.pid
|
|||
function usage(){
|
||||
echo "usage: $$0 (stop) (start) (restart)"
|
||||
echo "This starts pelican in debug and reload mode and then launches"
|
||||
echo "A SimpleHTTP server to help site development. It doesn't read"
|
||||
echo "A pelican.server to help site development. It doesn't read"
|
||||
echo "your pelican options so you edit any paths in your Makefile"
|
||||
echo "you will need to edit it as well"
|
||||
exit 3
|
||||
|
|
@ -31,14 +31,14 @@ function shut_down(){
|
|||
PID=$$(cat $$SRV_PID)
|
||||
PROCESS=$$(ps -p $$PID | tail -n 1 | awk '{print $$4}')
|
||||
if [[ $$PROCESS != "" ]]; then
|
||||
echo "Killing SimpleHTTPServer"
|
||||
echo "Killing pelican.server"
|
||||
kill $$PID
|
||||
else
|
||||
echo "Stale PID, deleting"
|
||||
fi
|
||||
rm $$SRV_PID
|
||||
else
|
||||
echo "SimpleHTTPServer PIDFile not found"
|
||||
echo "pelican.server PIDFile not found"
|
||||
fi
|
||||
|
||||
if [[ -f $$PELICAN_PID ]]; then
|
||||
|
|
@ -57,15 +57,15 @@ function shut_down(){
|
|||
}
|
||||
|
||||
function start_up(){
|
||||
echo "Starting up Pelican and SimpleHTTPServer"
|
||||
echo "Starting up Pelican and pelican.server"
|
||||
shift
|
||||
$$PELICAN --debug --autoreload -r $$INPUTDIR -o $$OUTPUTDIR -s $$CONFFILE $$PELICANOPTS &
|
||||
echo $$! > $$PELICAN_PID
|
||||
cd $$OUTPUTDIR
|
||||
python -m SimpleHTTPServer &
|
||||
python -m pelican.server &
|
||||
echo $$! > $$SRV_PID
|
||||
cd $$BASEDIR
|
||||
sleep 1 && echo 'Pelican and SimpleHTTPServer processes now running in background.'
|
||||
sleep 1 && echo 'Pelican and pelican.server processes now running in background.'
|
||||
}
|
||||
|
||||
###
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue