diff --git a/jc/cli.py b/jc/cli.py index a5b1af01..7f16cf0e 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -183,29 +183,26 @@ def json_out(data, pretty=False): print(json.dumps(data)) -def magic(): - """Parse with magic syntax: jc -p ls -al""" - if len(sys.argv) <= 1 or sys.argv[1].startswith('--'): - return +def generate_magic_command(args): + """ + Returns a tuple with a boolean and a command, where the boolean signifies that + the command is valid, and the command is either a command string or None. + """ - magic_dict = {} - parser_info = about_jc()['parsers'] - - # Create a dictionary of magic_commands to their respective parsers. - for entry in parser_info: - # Update the dict with all of the magic commands for this parser, if they exist. - magic_dict.update({mc: entry['argument'] for mc in entry.get('magic_commands', [])}) + # Parse with magic syntax: jc -p ls -al + if len(args) <= 1 or args[1].startswith('--'): + return False, None # correctly parse escape characters and spaces with shlex - args_given = " ".join(map(shlex.quote, sys.argv[1:])).split() + args_given = " ".join(map(shlex.quote, args[1:])).split() options = [] # find the options popped = 0 - for i, arg in list(enumerate(args_given)): + for i, arg in enumerate(args_given): # parser found - use standard syntax if arg.startswith('--'): - return + return False, None # option found - populate option list elif arg.startswith('-'): @@ -218,7 +215,15 @@ def magic(): # all options popped and no command found - for case like 'jc -a' if len(args_given) == 0: - return + return False, None + + magic_dict = {} + parser_info = about_jc()['parsers'] + + # Create a dictionary of magic_commands to their respective parsers. + for entry in parser_info: + # Update the dict with all of the magic commands for this parser, if they exist. + magic_dict.update({mc: entry['argument'] for mc in entry.get('magic_commands', [])}) # find the command and parser one_word_command = args_given[0] @@ -230,11 +235,19 @@ def magic(): # construct a new command line using the standard syntax: COMMAND | jc --PARSER -OPTIONS run_command = ' '.join(args_given) if found_parser: - cmd_options = '-' + ''.join(options) if options else '' - whole_command = ' '.join([run_command, '|', 'jc', found_parser, cmd_options]) - os.system(whole_command) - exit() + cmd_options = ('-' + ''.join(options)) if options else '' + return True, ' '.join([run_command, '|', 'jc', found_parser, cmd_options]) + else: + return False, run_command + +def magic(): + valid_command, run_command = generate_magic_command(sys.argv) + if valid_command: + os.system(run_command) + exit() + elif run_command is None: + return else: helptext(f'parser not found for "{run_command}"') sys.exit(1) @@ -293,7 +306,8 @@ def main(): found = True break except Exception: - jc.utils.error_message(f'{parser_name} parser could not parse the input data. Did you use the correct parser?\n For details use the -d option.') + jc.utils.error_message( + f'{parser_name} parser could not parse the input data. Did you use the correct parser?\n For details use the -d option.') sys.exit(1) if not found: diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 00000000..fdd768da --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,21 @@ +import unittest +import jc.cli + + +class MyTests(unittest.TestCase): + def test_cli(self): + commands = { + 'jc -p systemctl list-sockets': 'systemctl list-sockets | jc --systemctl-ls -p', + 'jc -p systemctl list-unit-files': 'systemctl list-unit-files | jc --systemctl-luf -p', + 'jc -p pip list': 'pip list | jc --pip-list -p', + 'jc -p pip3 list': 'pip3 list | jc --pip-list -p', + 'jc -p pip show jc': 'pip show jc | jc --pip-show -p', + 'jc -p pip3 show jc': 'pip3 show jc | jc --pip-show -p', + 'jc -prd last': 'last | jc --last -prd', + 'jc -prd lastb': 'lastb | jc --last -prd', + 'jc -p nonexistent command': 'nonexistent command', + 'jc -ap': None + } + + for command, expected_command in commands.items(): + self.assertEqual(jc.cli.generate_magic_command(command.split(' '))[1], expected_command)