Commit b2f34ad9 authored by Jacek Sowiński's avatar Jacek Sowiński

Don't crash on shlex.split error

Show some meaningful error messages instead.

Fixes #107
parent 3adbc019
...@@ -4,3 +4,4 @@ baz = FooBar ...@@ -4,3 +4,4 @@ baz = FooBar
format = ls -F "|I| x c d {(}p{)} s k" -n 25 format = ls -F "|I| x c d {(}p{)} s k" -n 25
smile = ls smile = ls
star = tag {} star 1 star = tag {} star 1
quot = lol'd
...@@ -21,9 +21,8 @@ from topydo.Commands import get_subcommand ...@@ -21,9 +21,8 @@ from topydo.Commands import get_subcommand
from topydo.commands.AddCommand import AddCommand from topydo.commands.AddCommand import AddCommand
from topydo.commands.DeleteCommand import DeleteCommand from topydo.commands.DeleteCommand import DeleteCommand
from topydo.commands.ListCommand import ListCommand from topydo.commands.ListCommand import ListCommand
from topydo.commands.ListProjectCommand import ListProjectCommand
from topydo.commands.TagCommand import TagCommand from topydo.commands.TagCommand import TagCommand
from topydo.lib.Config import config from topydo.lib.Config import config, ConfigError
class GetSubcommandTest(TopydoTest): class GetSubcommandTest(TopydoTest):
def test_normal_cmd(self): def test_normal_cmd(self):
...@@ -120,6 +119,15 @@ class GetSubcommandTest(TopydoTest): ...@@ -120,6 +119,15 @@ class GetSubcommandTest(TopydoTest):
real_cmd, final_args = get_subcommand(args) real_cmd, final_args = get_subcommand(args)
self.assertEqual(real_cmd, None) self.assertEqual(real_cmd, None)
def test_alias_quotation(self):
config("test/data/aliases.conf")
args = ["quot"]
with self.assertRaises(ConfigError) as ce:
get_subcommand(args)
self.assertEqual(str(ce.exception), 'No closing quotation')
def test_help(self): def test_help(self):
real_cmd, final_args = get_subcommand(['help', 'nonexisting']) real_cmd, final_args = get_subcommand(['help', 'nonexisting'])
self.assertFalse(real_cmd) self.assertFalse(real_cmd)
......
...@@ -21,7 +21,7 @@ instance based on an argument list. ...@@ -21,7 +21,7 @@ instance based on an argument list.
import sys import sys
from topydo.lib.Config import config from topydo.lib.Config import config, ConfigError
_SUBCOMMAND_MAP = { _SUBCOMMAND_MAP = {
'add': 'AddCommand', 'add': 'AddCommand',
...@@ -90,7 +90,11 @@ def get_subcommand(p_args): ...@@ -90,7 +90,11 @@ def get_subcommand(p_args):
If alias resolves to non-existent command, main help message is If alias resolves to non-existent command, main help message is
returned. returned.
""" """
real_subcommand, alias_args = alias_map[p_alias] try:
real_subcommand, alias_args = alias_map[p_alias]
except ValueError as ve:
raise ConfigError(alias_map[p_alias]) from ve
try: try:
result = import_subcommand(real_subcommand) result = import_subcommand(real_subcommand)
args = join_args(p_args, alias_args) args = join_args(p_args, alias_args)
......
...@@ -50,7 +50,11 @@ class CLIApplication(CLIApplicationBase): ...@@ -50,7 +50,11 @@ class CLIApplication(CLIApplicationBase):
self.todofile = TodoFile.TodoFile(config().todotxt()) self.todofile = TodoFile.TodoFile(config().todotxt())
self.todolist = TodoList.TodoList(self.todofile.read()) self.todolist = TodoList.TodoList(self.todofile.read())
(subcommand, args) = get_subcommand(args) try:
(subcommand, args) = get_subcommand(args)
except ConfigError as ce:
error('Error: ' + str(ce) + '. Check your aliases configuration')
sys.exit(1)
if subcommand is None: if subcommand is None:
self._usage() self._usage()
......
...@@ -99,9 +99,16 @@ class PromptApplication(CLIApplicationBase): ...@@ -99,9 +99,16 @@ class PromptApplication(CLIApplicationBase):
sys.exit(0) sys.exit(0)
except KeyboardInterrupt: except KeyboardInterrupt:
continue continue
except ValueError as verr:
error('Error: ' + str(verr))
mtime_after = _todotxt_mtime() mtime_after = _todotxt_mtime()
(subcommand, args) = get_subcommand(user_input)
try:
(subcommand, args) = get_subcommand(user_input)
except ConfigError as ce:
error('Error: ' + str(ce) + '. Check your aliases configuration')
continue
# refuse to perform operations such as 'del' and 'do' if the # refuse to perform operations such as 'del' and 'do' if the
# todo.txt file has been changed in the background. # todo.txt file has been changed in the background.
......
...@@ -18,6 +18,7 @@ import configparser ...@@ -18,6 +18,7 @@ import configparser
import os import os
import shlex import shlex
class ConfigError(Exception): class ConfigError(Exception):
def __init__(self, p_text): def __init__(self, p_text):
self.text = p_text self.text = p_text
...@@ -299,10 +300,13 @@ class _Config: ...@@ -299,10 +300,13 @@ class _Config:
alias_dict = dict() alias_dict = dict()
for alias, meaning in aliases: for alias, meaning in aliases:
meaning = shlex.split(meaning) try:
real_subcommand = meaning[0] meaning = shlex.split(meaning)
alias_args = meaning[1:] real_subcommand = meaning[0]
alias_dict[alias] = (real_subcommand, alias_args) alias_args = meaning[1:]
alias_dict[alias] = (real_subcommand, alias_args)
except ValueError as verr:
alias_dict[alias] = str(verr)
return alias_dict return alias_dict
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment