From 3a0d66f07b112b6d2bdc2b57bbf717a89a351ce6 Mon Sep 17 00:00:00 2001 From: Unit 193 Date: Wed, 3 Feb 2021 19:17:00 -0500 Subject: New upstream version 8.1.2. --- nikola/plugins/command/init.py | 124 ++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 50 deletions(-) (limited to 'nikola/plugins/command/init.py') diff --git a/nikola/plugins/command/init.py b/nikola/plugins/command/init.py index 91ccdb4..0026edc 100644 --- a/nikola/plugins/command/init.py +++ b/nikola/plugins/command/init.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -# Copyright © 2012-2015 Roberto Alsina and others. +# Copyright © 2012-2020 Roberto Alsina and others. # Permission is hereby granted, free of charge, to any # person obtaining a copy of this software and associated @@ -26,28 +26,28 @@ """Create a new site.""" -from __future__ import print_function, unicode_literals -import os -import shutil +import datetime import io import json +import os +import shutil import textwrap -import datetime import unidecode +from urllib.parse import urlsplit, urlunsplit + import dateutil.tz import dateutil.zoneinfo from mako.template import Template from pkg_resources import resource_filename -import tarfile import nikola -from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN, DEFAULT_INDEX_READ_MORE_LINK, DEFAULT_RSS_READ_MORE_LINK, LEGAL_VALUES, urlsplit, urlunsplit +from nikola.nikola import DEFAULT_INDEX_READ_MORE_LINK, DEFAULT_FEED_READ_MORE_LINK, LEGAL_VALUES from nikola.plugin_categories import Command -from nikola.utils import ask, ask_yesno, get_logger, makedirs, STDERR_HANDLER, load_messages +from nikola.utils import ask, ask_yesno, get_logger, makedirs, load_messages from nikola.packages.tzlocal import get_localzone -LOGGER = get_logger('init', STDERR_HANDLER) +LOGGER = get_logger('init') SAMPLE_CONF = { 'BLOG_AUTHOR': "Your Name", @@ -55,48 +55,51 @@ SAMPLE_CONF = { 'SITE_URL': "https://example.com/", 'BLOG_EMAIL': "joe@demo.site", 'BLOG_DESCRIPTION': "This is a demo site for Nikola.", - 'PRETTY_URLS': False, - 'STRIP_INDEXES': False, + 'PRETTY_URLS': True, + 'STRIP_INDEXES': True, 'DEFAULT_LANG': "en", 'TRANSLATIONS': """{ DEFAULT_LANG: "", # Example for another language: # "es": "./es", }""", - 'THEME': 'bootstrap3', + 'THEME': LEGAL_VALUES['DEFAULT_THEME'], 'TIMEZONE': 'UTC', 'COMMENT_SYSTEM': 'disqus', 'COMMENT_SYSTEM_ID': 'nikolademo', 'CATEGORY_ALLOW_HIERARCHIES': False, 'CATEGORY_OUTPUT_FLAT_HIERARCHY': False, - 'TRANSLATIONS_PATTERN': DEFAULT_TRANSLATIONS_PATTERN, 'INDEX_READ_MORE_LINK': DEFAULT_INDEX_READ_MORE_LINK, - 'RSS_READ_MORE_LINK': DEFAULT_RSS_READ_MORE_LINK, + 'FEED_READ_MORE_LINK': DEFAULT_FEED_READ_MORE_LINK, 'POSTS': """( ("posts/*.rst", "posts", "post.tmpl"), + ("posts/*.md", "posts", "post.tmpl"), ("posts/*.txt", "posts", "post.tmpl"), + ("posts/*.html", "posts", "post.tmpl"), )""", 'PAGES': """( - ("stories/*.rst", "stories", "story.tmpl"), - ("stories/*.txt", "stories", "story.tmpl"), + ("pages/*.rst", "pages", "page.tmpl"), + ("pages/*.md", "pages", "page.tmpl"), + ("pages/*.txt", "pages", "page.tmpl"), + ("pages/*.html", "pages", "page.tmpl"), )""", 'COMPILERS': """{ - "rest": ('.rst', '.txt'), - "markdown": ('.md', '.mdown', '.markdown'), - "textile": ('.textile',), - "txt2tags": ('.t2t',), - "bbcode": ('.bb',), - "wiki": ('.wiki',), - "ipynb": ('.ipynb',), - "html": ('.html', '.htm'), + "rest": ['.rst', '.txt'], + "markdown": ['.md', '.mdown', '.markdown'], + "textile": ['.textile'], + "txt2tags": ['.t2t'], + "bbcode": ['.bb'], + "wiki": ['.wiki'], + "ipynb": ['.ipynb'], + "html": ['.html', '.htm'], # PHP files are rendered the usual way (i.e. with the full templates). # The resulting files have .php extensions, making it possible to run # them without reconfiguring your server to recognize them. - "php": ('.php',), + "php": ['.php'], # Pandoc detects the input from the source filename # but is disabled by default as it would conflict # with many of the others. - # "pandoc": ('.rst', '.md', '.txt'), + # "pandoc": ['.rst', '.md', '.txt'], }""", 'NAVIGATION_LINKS': """{ DEFAULT_LANG: ( @@ -106,6 +109,7 @@ SAMPLE_CONF = { ), }""", 'REDIRECTIONS': [], + '_METADATA_MAPPING_FORMATS': ', '.join(LEGAL_VALUES['METADATA_MAPPING']) } @@ -169,6 +173,14 @@ def format_default_translations_config(additional_languages): return "{{\n{0}\n}}".format("\n".join(lang_paths)) +def get_default_translations_dict(default_lang, additional_languages): + """Generate a TRANSLATIONS dict matching the config from 'format_default_translations_config'.""" + tr = {default_lang: ''} + for l in additional_languages: + tr[l] = './' + l + return tr + + def format_navigation_links(additional_languages, default_lang, messages, strip_indexes=False): """Return the string to configure NAVIGATION_LINKS.""" f = u"""\ @@ -210,17 +222,28 @@ def prepare_config(config): """Parse sample config with JSON.""" p = config.copy() p.update({k: json.dumps(v, ensure_ascii=False) for k, v in p.items() - if k not in ('POSTS', 'PAGES', 'COMPILERS', 'TRANSLATIONS', 'NAVIGATION_LINKS', '_SUPPORTED_LANGUAGES', '_SUPPORTED_COMMENT_SYSTEMS', 'INDEX_READ_MORE_LINK', 'RSS_READ_MORE_LINK')}) + if k not in ('POSTS', 'PAGES', 'COMPILERS', 'TRANSLATIONS', 'NAVIGATION_LINKS', '_SUPPORTED_LANGUAGES', '_SUPPORTED_COMMENT_SYSTEMS', 'INDEX_READ_MORE_LINK', 'FEED_READ_MORE_LINK', '_METADATA_MAPPING_FORMATS')}) # READ_MORE_LINKs require some special treatment. p['INDEX_READ_MORE_LINK'] = "'" + p['INDEX_READ_MORE_LINK'].replace("'", "\\'") + "'" - p['RSS_READ_MORE_LINK'] = "'" + p['RSS_READ_MORE_LINK'].replace("'", "\\'") + "'" + p['FEED_READ_MORE_LINK'] = "'" + p['FEED_READ_MORE_LINK'].replace("'", "\\'") + "'" # fix booleans and None p.update({k: str(v) for k, v in config.items() if isinstance(v, bool) or v is None}) return p -class CommandInit(Command): +def test_destination(destination, demo=False): + """Check if the destination already exists, which can break demo site creation.""" + # Issue #2214 + if demo and os.path.exists(destination): + LOGGER.warning("The directory {0} already exists, and a new demo site cannot be initialized in an existing directory.".format(destination)) + LOGGER.warning("Please remove the directory and try again, or use another directory.") + LOGGER.info("Hint: If you want to initialize a git repository in this directory, run `git init` in the directory after creating a Nikola site.") + return False + else: + return True + +class CommandInit(Command): """Create a new site.""" name = "init" @@ -272,11 +295,11 @@ class CommandInit(Command): @classmethod def create_empty_site(cls, target): """Create an empty site with directories only.""" - for folder in ('files', 'galleries', 'listings', 'posts', 'stories'): + for folder in ('files', 'galleries', 'images', 'listings', 'posts', 'pages'): makedirs(os.path.join(target, folder)) @staticmethod - def ask_questions(target): + def ask_questions(target, demo=False): """Ask some questions about Nikola.""" def urlhandler(default, toconf): answer = ask('Site URL', 'https://example.com/') @@ -310,7 +333,6 @@ class CommandInit(Command): def prettyhandler(default, toconf): SAMPLE_CONF['PRETTY_URLS'] = ask_yesno('Enable pretty URLs (/page/ instead of /page.html) that don\'t need web server configuration?', default=True) - SAMPLE_CONF['STRIP_INDEXES'] = SAMPLE_CONF['PRETTY_URLS'] def lhandler(default, toconf, show_header=True): if show_header: @@ -341,13 +363,12 @@ class CommandInit(Command): # Get messages for navigation_links. In order to do this, we need # to generate a throwaway TRANSLATIONS dict. - tr = {default: ''} - for l in langs: - tr[l] = './' + l + tr = get_default_translations_dict(default, langs) + # Assuming that base contains all the locales, and that base does # not inherit from anywhere. try: - messages = load_messages(['base'], tr, default) + messages = load_messages(['base'], tr, default, themes_dirs=['themes']) SAMPLE_CONF['NAVIGATION_LINKS'] = format_navigation_links(langs, default, messages, SAMPLE_CONF['STRIP_INDEXES']) except nikola.utils.LanguageNotFoundError as e: print(" ERROR: the language '{0}' is not supported.".format(e.lang)) @@ -358,28 +379,28 @@ class CommandInit(Command): def tzhandler(default, toconf): print("\nPlease choose the correct time zone for your blog. Nikola uses the tz database.") print("You can find your time zone here:") - print("http://en.wikipedia.org/wiki/List_of_tz_database_time_zones") + print("https://en.wikipedia.org/wiki/List_of_tz_database_time_zones") print("") answered = False while not answered: try: lz = get_localzone() - except: + except Exception: lz = None answer = ask('Time zone', lz if lz else "UTC") tz = dateutil.tz.gettz(answer) if tz is None: print(" WARNING: Time zone not found. Searching list of time zones for a match.") - zonesfile = tarfile.open(fileobj=dateutil.zoneinfo.getzoneinfofile_stream()) - zonenames = [zone for zone in zonesfile.getnames() if answer.lower() in zone.lower()] - if len(zonenames) == 1: - tz = dateutil.tz.gettz(zonenames[0]) - answer = zonenames[0] + all_zones = dateutil.zoneinfo.get_zonefile_instance().zones + matching_zones = [zone for zone in all_zones if answer.lower() in zone.lower()] + if len(matching_zones) == 1: + tz = dateutil.tz.gettz(matching_zones[0]) + answer = matching_zones[0] print(" Picking '{0}'.".format(answer)) - elif len(zonenames) > 1: + elif len(matching_zones) > 1: print(" The following time zones match your query:") - print(' ' + '\n '.join(zonenames)) + print(' ' + '\n '.join(matching_zones)) continue if tz is not None: @@ -441,7 +462,7 @@ class CommandInit(Command): print("If you do not want to answer and want to go with the defaults instead, simply restart with the `-q` parameter.") for query, default, toconf, destination in questions: - if target and destination == '!target': + if target and destination == '!target' and test_destination(target, demo): # Skip the destination question if we know it already pass else: @@ -458,8 +479,9 @@ class CommandInit(Command): if toconf: SAMPLE_CONF[destination] = answer if destination == '!target': - while not answer: - print(' ERROR: you need to specify a target directory.\n') + while not answer or not test_destination(answer, demo): + if not answer: + print(' ERROR: you need to specify a target directory.\n') answer = ask(query, default) STORAGE['target'] = answer @@ -475,7 +497,7 @@ class CommandInit(Command): except IndexError: target = None if not options.get('quiet'): - st = self.ask_questions(target=target) + st = self.ask_questions(target=target, demo=options.get('demo')) try: if not target: target = st['target'] @@ -488,11 +510,13 @@ class CommandInit(Command): Options: -q, --quiet Do not ask questions about config. -d, --demo Create a site filled with example data.""") - return False + return 1 if not options.get('demo'): self.create_empty_site(target) LOGGER.info('Created empty site at {0}.'.format(target)) else: + if not test_destination(target, True): + return 2 self.copy_sample_site(target) LOGGER.info("A new site with example data has been created at " "{0}.".format(target)) -- cgit v1.2.3