aboutsummaryrefslogtreecommitdiffstats
path: root/nikola/__main__.py
diff options
context:
space:
mode:
authorLibravatarAgustin Henze <tin@sluc.org.ar>2015-08-26 07:57:23 -0300
committerLibravatarAgustin Henze <tin@sluc.org.ar>2015-08-26 07:57:23 -0300
commit70ceb871117ca811d63cb02671dc0fefc2700883 (patch)
tree846133ea39797d2cd1101cff2ac0818167353490 /nikola/__main__.py
parent8559119e2f45b7f6508282962c0430423bfab051 (diff)
parent787b97a4cb24330b36f11297c6d3a7a473a907d0 (diff)
Merge tag 'upstream/7.6.4'
Upstream version 7.6.4
Diffstat (limited to 'nikola/__main__.py')
-rw-r--r--nikola/__main__.py94
1 files changed, 76 insertions, 18 deletions
diff --git a/nikola/__main__.py b/nikola/__main__.py
index 6aa0977..2aa63f4 100644
--- a/nikola/__main__.py
+++ b/nikola/__main__.py
@@ -24,6 +24,8 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""The main function of Nikola."""
+
from __future__ import print_function, unicode_literals
from collections import defaultdict
import os
@@ -49,7 +51,7 @@ from blinker import signal
from . import __version__
from .plugin_categories import Command
from .nikola import Nikola
-from .utils import sys_decode, sys_encode, get_root_dir, req_missing, LOGGER, STRICT_HANDLER, ColorfulStderrHandler
+from .utils import sys_decode, sys_encode, get_root_dir, req_missing, LOGGER, STRICT_HANDLER, STDERR_HANDLER, ColorfulStderrHandler
if sys.version_info[0] == 3:
import importlib.machinery
@@ -63,6 +65,7 @@ _RETURN_DOITNIKOLA = False
def main(args=None):
+ """Run Nikola."""
colorful = False
if sys.stderr.isatty() and os.name != 'nt':
colorful = True
@@ -88,13 +91,18 @@ def main(args=None):
break
quiet = False
+ strict = False
if len(args) > 0 and args[0] == 'build' and '--strict' in args:
LOGGER.notice('Running in strict mode')
STRICT_HANDLER.push_application()
+ strict = True
if len(args) > 0 and args[0] == 'build' and '-q' in args or '--quiet' in args:
- nullhandler = NullHandler()
- nullhandler.push_application()
+ NullHandler().push_application()
quiet = True
+ if not quiet and not strict:
+ NullHandler().push_application()
+ STDERR_HANDLER[0].push_application()
+
global config
original_cwd = os.getcwd()
@@ -167,11 +175,12 @@ def main(args=None):
class Help(DoitHelp):
- """show Nikola usage."""
+
+ """Show Nikola usage."""
@staticmethod
def print_usage(cmds):
- """print nikola "usage" (basic help) instructions"""
+ """Print nikola "usage" (basic help) instructions."""
# Remove 'run'. Nikola uses 'build', though we support 'run' for
# people used to it (eg. doit users).
# WARNING: 'run' is the vanilla doit command, without support for
@@ -190,8 +199,11 @@ class Help(DoitHelp):
class Build(DoitRun):
- """expose "run" command as "build" for backward compatibility"""
+
+ """Expose "run" command as "build" for backwards compatibility."""
+
def __init__(self, *args, **kw):
+ """Initialize Build."""
opts = list(self.cmd_options)
opts.append(
{
@@ -226,9 +238,11 @@ class Build(DoitRun):
class Clean(DoitClean):
- """A clean that removes cache/"""
+
+ """Clean site, including the cache directory."""
def clean_tasks(self, tasks, dryrun):
+ """Clean tasks."""
if not dryrun and config:
cache_folder = config.get('CACHE_FOLDER', 'cache')
if os.path.exists(cache_folder):
@@ -241,12 +255,16 @@ DoitAuto.name = 'doit_auto'
class NikolaTaskLoader(TaskLoader):
- """custom task loader to get tasks from Nikola instead of dodo.py file"""
+
+ """Nikola-specific task loader."""
+
def __init__(self, nikola, quiet=False):
+ """Initialize the loader."""
self.nikola = nikola
self.quiet = quiet
def load_tasks(self, cmd, opt_values, pos_args):
+ """Load Nikola tasks."""
if self.quiet:
DOIT_CONFIG = {
'verbosity': 0,
@@ -270,17 +288,22 @@ class NikolaTaskLoader(TaskLoader):
class DoitNikola(DoitMain):
+
+ """Nikola-specific implementation of DoitMain."""
+
# overwite help command
DOIT_CMDS = list(DoitMain.DOIT_CMDS) + [Help, Build, Clean, DoitAuto]
TASK_LOADER = NikolaTaskLoader
def __init__(self, nikola, quiet=False):
+ """Initialzie DoitNikola."""
super(DoitNikola, self).__init__()
self.nikola = nikola
nikola.doit = self
self.task_loader = self.TASK_LOADER(nikola, quiet)
def get_cmds(self):
+ """Get commands."""
# core doit commands
cmds = DoitMain.get_cmds(self)
# load nikola commands
@@ -289,7 +312,7 @@ class DoitNikola(DoitMain):
return cmds
def run(self, cmd_args):
- sub_cmds = self.get_cmds()
+ """Run Nikola."""
args = self.process_args(cmd_args)
args = [sys_decode(arg) for arg in args]
@@ -311,17 +334,31 @@ class DoitNikola(DoitMain):
if arg not in ('--help', '-h'):
args.append(arg)
+ if args[0] == 'help':
+ self.nikola.init_plugins(commands_only=True)
+ else:
+ self.nikola.init_plugins()
+
+ sub_cmds = self.get_cmds()
+
if any(arg in ("--version", '-V') for arg in args):
cmd_args = ['version']
args = ['version']
if args[0] not in sub_cmds.keys():
LOGGER.error("Unknown command {0}".format(args[0]))
sugg = defaultdict(list)
- for c in sub_cmds.keys():
- d = lev(c, args[0])
+ sub_filtered = (i for i in sub_cmds.keys() if i != 'run')
+ for c in sub_filtered:
+ d = levenshtein(c, args[0])
sugg[d].append(c)
- LOGGER.info('Did you mean "{}"?', '" or "'.join(sugg[min(sugg.keys())]))
+ if sugg.keys():
+ best_sugg = sugg[min(sugg.keys())]
+ if len(best_sugg) == 1:
+ LOGGER.info('Did you mean "{}"?'.format(best_sugg[0]))
+ else:
+ LOGGER.info('Did you mean "{}" or "{}"?'.format('", "'.join(best_sugg[:-1]), best_sugg[-1]))
return 3
+
if sub_cmds[args[0]] is not Help and not isinstance(sub_cmds[args[0]], Command): # Is a doit command
if not self.nikola.configured:
LOGGER.error("This command needs to run inside an "
@@ -331,15 +368,36 @@ class DoitNikola(DoitMain):
@staticmethod
def print_version():
+ """Print Nikola version."""
print("Nikola v" + __version__)
-# Stolen from http://stackoverflow.com/questions/4173579/implementing-levenshtein-distance-in-python
-def lev(a, b):
- if not a or not b:
- return max(len(a), len(b))
- return min(lev(a[1:], b[1:]) + (a[0] != b[0]), lev(a[1:], b) + 1, lev(a, b[1:]) + 1)
-
+def levenshtein(s1, s2):
+ u"""Calculate the Levenshtein distance of two strings.
+
+ Implementation from Wikibooks:
+ https://en.wikibooks.org/w/index.php?title=Algorithm_Implementation/Strings/Levenshtein_distance&oldid=2974448#Python
+ Copyright © The Wikibooks contributors (CC BY-SA/fair use citation); edited to match coding style and add an exception.
+ """
+ if len(s1) < len(s2):
+ return levenshtein(s2, s1)
+
+ # len(s1) >= len(s2)
+ if len(s2) == 0:
+ return len(s1)
+
+ previous_row = range(len(s2) + 1)
+ for i, c1 in enumerate(s1):
+ current_row = [i + 1]
+ for j, c2 in enumerate(s2):
+ # j+1 instead of j since previous_row and current_row are one character longer than s2
+ insertions = previous_row[j + 1] + 1
+ deletions = current_row[j] + 1
+ substitutions = previous_row[j] + (c1 != c2)
+ current_row.append(min(insertions, deletions, substitutions))
+ previous_row = current_row
+
+ return previous_row[-1]
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))