From 3b4ef4a8148c93433c67ff8c48947349d631254f Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 1 Jun 2022 12:13:41 -0700 Subject: [PATCH 01/46] formatting --- jc/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jc/cli.py b/jc/cli.py index b5fd8fe3..2f8bc65f 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -285,7 +285,7 @@ def yaml_out(data, pretty=False, env_colors=None, mono=False, piped_out=False, a # ruamel.yaml versions prior to 0.17.0 the use of __file__ in the # plugin code is incompatible with the pyoxidizer packager YAML.official_plug_ins = lambda a: [] - yaml=YAML() + yaml = YAML() yaml.default_flow_style = False yaml.explicit_start = True yaml.allow_unicode = not ascii_only From 504a04279ebc53b1a8c63cdd42ebe02f62482b62 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 1 Jun 2022 12:13:50 -0700 Subject: [PATCH 02/46] version bump --- CHANGELOG | 3 +++ jc/lib.py | 2 +- setup.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 37aafbfb..03f7511d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ jc changelog +20220601 v1.20.1 (in progress) +- Fix `id` parser for cases where the user or group name is not present + 20220531 v1.20.0 - Add YAML output option with `-y` - Add `top -b` standard and streaming parsers tested on linux diff --git a/jc/lib.py b/jc/lib.py index abc6334a..fb6d8dff 100644 --- a/jc/lib.py +++ b/jc/lib.py @@ -6,7 +6,7 @@ import importlib from typing import Dict, List, Iterable, Union, Iterator from jc import appdirs -__version__ = '1.20.0' +__version__ = '1.20.1' parsers = [ 'acpi', diff --git a/setup.py b/setup.py index 0840e010..1bcb83a0 100755 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ with open('README.md', 'r') as f: setuptools.setup( name='jc', - version='1.20.0', + version='1.20.1', author='Kelly Brazil', author_email='kellyjonbrazil@gmail.com', description='Converts the output of popular command-line tools and file-types to JSON.', From 57142d899c2261ae02b7f5797f412113cd79f510 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Wed, 1 Jun 2022 13:32:54 +0200 Subject: [PATCH 03/46] id: parse output without name If a group does not exist only gid is present in the command output. --- jc/parsers/id.py | 14 ++++++++++---- tests/test_id.py | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/jc/parsers/id.py b/jc/parsers/id.py index 82a06e6c..098daa18 100644 --- a/jc/parsers/id.py +++ b/jc/parsers/id.py @@ -105,7 +105,7 @@ import jc.utils class info(): """Provides parser metadata (version, author, etc.)""" - version = '1.4' + version = '1.5' description = '`id` command parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -158,6 +158,12 @@ def parse(data, raw=False, quiet=False): Dictionary. Raw or processed structured data. """ + def _get_item(list, index, default=None): + if index < len(list): + return list[index] + + return default + jc.utils.compatibility(__name__, info.compatible, quiet) jc.utils.input_type_check(data) @@ -174,14 +180,14 @@ def parse(data, raw=False, quiet=False): uid_parsed = uid_parsed.split('=') raw_output['uid'] = {} raw_output['uid']['id'] = uid_parsed[1] - raw_output['uid']['name'] = uid_parsed[2] + raw_output['uid']['name'] = _get_item(uid_parsed, 2) if section.startswith('gid'): gid_parsed = section.replace('(', '=').replace(')', '=') gid_parsed = gid_parsed.split('=') raw_output['gid'] = {} raw_output['gid']['id'] = gid_parsed[1] - raw_output['gid']['name'] = gid_parsed[2] + raw_output['gid']['name'] = _get_item(gid_parsed, 2) if section.startswith('groups'): groups_parsed = section.replace('(', '=').replace(')', '=') @@ -193,7 +199,7 @@ def parse(data, raw=False, quiet=False): group_dict = {} grp_parsed = group.split('=') group_dict['id'] = grp_parsed[0] - group_dict['name'] = grp_parsed[1] + group_dict['name'] = _get_item(grp_parsed, 1) raw_output['groups'].append(group_dict) if section.startswith('context'): diff --git a/tests/test_id.py b/tests/test_id.py index d139b3bf..b3752dfe 100644 --- a/tests/test_id.py +++ b/tests/test_id.py @@ -29,6 +29,20 @@ class MyTests(unittest.TestCase): """ self.assertEqual(jc.parsers.id.parse('', quiet=True), {}) + def test_id_no_name(self): + """ + Test 'id' with no name + """ + self.assertEqual( + jc.parsers.id.parse('uid=1000 gid=1000 groups=1000,10', quiet=True), + {'uid': {'id': 1000, 'name': None}, 'gid': {'id': 1000, 'name': None}, 'groups': [{'id': 1000, 'name': None}, {'id': 10, 'name': None}]} + ) + + self.assertEqual( + jc.parsers.id.parse('uid=1000(user) gid=1000 groups=1000,10(wheel)', quiet=True), + {'uid': {'id': 1000, 'name': 'user'}, 'gid': {'id': 1000, 'name': None}, 'groups': [{'id': 1000, 'name': None}, {'id': 10, 'name': 'wheel'}]} + ) + def test_id_centos_7_7(self): """ Test 'id' on Centos 7.7 From ec8efebc94311a9e27b388afff3a379b757d35d0 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 2 Jun 2022 08:31:28 -0700 Subject: [PATCH 04/46] move _get_item outside of parse function --- jc/parsers/id.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/jc/parsers/id.py b/jc/parsers/id.py index 098daa18..1176dc6d 100644 --- a/jc/parsers/id.py +++ b/jc/parsers/id.py @@ -144,6 +144,13 @@ def _process(proc_data): return proc_data +def _get_item(list, index, default=None): + if index < len(list): + return list[index] + + return default + + def parse(data, raw=False, quiet=False): """ Main text parsing function @@ -158,12 +165,6 @@ def parse(data, raw=False, quiet=False): Dictionary. Raw or processed structured data. """ - def _get_item(list, index, default=None): - if index < len(list): - return list[index] - - return default - jc.utils.compatibility(__name__, info.compatible, quiet) jc.utils.input_type_check(data) From a5d5b1554f8fb6d25182405b69ed6727de63d8fa Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 2 Jun 2022 08:34:51 -0700 Subject: [PATCH 05/46] change variable name from list to my_list --- jc/parsers/id.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jc/parsers/id.py b/jc/parsers/id.py index 1176dc6d..b1e47825 100644 --- a/jc/parsers/id.py +++ b/jc/parsers/id.py @@ -144,9 +144,9 @@ def _process(proc_data): return proc_data -def _get_item(list, index, default=None): - if index < len(list): - return list[index] +def _get_item(my_list, index, default=None): + if index < len(my_list): + return my_list[index] return default From b1507dc5760855f1a07ede991d495e58b6746a07 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 2 Jun 2022 09:14:02 -0700 Subject: [PATCH 06/46] initial postconf parser --- jc/lib.py | 1 + jc/parsers/postconf.py | 102 ++++++++++++++++++++++++++ tests/fixtures/generic/postconf-M.out | 31 ++++++++ 3 files changed, 134 insertions(+) create mode 100644 jc/parsers/postconf.py create mode 100644 tests/fixtures/generic/postconf-M.out diff --git a/jc/lib.py b/jc/lib.py index fb6d8dff..1733a351 100644 --- a/jc/lib.py +++ b/jc/lib.py @@ -73,6 +73,7 @@ parsers = [ 'ping-s', 'pip-list', 'pip-show', + 'postconf', 'ps', 'route', 'rpm-qi', diff --git a/jc/parsers/postconf.py b/jc/parsers/postconf.py new file mode 100644 index 00000000..15eadd62 --- /dev/null +++ b/jc/parsers/postconf.py @@ -0,0 +1,102 @@ +"""jc - JSON Convert `postconf -M` command output parser + +Usage (cli): + + $ postconf -M | jc --postconf + + or + + $ jc postconf -M + +Usage (module): + + import jc + result = jc.parse('postconf', postconf_command_output) + +Schema: + + [ + { + "postconf": string, + "bar": boolean, + "baz": integer + } + ] + +Examples: + + $ postconf | jc --postconf -p + [] + + $ postconf | jc --postconf -p -r + [] +""" +from typing import List, Dict +import jc.utils +from jc.parsers.universal import simple_table_parse + + +class info(): + """Provides parser metadata (version, author, etc.)""" + version = '1.0' + description = '`postconf -M` command parser' + author = 'Kelly Brazil' + author_email = 'kellyjonbrazil@gmail.com' + compatible = ['linux'] + magic_commands = ['postconf -M'] + + +__version__ = info.version + + +def _process(proc_data: List[Dict]) -> List[Dict]: + """ + Final processing to conform to the schema. + + Parameters: + + proc_data: (List of Dictionaries) raw structured data to process + + Returns: + + List of Dictionaries. Structured to conform to the schema. + """ + + # process the data here + # rebuild output for added semantic information + # use helper functions in jc.utils for int, float, bool + # conversions and timestamps + + return proc_data + + +def parse( + data: str, + raw: bool = False, + quiet: bool = False +) -> List[Dict]: + """ + Main text parsing function + + Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + + Returns: + + List of Dictionaries. Raw or processed structured data. + """ + jc.utils.compatibility(__name__, info.compatible, quiet) + jc.utils.input_type_check(data) + + raw_output: List = [] + + if jc.utils.has_data(data): + table = ['service_name service_type private unprivileged chroot wake_up_time process_limit command'] + data_list = list(filter(None, data.splitlines())) + table.extend(data_list) + raw_output = simple_table_parse(table) + + return raw_output if raw else _process(raw_output) diff --git a/tests/fixtures/generic/postconf-M.out b/tests/fixtures/generic/postconf-M.out new file mode 100644 index 00000000..187dd624 --- /dev/null +++ b/tests/fixtures/generic/postconf-M.out @@ -0,0 +1,31 @@ +smtp inet n - y - - smtpd +pickup unix n - y 60 1 pickup +cleanup unix n - y - 0 cleanup +qmgr unix n - n 300 1 qmgr +tlsmgr unix - - y 1000? 1 tlsmgr +rewrite unix - - y - - trivial-rewrite +bounce unix - - y - 0 bounce +defer unix - - y - 0 bounce +trace unix - - y - 0 bounce +verify unix - - y - 1 verify +flush unix n - y 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - y - - smtp +relay unix - - y - - smtp -o syslog_name=postfix/$service_name +showq unix n - y - - showq +error unix - - y - - error +retry unix - - y - - error +discard unix - - y - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - y - - lmtp +anvil unix - - y - 1 anvil +scache unix - - y - 1 scache +postlog unix-dgram n - n - 1 postlogd +maildrop unix - n n - - pipe flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient} +uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) +ifmail unix - n n - - pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) +bsmtp unix - n n - - pipe flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient +scalemail-backend unix - n n - 2 pipe flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} +mailman unix - n n - - pipe flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user} From f6dd5a68cdb93c6502d8314a164bb9cc1a3ccb3e Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 2 Jun 2022 09:28:00 -0700 Subject: [PATCH 07/46] doc update --- CHANGELOG | 1 + jc/parsers/postconf.py | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 03f7511d..aaab44a3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ jc changelog 20220601 v1.20.1 (in progress) +- Add `postconf -M` parser tested on linux - Fix `id` parser for cases where the user or group name is not present 20220531 v1.20.0 diff --git a/jc/parsers/postconf.py b/jc/parsers/postconf.py index 15eadd62..d0a318f1 100644 --- a/jc/parsers/postconf.py +++ b/jc/parsers/postconf.py @@ -17,12 +17,22 @@ Schema: [ { - "postconf": string, - "bar": boolean, - "baz": integer + "service_name": string, + "service_type": string, + "private": boolean/null, # [0] + "unprivileged": boolean/null, # [0] + "chroot": boolean/null, # [0] + "wake_up_time": integer, # [1] + "no_wake_up_before_first_use": boolean/null, # [2] + "process_limit": integer, + "command": string } ] + [0] '-' converted to null/None + [1] '-' converted to -1 + [2] null/None if `wake_up_time` is null/None + Examples: $ postconf | jc --postconf -p From 6cde26d9ed0bffa281b2b3eacc3676fd3dec7b90 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Thu, 2 Jun 2022 14:53:31 -0700 Subject: [PATCH 08/46] add process logic --- jc/parsers/postconf.py | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/jc/parsers/postconf.py b/jc/parsers/postconf.py index d0a318f1..ee579dd5 100644 --- a/jc/parsers/postconf.py +++ b/jc/parsers/postconf.py @@ -24,7 +24,7 @@ Schema: "chroot": boolean/null, # [0] "wake_up_time": integer, # [1] "no_wake_up_before_first_use": boolean/null, # [2] - "process_limit": integer, + "process_limit": integer, # [1] "command": string } ] @@ -71,11 +71,36 @@ def _process(proc_data: List[Dict]) -> List[Dict]: List of Dictionaries. Structured to conform to the schema. """ + for item in proc_data: + if item['private'] == '-': + item['private'] = None + else: + item['private'] = jc.utils.convert_to_bool(item['private']) - # process the data here - # rebuild output for added semantic information - # use helper functions in jc.utils for int, float, bool - # conversions and timestamps + if item['unprivileged'] == '-': + item['unprivileged'] = None + else: + item['unprivileged'] = jc.utils.convert_to_bool(item['unprivileged']) + + if item['chroot'] == '-': + item['chroot'] = None + else: + item['chroot'] = jc.utils.convert_to_bool(item['chroot']) + + if item['wake_up_time'].endswith('?'): + item['no_wake_up_before_first_use'] = True + else: + item['no_wake_up_before_first_use'] = False + + if item['wake_up_time'] == '-': + item['wake_up_time'] = -1 + else: + item['wake_up_time'] = jc.utils.convert_to_int(item['wake_up_time']) + + if item['process_limit'] == '-': + item['process_limit'] = -1 + else: + item['process_limit'] = jc.utils.convert_to_int(item['process_limit']) return proc_data From 437fa62cb16ec2c5096f309e03385c0823ca6977 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 3 Jun 2022 10:29:55 -0700 Subject: [PATCH 09/46] update schema --- jc/parsers/postconf.py | 46 +++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/jc/parsers/postconf.py b/jc/parsers/postconf.py index ee579dd5..00a8715d 100644 --- a/jc/parsers/postconf.py +++ b/jc/parsers/postconf.py @@ -22,16 +22,15 @@ Schema: "private": boolean/null, # [0] "unprivileged": boolean/null, # [0] "chroot": boolean/null, # [0] - "wake_up_time": integer, # [1] - "no_wake_up_before_first_use": boolean/null, # [2] - "process_limit": integer, # [1] + "wake_up_time": integer/null, # [0] + "no_wake_up_before_first_use": boolean/null, # [1] + "process_limit": integer/null, # [0] "command": string } ] [0] '-' converted to null/None - [1] '-' converted to -1 - [2] null/None if `wake_up_time` is null/None + [1] null/None if `wake_up_time` is null/None Examples: @@ -71,36 +70,27 @@ def _process(proc_data: List[Dict]) -> List[Dict]: List of Dictionaries. Structured to conform to the schema. """ + keys = ['private', 'unprivileged', 'chroot', 'wake_up_time', 'process_limit'] + bools = ['private', 'unprivileged', 'chroot'] + integers = ['wake_up_time', 'process_limit'] + for item in proc_data: - if item['private'] == '-': - item['private'] = None - else: - item['private'] = jc.utils.convert_to_bool(item['private']) - - if item['unprivileged'] == '-': - item['unprivileged'] = None - else: - item['unprivileged'] = jc.utils.convert_to_bool(item['unprivileged']) - - if item['chroot'] == '-': - item['chroot'] = None - else: - item['chroot'] = jc.utils.convert_to_bool(item['chroot']) - if item['wake_up_time'].endswith('?'): item['no_wake_up_before_first_use'] = True else: item['no_wake_up_before_first_use'] = False - if item['wake_up_time'] == '-': - item['wake_up_time'] = -1 - else: - item['wake_up_time'] = jc.utils.convert_to_int(item['wake_up_time']) + for key in keys: + if item[key] == '-': + item[key] = None - if item['process_limit'] == '-': - item['process_limit'] = -1 - else: - item['process_limit'] = jc.utils.convert_to_int(item['process_limit']) + for key in bools: + if item[key] is not None: + item[key] = jc.utils.convert_to_bool(item[key]) + + for key in integers: + if item[key] is not None: + item[key] = jc.utils.convert_to_int(item[key]) return proc_data From 1d6bc40bfff971d3148a51f2ecdd85a9199342c3 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 3 Jun 2022 10:35:49 -0700 Subject: [PATCH 10/46] fix no_wake_up_before_first_use to allow None --- jc/parsers/postconf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jc/parsers/postconf.py b/jc/parsers/postconf.py index 00a8715d..1ce6172b 100644 --- a/jc/parsers/postconf.py +++ b/jc/parsers/postconf.py @@ -77,6 +77,8 @@ def _process(proc_data: List[Dict]) -> List[Dict]: for item in proc_data: if item['wake_up_time'].endswith('?'): item['no_wake_up_before_first_use'] = True + elif item['wake_up_time'] == '-': + item['no_wake_up_before_first_use'] = None else: item['no_wake_up_before_first_use'] = False From a38b6b552233a9080dae54067960ee419f38a22b Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 12:12:58 -0700 Subject: [PATCH 11/46] add long options --- jc/cli.py | 87 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/jc/cli.py b/jc/cli.py index 2f8bc65f..37dd5993 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -9,6 +9,7 @@ import textwrap import signal import shlex import subprocess +from typing import List, Dict from .lib import (__version__, parser_info, all_parser_info, parsers, _get_parser, _parser_is_streaming, standard_parser_mod_list, plugin_parser_mod_list, streaming_parser_mod_list) @@ -83,6 +84,19 @@ if PYGMENTS_INSTALLED: 'white': 'ansiwhite', } +long_options_map: Dict[str, List[str]] = { + '--about': ['a', 'about jc'], + '--force-color': ['C', 'force color output even when using pipes (overrides -m)'], + '--debug': ['d', 'debug (double for verbose debug)'], + '--help': ['h', 'help (--help --parser_name for parser documentation)'], + '--monochrome': ['m', 'monochrome output'], + '--pretty': ['p', 'pretty print output'], + '--quiet': ['q', 'suppress warnings (double to ignore streaming errors)'], + '--raw': ['r', 'raw output'], + '--unbuffer': ['u', 'unbuffer output'], + '--version': ['v', 'version info'], + '--yaml-out': ['y', 'YAML output'] +} def set_env_colors(env_colors=None): """ @@ -166,6 +180,22 @@ def parsers_text(indent=0, pad=0): return ptext +def options_text(indent=0, pad=0): + """Return the argument and description information from each option""" + otext = '' + padding_char = ' ' + for option in long_options_map: + o_short = '-' + long_options_map[option][0] + o_desc = long_options_map[option][1] + o_combined = o_short + ', ' + option + padding = pad - len(o_combined) + indent_text = padding_char * indent + padding_text = padding_char * padding + otext += indent_text + o_combined + padding_text + o_desc + '\n' + + return otext + + def about_jc(): """Return jc info and the contents of each parser.info as a dictionary""" return { @@ -189,43 +219,35 @@ def about_jc(): def helptext(): """Return the help text with the list of parsers""" - parsers_string = parsers_text(indent=12, pad=17) + parsers_string = parsers_text(indent=4, pad=20) + options_string = options_text(indent=4, pad=20) helptext_string = f'''\ - jc converts the output of many commands and file-types to JSON +jc converts the output of many commands and file-types to JSON or YAML - Usage: COMMAND | jc PARSER [OPTIONS] +Usage: + COMMAND | jc PARSER [OPTIONS] - or magic syntax: + or magic syntax: - jc [OPTIONS] COMMAND + jc [OPTIONS] COMMAND - Parsers: +Parsers: {parsers_string} - Options: - -a about jc - -C force color output even when using pipes (overrides -m) - -d debug (-dd for verbose debug) - -h help (-h --parser_name for parser documentation) - -m monochrome output - -p pretty print output - -q quiet - suppress parser warnings (-qq to ignore streaming errors) - -r raw JSON output - -u unbuffer output - -v version info - -y YAML output +Options: +{options_string} +Examples: + Standard Syntax: + $ dig www.google.com | jc --dig --pretty - Examples: - Standard Syntax: - $ dig www.google.com | jc --dig -p + Magic Syntax: + $ jc --pretty dig www.google.com - Magic Syntax: - $ jc -p dig www.google.com - - Parser Documentation: - $ jc -h --dig + Parser Documentation: + $ jc --help --dig ''' - return textwrap.dedent(helptext_string) + + return helptext_string def help_doc(options): @@ -381,7 +403,7 @@ def magic_parser(args): jc_options (list) list of jc options """ # bail immediately if there are no args or a parser is defined - if len(args) <= 1 or args[1].startswith('--'): + if len(args) <= 1 or (args[1].startswith('--') and args[1] not in long_options_map): return False, None, None, [] args_given = args[1:] @@ -389,6 +411,12 @@ def magic_parser(args): # find the options for arg in list(args_given): + # long option found - populate option list + if arg in long_options_map: + options.extend(long_options_map[arg][0]) + args_given.pop(0) + continue + # parser found - use standard syntax if arg.startswith('--'): return False, None, None, [] @@ -483,6 +511,9 @@ def main(): # find options if magic_parser did not find a command if not valid_command: for opt in sys.argv: + if opt in long_options_map: + options.extend(long_options_map[opt][0]) + if opt.startswith('-') and not opt.startswith('--'): options.extend(opt[1:]) From 5996192455f613fd5417986f153c79387d43cb77 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 12:16:30 -0700 Subject: [PATCH 12/46] remove indent at end of help text --- jc/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jc/cli.py b/jc/cli.py index 37dd5993..927b25fe 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -245,7 +245,7 @@ Examples: Parser Documentation: $ jc --help --dig - ''' +''' return helptext_string From d849bd3b66c2af7802a3be62b116f2f9ff8099ce Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 16:23:55 -0700 Subject: [PATCH 13/46] add bash and zsh completions to cli --- jc/cli.py | 25 +++++++------ jc/cli_data.py | 18 ++++++++++ jc/shell_completions.py | 79 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 jc/cli_data.py create mode 100644 jc/shell_completions.py diff --git a/jc/cli.py b/jc/cli.py index 927b25fe..c74c73be 100644 --- a/jc/cli.py +++ b/jc/cli.py @@ -14,6 +14,8 @@ from .lib import (__version__, parser_info, all_parser_info, parsers, _get_parser, _parser_is_streaming, standard_parser_mod_list, plugin_parser_mod_list, streaming_parser_mod_list) from . import utils +from .cli_data import long_options_map +from .shell_completions import bash_completion, zsh_completion from . import tracebackplus from .exceptions import LibraryNotInstalled, ParseError @@ -84,19 +86,6 @@ if PYGMENTS_INSTALLED: 'white': 'ansiwhite', } -long_options_map: Dict[str, List[str]] = { - '--about': ['a', 'about jc'], - '--force-color': ['C', 'force color output even when using pipes (overrides -m)'], - '--debug': ['d', 'debug (double for verbose debug)'], - '--help': ['h', 'help (--help --parser_name for parser documentation)'], - '--monochrome': ['m', 'monochrome output'], - '--pretty': ['p', 'pretty print output'], - '--quiet': ['q', 'suppress warnings (double to ignore streaming errors)'], - '--raw': ['r', 'raw output'], - '--unbuffer': ['u', 'unbuffer output'], - '--version': ['v', 'version info'], - '--yaml-out': ['y', 'YAML output'] -} def set_env_colors(env_colors=None): """ @@ -530,6 +519,8 @@ def main(): unbuffer = 'u' in options version_info = 'v' in options yaml_out = 'y' in options + bash_comp = 'B' in options + zsh_comp = 'Z' in options if verbose_debug: tracebackplus.enable(context=11) @@ -554,6 +545,14 @@ def main(): utils._safe_print(versiontext()) sys.exit(0) + if bash_comp: + utils._safe_print(bash_completion()) + sys.exit(0) + + if zsh_comp: + utils._safe_print(zsh_completion()) + sys.exit(0) + # if magic syntax used, try to run the command and error if it's not found, etc. magic_stdout, magic_stderr, magic_exit_code = None, None, 0 if run_command: diff --git a/jc/cli_data.py b/jc/cli_data.py new file mode 100644 index 00000000..f9f6ed2f --- /dev/null +++ b/jc/cli_data.py @@ -0,0 +1,18 @@ +"""jc - JSON Convert cli_data module""" +from typing import List, Dict + +long_options_map: Dict[str, List[str]] = { + '--about': ['a', 'about jc'], + '--force-color': ['C', 'force color output even when using pipes (overrides -m)'], + '--debug': ['d', 'debug (double for verbose debug)'], + '--help': ['h', 'help (--help --parser_name for parser documentation)'], + '--monochrome': ['m', 'monochrome output'], + '--pretty': ['p', 'pretty print output'], + '--quiet': ['q', 'suppress warnings (double to ignore streaming errors)'], + '--raw': ['r', 'raw output'], + '--unbuffer': ['u', 'unbuffer output'], + '--version': ['v', 'version info'], + '--yaml-out': ['y', 'YAML output'], + '--bash-comp': ['B', 'gen Bash completion: jc -B > /etc/bash_completion.d/jc'], + '--zsh-comp': ['Z', 'gen Zsh completion: jc -Z > "${fpath[1]}/_jc"'] +} diff --git a/jc/shell_completions.py b/jc/shell_completions.py new file mode 100644 index 00000000..d5567959 --- /dev/null +++ b/jc/shell_completions.py @@ -0,0 +1,79 @@ +"""jc - JSON Convert shell_completions module""" + +from string import Template +from .cli_data import long_options_map +from .lib import all_parser_info + +# $(jc -a | jq -r '.parsers[] | .argument, .magic_commands[]?') +bash_template = Template('''\ +complete -W "${bash_arguments}${bash_options}${bash_commands}" jc +''') + +zsh_template = Template('''\ +#compdef jc + +_jc() { + # autogenerate completions based on jc --help output + _arguments -- + + # add commands supported by magic syntax + local -a commands + commands=( + # e.g. 'arp:run arp with magic syntax.' + ${zsh_commands} + ) + + _describe -t commands 'commands' commands + return 0 +} + +_jc +''') + +def get_commands(): + command_list = [] + for cmd in all_parser_info(): + if 'magic_commands' in cmd: + command_list.extend(cmd['magic_commands']) + + return list(set([i.split()[0] for i in command_list])) + + +def get_options(): + options_list = [] + for opt in long_options_map: + options_list.append(opt) + options_list.append('-' + long_options_map[opt][0]) + + return options_list + + +def get_arguments(): + arg_list = [] + for cmd in all_parser_info(): + if 'argument' in cmd: + arg_list.append(cmd['argument']) + + return arg_list + + +def gen_zsh_command_descriptions(command_list): + zsh_commands = [] + for cmd in command_list: + zsh_commands.append(f"""'{cmd}:run "{cmd}" command with magic syntax.'""") + + return zsh_commands + + +def bash_completion(): + args = '\n'.join(get_arguments()) + options = '\n' + '\n'.join(get_options()) + commands = '\n' + '\n'.join(get_commands()) + return bash_template.substitute(bash_arguments=args, + bash_options=options, + bash_commands=commands) + + +def zsh_completion(): + commands = '\n '.join(gen_zsh_command_descriptions(get_commands())) + return zsh_template.substitute(zsh_commands=commands) From 26415e297846a2e82ab27eca1d70693042e07385 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 17:17:13 -0700 Subject: [PATCH 14/46] formatting --- jc/shell_completions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index d5567959..a04ccc98 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -4,11 +4,12 @@ from string import Template from .cli_data import long_options_map from .lib import all_parser_info -# $(jc -a | jq -r '.parsers[] | .argument, .magic_commands[]?') + bash_template = Template('''\ complete -W "${bash_arguments}${bash_options}${bash_commands}" jc ''') + zsh_template = Template('''\ #compdef jc @@ -30,6 +31,7 @@ _jc() { _jc ''') + def get_commands(): command_list = [] for cmd in all_parser_info(): From da6c98826bba3c5c0fbbc41bc0e319f85b1d66cf Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 17:40:05 -0700 Subject: [PATCH 15/46] doc update --- README.md | 3 ++ docs/parsers/id.md | 2 +- docs/parsers/postconf.md | 71 ++++++++++++++++++++++++++++++++++++++ man/jc.1 | 15 +++++++- templates/manpage_template | 8 +++++ templates/readme_template | 2 ++ 6 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 docs/parsers/postconf.md diff --git a/README.md b/README.md index 5539453f..ecdaaf3f 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,7 @@ option. | ` --ping-s` | `ping` and `ping6` command streaming parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/ping_s) | | ` --pip-list` | `pip list` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/pip_list) | | ` --pip-show` | `pip show` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/pip_show) | +| ` --postconf` | `postconf -M` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/postconf) | | ` --ps` | `ps` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/ps) | | ` --route` | `route` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/route) | | ` --rpm-qi` | `rpm -qi` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/rpm_qi) | @@ -266,6 +267,8 @@ option. - `-u` unbuffer output - `-v` version information - `-y` YAML output +- `-B` generate Bash shell completion script +- `-Z` generate Zsh shell completion script ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the diff --git a/docs/parsers/id.md b/docs/parsers/id.md index df76f94a..976e0cf3 100644 --- a/docs/parsers/id.md +++ b/docs/parsers/id.md @@ -128,4 +128,4 @@ Returns: ### Parser Information Compatibility: linux, darwin, aix, freebsd -Version 1.4 by Kelly Brazil (kellyjonbrazil@gmail.com) +Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/postconf.md b/docs/parsers/postconf.md new file mode 100644 index 00000000..6f481375 --- /dev/null +++ b/docs/parsers/postconf.md @@ -0,0 +1,71 @@ +[Home](https://kellyjonbrazil.github.io/jc/) + + +# jc.parsers.postconf + +jc - JSON Convert `postconf -M` command output parser + +Usage (cli): + + $ postconf -M | jc --postconf + + or + + $ jc postconf -M + +Usage (module): + + import jc + result = jc.parse('postconf', postconf_command_output) + +Schema: + + [ + { + "service_name": string, + "service_type": string, + "private": boolean/null, # [0] + "unprivileged": boolean/null, # [0] + "chroot": boolean/null, # [0] + "wake_up_time": integer/null, # [0] + "no_wake_up_before_first_use": boolean/null, # [1] + "process_limit": integer/null, # [0] + "command": string + } + ] + + [0] '-' converted to null/None + [1] null/None if `wake_up_time` is null/None + +Examples: + + $ postconf | jc --postconf -p + [] + + $ postconf | jc --postconf -p -r + [] + + + +### parse + +```python +def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict] +``` + +Main text parsing function + +Parameters: + + data: (string) text data to parse + raw: (boolean) unprocessed output if True + quiet: (boolean) suppress warning messages if True + +Returns: + + List of Dictionaries. Raw or processed structured data. + +### Parser Information +Compatibility: linux + +Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/man/jc.1 b/man/jc.1 index c762d7b8..e200dfa7 100644 --- a/man/jc.1 +++ b/man/jc.1 @@ -1,4 +1,4 @@ -.TH jc 1 2022-05-31 1.20.0 "JSON Convert" +.TH jc 1 2022-06-05 1.20.1 "JSON Convert" .SH NAME \fBjc\fP \- JSON Convert JSONifies the output of many CLI tools and file-types .SH SYNOPSIS @@ -337,6 +337,11 @@ Key/Value file parser \fB--pip-show\fP `pip show` command parser +.TP +.B +\fB--postconf\fP +`postconf -M` command parser + .TP .B \fB--ps\fP @@ -578,6 +583,14 @@ version information .B \fB-y\fP YAML output +.TP +.B +\fB-B\fP +generate Bash shell completion script +.TP +.B +\fB-Z\fP +generate Zsh shell completion script .SH EXIT CODES Any fatal errors within \fBjc\fP will generate an exit code of \fB100\fP, otherwise the exit code will be \fB0\fP. When using the "Magic" syntax (e.g. \fBjc ifconfig eth0\fP), \fBjc\fP will store the exit code of the program being parsed and add it to the \fBjc\fP exit code. This way it is easier to determine if an error was from the parsed program or \fBjc\fP. diff --git a/templates/manpage_template b/templates/manpage_template index a8effee5..d175b0db 100644 --- a/templates/manpage_template +++ b/templates/manpage_template @@ -73,6 +73,14 @@ version information .B \fB-y\fP YAML output +.TP +.B +\fB-B\fP +generate Bash shell completion script +.TP +.B +\fB-Z\fP +generate Zsh shell completion script .SH EXIT CODES Any fatal errors within \fBjc\fP will generate an exit code of \fB100\fP, otherwise the exit code will be \fB0\fP. When using the "Magic" syntax (e.g. \fBjc ifconfig eth0\fP), \fBjc\fP will store the exit code of the program being parsed and add it to the \fBjc\fP exit code. This way it is easier to determine if an error was from the parsed program or \fBjc\fP. diff --git a/templates/readme_template b/templates/readme_template index d5a2be35..1d4a8adf 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -165,6 +165,8 @@ option. - `-u` unbuffer output - `-v` version information - `-y` YAML output +- `-B` generate Bash shell completion script +- `-Z` generate Zsh shell completion script ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the From 15b58e3a6b307d858e228ad67153371fe6a70baf Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 17:52:14 -0700 Subject: [PATCH 16/46] add long-options --- README.md | 33 +++++++++++++++------------------ templates/readme_template | 33 +++++++++++++++------------------ 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index ecdaaf3f..35db0982 100644 --- a/README.md +++ b/README.md @@ -251,24 +251,21 @@ option. | ` --zipinfo` | `zipinfo` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/zipinfo) | ### Options -- `-a` about `jc`. Prints information about `jc` and the parsers (in JSON or - YAML, of course!) -- `-C` force color output even when using pipes (overrides `-m` and the - `NO_COLOR` env variable) -- `-d` debug mode. Prints trace messages if parsing issues are encountered (use - `-dd` for verbose debugging) -- `-h` help. Use `jc -h --parser_name` for parser documentation -- `-m` monochrome JSON output -- `-p` pretty format the JSON output -- `-q` quiet mode. Suppresses parser warning messages (use `-qq` to ignore - streaming parser errors) -- `-r` raw output. Provides a more literal JSON output, typically with string - values and no additional semantic processing -- `-u` unbuffer output -- `-v` version information -- `-y` YAML output -- `-B` generate Bash shell completion script -- `-Z` generate Zsh shell completion script +| Option | Description | +|-----------------------|--------------------------------------------------------------------------------------------------------------| +| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C`, `--force_color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | +| `-m`, `--monochrome` | monochrome output | +| `-p`, `--pretty` | pretty format the JSON output | +| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u`, `--unbuffer` | unbuffer output | +| `-v`, `--version` | version information | +| `-y`, `--yaml-out` | YAML output | +| `-B`, `--bash-comp` | generate Bash shell completion script | +| `-Z`, `--zsh-comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the diff --git a/templates/readme_template b/templates/readme_template index 1d4a8adf..4465d588 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -149,24 +149,21 @@ option. | `{{ "{:>15}".format(parser.argument) }}` | {{ "{:<55}".format(parser.description) }} | {{ "{:<70}".format("[📃](https://kellyjonbrazil.github.io/jc/docs/parsers/" + parser.name + ")") }} |{% endfor %} ### Options -- `-a` about `jc`. Prints information about `jc` and the parsers (in JSON or - YAML, of course!) -- `-C` force color output even when using pipes (overrides `-m` and the - `NO_COLOR` env variable) -- `-d` debug mode. Prints trace messages if parsing issues are encountered (use - `-dd` for verbose debugging) -- `-h` help. Use `jc -h --parser_name` for parser documentation -- `-m` monochrome JSON output -- `-p` pretty format the JSON output -- `-q` quiet mode. Suppresses parser warning messages (use `-qq` to ignore - streaming parser errors) -- `-r` raw output. Provides a more literal JSON output, typically with string - values and no additional semantic processing -- `-u` unbuffer output -- `-v` version information -- `-y` YAML output -- `-B` generate Bash shell completion script -- `-Z` generate Zsh shell completion script +| Option | Description | +|-----------------------|--------------------------------------------------------------------------------------------------------------| +| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C`, `--force_color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | +| `-m`, `--monochrome` | monochrome output | +| `-p`, `--pretty` | pretty format the JSON output | +| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u`, `--unbuffer` | unbuffer output | +| `-v`, `--version` | version information | +| `-y`, `--yaml-out` | YAML output | +| `-B`, `--bash-comp` | generate Bash shell completion script | +| `-Z`, `--zsh-comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the From f17b3fbd322ea48a443f16406afc419201838660 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 17:54:34 -0700 Subject: [PATCH 17/46] add non-breaking hyphens --- README.md | 26 +++++++++++++------------- templates/readme_template | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 35db0982..c32cdbee 100644 --- a/README.md +++ b/README.md @@ -253,19 +253,19 @@ option. ### Options | Option | Description | |-----------------------|--------------------------------------------------------------------------------------------------------------| -| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `-C`, `--force_color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | -| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | -| `-m`, `--monochrome` | monochrome output | -| `-p`, `--pretty` | pretty format the JSON output | -| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | -| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `-u`, `--unbuffer` | unbuffer output | -| `-v`, `--version` | version information | -| `-y`, `--yaml-out` | YAML output | -| `-B`, `--bash-comp` | generate Bash shell completion script | -| `-Z`, `--zsh-comp` | generate Zsh shell completion script | +| `‑a`, `‑‑about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `‑C`, `‑‑force_color` | force color output even when using pipes (overrides `‑m` and the `NO_COLOR` env variable) | +| `‑d`, `‑‑debug` | debug mode. Prints trace messages if parsing issues are encountered (use`‑dd` for verbose debugging) | +| `‑h`, `‑‑help` | help. Use `jc ‑h ‑‑parser_name` for parser documentation | +| `‑m`, `‑‑monochrome` | monochrome output | +| `‑p`, `‑‑pretty` | pretty format the JSON output | +| `‑q`, `‑‑quiet` | quiet mode. Suppresses parser warning messages (use `‑qq` to ignore streaming parser errors) | +| `‑r`, `‑‑raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `‑u`, `‑‑unbuffer` | unbuffer output | +| `‑v`, `‑‑version` | version information | +| `‑y`, `‑‑yaml‑out` | YAML output | +| `‑B`, `‑‑bash‑comp` | generate Bash shell completion script | +| `‑Z`, `‑‑zsh‑comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the diff --git a/templates/readme_template b/templates/readme_template index 4465d588..38bb61ab 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -151,19 +151,19 @@ option. ### Options | Option | Description | |-----------------------|--------------------------------------------------------------------------------------------------------------| -| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `-C`, `--force_color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | -| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | -| `-m`, `--monochrome` | monochrome output | -| `-p`, `--pretty` | pretty format the JSON output | -| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | -| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `-u`, `--unbuffer` | unbuffer output | -| `-v`, `--version` | version information | -| `-y`, `--yaml-out` | YAML output | -| `-B`, `--bash-comp` | generate Bash shell completion script | -| `-Z`, `--zsh-comp` | generate Zsh shell completion script | +| `‑a`, `‑‑about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `‑C`, `‑‑force_color` | force color output even when using pipes (overrides `‑m` and the `NO_COLOR` env variable) | +| `‑d`, `‑‑debug` | debug mode. Prints trace messages if parsing issues are encountered (use`‑dd` for verbose debugging) | +| `‑h`, `‑‑help` | help. Use `jc ‑h ‑‑parser_name` for parser documentation | +| `‑m`, `‑‑monochrome` | monochrome output | +| `‑p`, `‑‑pretty` | pretty format the JSON output | +| `‑q`, `‑‑quiet` | quiet mode. Suppresses parser warning messages (use `‑qq` to ignore streaming parser errors) | +| `‑r`, `‑‑raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `‑u`, `‑‑unbuffer` | unbuffer output | +| `‑v`, `‑‑version` | version information | +| `‑y`, `‑‑yaml‑out` | YAML output | +| `‑B`, `‑‑bash‑comp` | generate Bash shell completion script | +| `‑Z`, `‑‑zsh‑comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the From 020093fd67cee841291e8115881a8e6418417582 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 18:04:35 -0700 Subject: [PATCH 18/46] revert non-breaking hyphens --- README.md | 33 +++++++++++++++------------------ templates/readme_template | 33 +++++++++++++++------------------ 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index ecdaaf3f..c32cdbee 100644 --- a/README.md +++ b/README.md @@ -251,24 +251,21 @@ option. | ` --zipinfo` | `zipinfo` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/zipinfo) | ### Options -- `-a` about `jc`. Prints information about `jc` and the parsers (in JSON or - YAML, of course!) -- `-C` force color output even when using pipes (overrides `-m` and the - `NO_COLOR` env variable) -- `-d` debug mode. Prints trace messages if parsing issues are encountered (use - `-dd` for verbose debugging) -- `-h` help. Use `jc -h --parser_name` for parser documentation -- `-m` monochrome JSON output -- `-p` pretty format the JSON output -- `-q` quiet mode. Suppresses parser warning messages (use `-qq` to ignore - streaming parser errors) -- `-r` raw output. Provides a more literal JSON output, typically with string - values and no additional semantic processing -- `-u` unbuffer output -- `-v` version information -- `-y` YAML output -- `-B` generate Bash shell completion script -- `-Z` generate Zsh shell completion script +| Option | Description | +|-----------------------|--------------------------------------------------------------------------------------------------------------| +| `‑a`, `‑‑about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `‑C`, `‑‑force_color` | force color output even when using pipes (overrides `‑m` and the `NO_COLOR` env variable) | +| `‑d`, `‑‑debug` | debug mode. Prints trace messages if parsing issues are encountered (use`‑dd` for verbose debugging) | +| `‑h`, `‑‑help` | help. Use `jc ‑h ‑‑parser_name` for parser documentation | +| `‑m`, `‑‑monochrome` | monochrome output | +| `‑p`, `‑‑pretty` | pretty format the JSON output | +| `‑q`, `‑‑quiet` | quiet mode. Suppresses parser warning messages (use `‑qq` to ignore streaming parser errors) | +| `‑r`, `‑‑raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `‑u`, `‑‑unbuffer` | unbuffer output | +| `‑v`, `‑‑version` | version information | +| `‑y`, `‑‑yaml‑out` | YAML output | +| `‑B`, `‑‑bash‑comp` | generate Bash shell completion script | +| `‑Z`, `‑‑zsh‑comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the diff --git a/templates/readme_template b/templates/readme_template index 1d4a8adf..38bb61ab 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -149,24 +149,21 @@ option. | `{{ "{:>15}".format(parser.argument) }}` | {{ "{:<55}".format(parser.description) }} | {{ "{:<70}".format("[📃](https://kellyjonbrazil.github.io/jc/docs/parsers/" + parser.name + ")") }} |{% endfor %} ### Options -- `-a` about `jc`. Prints information about `jc` and the parsers (in JSON or - YAML, of course!) -- `-C` force color output even when using pipes (overrides `-m` and the - `NO_COLOR` env variable) -- `-d` debug mode. Prints trace messages if parsing issues are encountered (use - `-dd` for verbose debugging) -- `-h` help. Use `jc -h --parser_name` for parser documentation -- `-m` monochrome JSON output -- `-p` pretty format the JSON output -- `-q` quiet mode. Suppresses parser warning messages (use `-qq` to ignore - streaming parser errors) -- `-r` raw output. Provides a more literal JSON output, typically with string - values and no additional semantic processing -- `-u` unbuffer output -- `-v` version information -- `-y` YAML output -- `-B` generate Bash shell completion script -- `-Z` generate Zsh shell completion script +| Option | Description | +|-----------------------|--------------------------------------------------------------------------------------------------------------| +| `‑a`, `‑‑about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `‑C`, `‑‑force_color` | force color output even when using pipes (overrides `‑m` and the `NO_COLOR` env variable) | +| `‑d`, `‑‑debug` | debug mode. Prints trace messages if parsing issues are encountered (use`‑dd` for verbose debugging) | +| `‑h`, `‑‑help` | help. Use `jc ‑h ‑‑parser_name` for parser documentation | +| `‑m`, `‑‑monochrome` | monochrome output | +| `‑p`, `‑‑pretty` | pretty format the JSON output | +| `‑q`, `‑‑quiet` | quiet mode. Suppresses parser warning messages (use `‑qq` to ignore streaming parser errors) | +| `‑r`, `‑‑raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `‑u`, `‑‑unbuffer` | unbuffer output | +| `‑v`, `‑‑version` | version information | +| `‑y`, `‑‑yaml‑out` | YAML output | +| `‑B`, `‑‑bash‑comp` | generate Bash shell completion script | +| `‑Z`, `‑‑zsh‑comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the From 901763fc39f5342839d112876b843264cf866df8 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 18:06:38 -0700 Subject: [PATCH 19/46] fix hyphens --- README.md | 26 +++++++++++++------------- templates/readme_template | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c32cdbee..ef33e42a 100644 --- a/README.md +++ b/README.md @@ -253,19 +253,19 @@ option. ### Options | Option | Description | |-----------------------|--------------------------------------------------------------------------------------------------------------| -| `‑a`, `‑‑about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `‑C`, `‑‑force_color` | force color output even when using pipes (overrides `‑m` and the `NO_COLOR` env variable) | -| `‑d`, `‑‑debug` | debug mode. Prints trace messages if parsing issues are encountered (use`‑dd` for verbose debugging) | -| `‑h`, `‑‑help` | help. Use `jc ‑h ‑‑parser_name` for parser documentation | -| `‑m`, `‑‑monochrome` | monochrome output | -| `‑p`, `‑‑pretty` | pretty format the JSON output | -| `‑q`, `‑‑quiet` | quiet mode. Suppresses parser warning messages (use `‑qq` to ignore streaming parser errors) | -| `‑r`, `‑‑raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `‑u`, `‑‑unbuffer` | unbuffer output | -| `‑v`, `‑‑version` | version information | -| `‑y`, `‑‑yaml‑out` | YAML output | -| `‑B`, `‑‑bash‑comp` | generate Bash shell completion script | -| `‑Z`, `‑‑zsh‑comp` | generate Zsh shell completion script | +| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C`, `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | +| `-m`, `--monochrome` | monochrome output | +| `-p`, `--pretty` | pretty format the JSON output | +| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u`, `--unbuffer` | unbuffer output | +| `-v`, `--version` | version information | +| `-y`, `--yaml-out` | YAML output | +| `-B`, `--bash-comp` | generate Bash shell completion script | +| `-Z`, `--zsh-comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the diff --git a/templates/readme_template b/templates/readme_template index 38bb61ab..3db0a4e1 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -151,19 +151,19 @@ option. ### Options | Option | Description | |-----------------------|--------------------------------------------------------------------------------------------------------------| -| `‑a`, `‑‑about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `‑C`, `‑‑force_color` | force color output even when using pipes (overrides `‑m` and the `NO_COLOR` env variable) | -| `‑d`, `‑‑debug` | debug mode. Prints trace messages if parsing issues are encountered (use`‑dd` for verbose debugging) | -| `‑h`, `‑‑help` | help. Use `jc ‑h ‑‑parser_name` for parser documentation | -| `‑m`, `‑‑monochrome` | monochrome output | -| `‑p`, `‑‑pretty` | pretty format the JSON output | -| `‑q`, `‑‑quiet` | quiet mode. Suppresses parser warning messages (use `‑qq` to ignore streaming parser errors) | -| `‑r`, `‑‑raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `‑u`, `‑‑unbuffer` | unbuffer output | -| `‑v`, `‑‑version` | version information | -| `‑y`, `‑‑yaml‑out` | YAML output | -| `‑B`, `‑‑bash‑comp` | generate Bash shell completion script | -| `‑Z`, `‑‑zsh‑comp` | generate Zsh shell completion script | +| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C`, `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | +| `-m`, `--monochrome` | monochrome output | +| `-p`, `--pretty` | pretty format the JSON output | +| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u`, `--unbuffer` | unbuffer output | +| `-v`, `--version` | version information | +| `-y`, `--yaml-out` | YAML output | +| `-B`, `--bash-comp` | generate Bash shell completion script | +| `-Z`, `--zsh-comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the From 79add35fc14f2c2e9fa4bfaa7292dd35c34e226e Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Sun, 5 Jun 2022 18:09:44 -0700 Subject: [PATCH 20/46] split long and short options --- README.md | 30 +++++++++++++++--------------- templates/readme_template | 30 +++++++++++++++--------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index ef33e42a..75c1e0fc 100644 --- a/README.md +++ b/README.md @@ -251,21 +251,21 @@ option. | ` --zipinfo` | `zipinfo` command parser | [📃](https://kellyjonbrazil.github.io/jc/docs/parsers/zipinfo) | ### Options -| Option | Description | -|-----------------------|--------------------------------------------------------------------------------------------------------------| -| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `-C`, `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | -| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | -| `-m`, `--monochrome` | monochrome output | -| `-p`, `--pretty` | pretty format the JSON output | -| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | -| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `-u`, `--unbuffer` | unbuffer output | -| `-v`, `--version` | version information | -| `-y`, `--yaml-out` | YAML output | -| `-B`, `--bash-comp` | generate Bash shell completion script | -| `-Z`, `--zsh-comp` | generate Zsh shell completion script | +| Short | Long | Description | +|-------|-----------------|--------------------------------------------------------------------------------------------------------------| +| `-a` | `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C` | `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d` | `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h` | `--help` | help. Use `jc -h --parser_name` for parser documentation | +| `-m` | `--monochrome` | monochrome output | +| `-p` | `--pretty` | pretty format the JSON output | +| `-q` | `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r` | `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u` | `--unbuffer` | unbuffer output | +| `-v` | `--version` | version information | +| `-y` | `--yaml-out` | YAML output | +| `-B` | `--bash-comp` | generate Bash shell completion script | +| `-Z` | `--zsh-comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the diff --git a/templates/readme_template b/templates/readme_template index 3db0a4e1..9a65dd6f 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -149,21 +149,21 @@ option. | `{{ "{:>15}".format(parser.argument) }}` | {{ "{:<55}".format(parser.description) }} | {{ "{:<70}".format("[📃](https://kellyjonbrazil.github.io/jc/docs/parsers/" + parser.name + ")") }} |{% endfor %} ### Options -| Option | Description | -|-----------------------|--------------------------------------------------------------------------------------------------------------| -| `-a`, `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `-C`, `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | -| `-d`, `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h`, `--help` | help. Use `jc -h --parser_name` for parser documentation | -| `-m`, `--monochrome` | monochrome output | -| `-p`, `--pretty` | pretty format the JSON output | -| `-q`, `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | -| `-r`, `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `-u`, `--unbuffer` | unbuffer output | -| `-v`, `--version` | version information | -| `-y`, `--yaml-out` | YAML output | -| `-B`, `--bash-comp` | generate Bash shell completion script | -| `-Z`, `--zsh-comp` | generate Zsh shell completion script | +| Short | Long | Description | +|-------|-----------------|--------------------------------------------------------------------------------------------------------------| +| `-a` | `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C` | `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d` | `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h` | `--help` | help. Use `jc -h --parser_name` for parser documentation | +| `-m` | `--monochrome` | monochrome output | +| `-p` | `--pretty` | pretty format the JSON output | +| `-q` | `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r` | `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u` | `--unbuffer` | unbuffer output | +| `-v` | `--version` | version information | +| `-y` | `--yaml-out` | YAML output | +| `-B` | `--bash-comp` | generate Bash shell completion script | +| `-Z` | `--zsh-comp` | generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the From a415bc23fa9c068d4eabd222ba9d897a32aa4501 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 6 Jun 2022 10:32:18 -0700 Subject: [PATCH 21/46] man page update --- man/jc.1 | 32 ++++++++++++++++---------------- templates/manpage_template | 30 +++++++++++++++--------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/man/jc.1 b/man/jc.1 index e200dfa7..330d15dd 100644 --- a/man/jc.1 +++ b/man/jc.1 @@ -1,4 +1,4 @@ -.TH jc 1 2022-06-05 1.20.1 "JSON Convert" +.TH jc 1 2022-06-06 1.20.1 "JSON Convert" .SH NAME \fBjc\fP \- JSON Convert JSONifies the output of many CLI tools and file-types .SH SYNOPSIS @@ -541,55 +541,55 @@ Options: .TP .B -\fB-a\fP +\fB-a\fP, \fB--about\fP about \fBjc\fP (JSON or YAML output) .TP .B -\fB-C\fP +\fB-C\fP, \fB--force-color\fP force color output even when using pipes (overrides \fB-m\fP and the \fBNO_COLOR\fP env variable) .TP .B -\fB-d\fP +\fB-d\fP, \fB--debug\fP debug - show traceback (use \fB-dd\fP for verbose traceback) .TP .B -\fB-h\fP -help (\fB-h --parser_name\fP for parser documentation) +\fB-h\fP, \fB--help\fP +help (\fB--help --parser_name\fP for parser documentation) .TP .B -\fB-m\fP +\fB-m\fP, \fB--monochrome\fP monochrome output .TP .B -\fB-p\fP +\fB-p\fP, \fB--pretty\fP pretty print output .TP .B -\fB-q\fP +\fB-q\fP, \fB--quiet\fP quiet - suppress warnings (use \fB-qq\fP to ignore streaming parser errors) .TP .B -\fB-r\fP -raw JSON output +\fB-r\fP, \fB--raw\fP +raw output .TP .B -\fB-u\fP +\fB-u\fP, \fB--unbuffer\fP unbuffer output (useful for slow streaming data with streaming parsers) .TP .B -\fB-v\fP +\fB-v\fP, \fB--version\fP version information .TP .B -\fB-y\fP +\fB-y\fP, \fB--yaml-out\fP YAML output .TP .B -\fB-B\fP +\fB-B\fP, \fB--bash-comp\fP generate Bash shell completion script .TP .B -\fB-Z\fP +\fB-Z\fP, \fB--zsh-comp\fP generate Zsh shell completion script .SH EXIT CODES diff --git a/templates/manpage_template b/templates/manpage_template index d175b0db..b238d58d 100644 --- a/templates/manpage_template +++ b/templates/manpage_template @@ -31,55 +31,55 @@ Options: .TP .B -\fB-a\fP +\fB-a\fP, \fB--about\fP about \fBjc\fP (JSON or YAML output) .TP .B -\fB-C\fP +\fB-C\fP, \fB--force-color\fP force color output even when using pipes (overrides \fB-m\fP and the \fBNO_COLOR\fP env variable) .TP .B -\fB-d\fP +\fB-d\fP, \fB--debug\fP debug - show traceback (use \fB-dd\fP for verbose traceback) .TP .B -\fB-h\fP -help (\fB-h --parser_name\fP for parser documentation) +\fB-h\fP, \fB--help\fP +help (\fB--help --parser_name\fP for parser documentation) .TP .B -\fB-m\fP +\fB-m\fP, \fB--monochrome\fP monochrome output .TP .B -\fB-p\fP +\fB-p\fP, \fB--pretty\fP pretty print output .TP .B -\fB-q\fP +\fB-q\fP, \fB--quiet\fP quiet - suppress warnings (use \fB-qq\fP to ignore streaming parser errors) .TP .B -\fB-r\fP -raw JSON output +\fB-r\fP, \fB--raw\fP +raw output .TP .B -\fB-u\fP +\fB-u\fP, \fB--unbuffer\fP unbuffer output (useful for slow streaming data with streaming parsers) .TP .B -\fB-v\fP +\fB-v\fP, \fB--version\fP version information .TP .B -\fB-y\fP +\fB-y\fP, \fB--yaml-out\fP YAML output .TP .B -\fB-B\fP +\fB-B\fP, \fB--bash-comp\fP generate Bash shell completion script .TP .B -\fB-Z\fP +\fB-Z\fP, \fB--zsh-comp\fP generate Zsh shell completion script .SH EXIT CODES From 231a2039c2480069f01f83ac24645530d3ec9f96 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 6 Jun 2022 10:49:17 -0700 Subject: [PATCH 22/46] update options --- man/jc.1 | 24 ++++++++++++------------ templates/manpage_template | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/man/jc.1 b/man/jc.1 index 330d15dd..280104fb 100644 --- a/man/jc.1 +++ b/man/jc.1 @@ -542,43 +542,43 @@ Options: .TP .B \fB-a\fP, \fB--about\fP -about \fBjc\fP (JSON or YAML output) +About \fBjc\fP (JSON or YAML output) .TP .B \fB-C\fP, \fB--force-color\fP -force color output even when using pipes (overrides \fB-m\fP and the \fBNO_COLOR\fP env variable) +Force color output even when using pipes (overrides \fB-m\fP and the \fBNO_COLOR\fP env variable) .TP .B \fB-d\fP, \fB--debug\fP -debug - show traceback (use \fB-dd\fP for verbose traceback) +Debug - show traceback (use \fB-dd\fP for verbose traceback) .TP .B \fB-h\fP, \fB--help\fP -help (\fB--help --parser_name\fP for parser documentation) +Help (\fB--help --parser_name\fP for parser documentation) .TP .B \fB-m\fP, \fB--monochrome\fP -monochrome output +Monochrome output .TP .B \fB-p\fP, \fB--pretty\fP -pretty print output +Pretty print output .TP .B \fB-q\fP, \fB--quiet\fP -quiet - suppress warnings (use \fB-qq\fP to ignore streaming parser errors) +Quiet mode. Suppresses parser warning messages (use -qq to ignore streaming parser errors) .TP .B \fB-r\fP, \fB--raw\fP -raw output +Raw output. Provides more literal output, typically with string values and no additional semantic processing .TP .B \fB-u\fP, \fB--unbuffer\fP -unbuffer output (useful for slow streaming data with streaming parsers) +Unbuffer output (useful for slow streaming data with streaming parsers) .TP .B \fB-v\fP, \fB--version\fP -version information +Version information .TP .B \fB-y\fP, \fB--yaml-out\fP @@ -586,11 +586,11 @@ YAML output .TP .B \fB-B\fP, \fB--bash-comp\fP -generate Bash shell completion script +Generate Bash shell completion script .TP .B \fB-Z\fP, \fB--zsh-comp\fP -generate Zsh shell completion script +Generate Zsh shell completion script .SH EXIT CODES Any fatal errors within \fBjc\fP will generate an exit code of \fB100\fP, otherwise the exit code will be \fB0\fP. When using the "Magic" syntax (e.g. \fBjc ifconfig eth0\fP), \fBjc\fP will store the exit code of the program being parsed and add it to the \fBjc\fP exit code. This way it is easier to determine if an error was from the parsed program or \fBjc\fP. diff --git a/templates/manpage_template b/templates/manpage_template index b238d58d..f5ed2d21 100644 --- a/templates/manpage_template +++ b/templates/manpage_template @@ -32,43 +32,43 @@ Options: .TP .B \fB-a\fP, \fB--about\fP -about \fBjc\fP (JSON or YAML output) +About \fBjc\fP (JSON or YAML output) .TP .B \fB-C\fP, \fB--force-color\fP -force color output even when using pipes (overrides \fB-m\fP and the \fBNO_COLOR\fP env variable) +Force color output even when using pipes (overrides \fB-m\fP and the \fBNO_COLOR\fP env variable) .TP .B \fB-d\fP, \fB--debug\fP -debug - show traceback (use \fB-dd\fP for verbose traceback) +Debug - show traceback (use \fB-dd\fP for verbose traceback) .TP .B \fB-h\fP, \fB--help\fP -help (\fB--help --parser_name\fP for parser documentation) +Help (\fB--help --parser_name\fP for parser documentation) .TP .B \fB-m\fP, \fB--monochrome\fP -monochrome output +Monochrome output .TP .B \fB-p\fP, \fB--pretty\fP -pretty print output +Pretty print output .TP .B \fB-q\fP, \fB--quiet\fP -quiet - suppress warnings (use \fB-qq\fP to ignore streaming parser errors) +Quiet mode. Suppresses parser warning messages (use -qq to ignore streaming parser errors) .TP .B \fB-r\fP, \fB--raw\fP -raw output +Raw output. Provides more literal output, typically with string values and no additional semantic processing .TP .B \fB-u\fP, \fB--unbuffer\fP -unbuffer output (useful for slow streaming data with streaming parsers) +Unbuffer output (useful for slow streaming data with streaming parsers) .TP .B \fB-v\fP, \fB--version\fP -version information +Version information .TP .B \fB-y\fP, \fB--yaml-out\fP @@ -76,11 +76,11 @@ YAML output .TP .B \fB-B\fP, \fB--bash-comp\fP -generate Bash shell completion script +Generate Bash shell completion script .TP .B \fB-Z\fP, \fB--zsh-comp\fP -generate Zsh shell completion script +Generate Zsh shell completion script .SH EXIT CODES Any fatal errors within \fBjc\fP will generate an exit code of \fB100\fP, otherwise the exit code will be \fB0\fP. When using the "Magic" syntax (e.g. \fBjc ifconfig eth0\fP), \fBjc\fP will store the exit code of the program being parsed and add it to the \fBjc\fP exit code. This way it is easier to determine if an error was from the parsed program or \fBjc\fP. From b9a5eda18736231997668e370850e64e4ee95847 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 6 Jun 2022 10:52:40 -0700 Subject: [PATCH 23/46] formatting --- README.md | 24 ++++++++++++------------ templates/readme_template | 24 ++++++++++++------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 75c1e0fc..f1d2bbcb 100644 --- a/README.md +++ b/README.md @@ -253,19 +253,19 @@ option. ### Options | Short | Long | Description | |-------|-----------------|--------------------------------------------------------------------------------------------------------------| -| `-a` | `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `-C` | `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | -| `-d` | `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h` | `--help` | help. Use `jc -h --parser_name` for parser documentation | -| `-m` | `--monochrome` | monochrome output | -| `-p` | `--pretty` | pretty format the JSON output | -| `-q` | `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | -| `-r` | `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `-u` | `--unbuffer` | unbuffer output | -| `-v` | `--version` | version information | +| `-a` | `--about` | About `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C` | `--force-color` | Force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d` | `--debug` | Debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h` | `--help` | Help. Use `jc -h --parser_name` for parser documentation | +| `-m` | `--monochrome` | Monochrome output | +| `-p` | `--pretty` | Pretty format the JSON output | +| `-q` | `--quiet` | Quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r` | `--raw` | Raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u` | `--unbuffer` | Unbuffer output | +| `-v` | `--version` | Version information | | `-y` | `--yaml-out` | YAML output | -| `-B` | `--bash-comp` | generate Bash shell completion script | -| `-Z` | `--zsh-comp` | generate Zsh shell completion script | +| `-B` | `--bash-comp` | Generate Bash shell completion script | +| `-Z` | `--zsh-comp` | Generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the diff --git a/templates/readme_template b/templates/readme_template index 9a65dd6f..36fefd2a 100644 --- a/templates/readme_template +++ b/templates/readme_template @@ -151,19 +151,19 @@ option. ### Options | Short | Long | Description | |-------|-----------------|--------------------------------------------------------------------------------------------------------------| -| `-a` | `--about` | about `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | -| `-C` | `--force-color` | force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | -| `-d` | `--debug` | debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | -| `-h` | `--help` | help. Use `jc -h --parser_name` for parser documentation | -| `-m` | `--monochrome` | monochrome output | -| `-p` | `--pretty` | pretty format the JSON output | -| `-q` | `--quiet` | quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | -| `-r` | `--raw` | raw output. Provides more literal output, typically with string values and no additional semantic processing | -| `-u` | `--unbuffer` | unbuffer output | -| `-v` | `--version` | version information | +| `-a` | `--about` | About `jc`. Prints information about `jc` and the parsers (in JSON or YAML, of course!) | +| `-C` | `--force-color` | Force color output even when using pipes (overrides `-m` and the `NO_COLOR` env variable) | +| `-d` | `--debug` | Debug mode. Prints trace messages if parsing issues are encountered (use`-dd` for verbose debugging) | +| `-h` | `--help` | Help. Use `jc -h --parser_name` for parser documentation | +| `-m` | `--monochrome` | Monochrome output | +| `-p` | `--pretty` | Pretty format the JSON output | +| `-q` | `--quiet` | Quiet mode. Suppresses parser warning messages (use `-qq` to ignore streaming parser errors) | +| `-r` | `--raw` | Raw output. Provides more literal output, typically with string values and no additional semantic processing | +| `-u` | `--unbuffer` | Unbuffer output | +| `-v` | `--version` | Version information | | `-y` | `--yaml-out` | YAML output | -| `-B` | `--bash-comp` | generate Bash shell completion script | -| `-Z` | `--zsh-comp` | generate Zsh shell completion script | +| `-B` | `--bash-comp` | Generate Bash shell completion script | +| `-Z` | `--zsh-comp` | Generate Zsh shell completion script | ### Exit Codes Any fatal errors within `jc` will generate an exit code of `100`, otherwise the From 71ae54590716295cda7b4775d517c586ae2ef5c6 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 6 Jun 2022 16:24:52 -0700 Subject: [PATCH 24/46] better working bash completion --- jc/shell_completions.py | 44 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index a04ccc98..a9df5ee8 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -6,7 +6,43 @@ from .lib import all_parser_info bash_template = Template('''\ -complete -W "${bash_arguments}${bash_options}${bash_commands}" jc +_jc() +{ + local cur prev jc_commands jc_parsers jc_options + + jc_commands=(${bash_commands}) + jc_parsers=(${bash_arguments}) + jc_options=(${bash_options}) + + COMPREPLY=() + _get_comp_words_by_ref cur prev + + # detect magic syntax and use called command's autocompletion + if [[ " $${jc_commands[*]} " =~ " $${prev} " ]]; then + _command + return 0 + fi + + # if parser argument, then display options + if [[ " $${jc_parsers[*]} " =~ " $${prev} " ]]; then + COMPREPLY=( $$( compgen -W "$${jc_options[*]}" \\ + -- "$${cur}" ) ) + return 0 + fi + + # if option, then display options and parsers and commands + if [[ " $${jc_options[*]} " =~ " $${prev} " ]]; then + COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ + -- "$${cur}" ) ) + return 0 + fi + + # default completion + COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ + -- "$${cur}" ) ) + +} && +complete -F _jc jc ''') @@ -68,9 +104,9 @@ def gen_zsh_command_descriptions(command_list): def bash_completion(): - args = '\n'.join(get_arguments()) - options = '\n' + '\n'.join(get_options()) - commands = '\n' + '\n'.join(get_commands()) + args = ' '.join(get_arguments()) + options = ' '.join(get_options()) + commands = ' '.join(get_commands()) return bash_template.substitute(bash_arguments=args, bash_options=options, bash_commands=commands) From e48b99f1c1620cef3f2192ebe1f97ad10bce4aba Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 7 Jun 2022 11:02:05 -0700 Subject: [PATCH 25/46] fix bash completion behavior --- jc/shell_completions.py | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index a9df5ee8..198e2922 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -8,39 +8,35 @@ from .lib import all_parser_info bash_template = Template('''\ _jc() { - local cur prev jc_commands jc_parsers jc_options + local cur prev words cword jc_commands jc_parsers jc_options jc_commands=(${bash_commands}) jc_parsers=(${bash_arguments}) jc_options=(${bash_options}) COMPREPLY=() - _get_comp_words_by_ref cur prev + _get_comp_words_by_ref cur prev words cword - # detect magic syntax and use called command's autocompletion - if [[ " $${jc_commands[*]} " =~ " $${prev} " ]]; then - _command - return 0 - fi + # if magic command is found anywhere in the line, use called command's autocompletion + for i in "$${words[@]}"; do + if [[ " $${jc_commands[*]} " =~ " $${i} " ]]; then + _command + return 0 + fi + done - # if parser argument, then display options - if [[ " $${jc_parsers[*]} " =~ " $${prev} " ]]; then - COMPREPLY=( $$( compgen -W "$${jc_options[*]}" \\ - -- "$${cur}" ) ) - return 0 - fi - - # if option, then display options and parsers and commands - if [[ " $${jc_options[*]} " =~ " $${prev} " ]]; then - COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ - -- "$${cur}" ) ) - return 0 - fi + # if a parser arg is found anywhere in the line, only show options + for i in "$${words[@]}"; do + if [[ " $${jc_parsers[*]} " =~ " $${i} " ]]; then + COMPREPLY=( $$( compgen -W "$${jc_options[*]}" \\ + -- "$${cur}" ) ) + return 0 + fi + done # default completion COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ -- "$${cur}" ) ) - } && complete -F _jc jc ''') @@ -74,7 +70,7 @@ def get_commands(): if 'magic_commands' in cmd: command_list.extend(cmd['magic_commands']) - return list(set([i.split()[0] for i in command_list])) + return sorted(list(set([i.split()[0] for i in command_list]))) def get_options(): From 39c1470ea6a6fc869cfc219c1ecbc1870f84d069 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 7 Jun 2022 11:57:48 -0700 Subject: [PATCH 26/46] add special options to bash completion --- jc/shell_completions.py | 42 ++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index 198e2922..6edef54d 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -8,15 +8,23 @@ from .lib import all_parser_info bash_template = Template('''\ _jc() { - local cur prev words cword jc_commands jc_parsers jc_options + local cur prev words cword jc_commands jc_parsers jc_options jc_special_options jc_commands=(${bash_commands}) jc_parsers=(${bash_arguments}) jc_options=(${bash_options}) + jc_special_options=(${bash_special_opts}) COMPREPLY=() _get_comp_words_by_ref cur prev words cword + # if special options are found anywhere in the line, then no more completions + for i in "$${words[@]}"; do + if [[ " $${jc_special_options[*]} " =~ " $${i} " ]]; then + return 0 + fi + done + # if magic command is found anywhere in the line, use called command's autocompletion for i in "$${words[@]}"; do if [[ " $${jc_commands[*]} " =~ " $${i} " ]]; then @@ -35,7 +43,7 @@ _jc() done # default completion - COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ + COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_special_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ -- "$${cur}" ) ) } && complete -F _jc jc @@ -46,23 +54,30 @@ zsh_template = Template('''\ #compdef jc _jc() { + + # if magic command is found anywhere in the line, use called command's autocompletion + + # if a parser arg is found anywhere in the line, only show options + + # default completion # autogenerate completions based on jc --help output - _arguments -- + # _arguments -- # add commands supported by magic syntax - local -a commands - commands=( - # e.g. 'arp:run arp with magic syntax.' - ${zsh_commands} - ) + # local -a commands + # commands=( + # # e.g. 'arp:run arp with magic syntax.' + # ${zsh_commands} + # ) - _describe -t commands 'commands' commands - return 0 + # _describe -t commands 'commands' commands + # return 0 } _jc ''') +special_options = ['--about', '-a', '--version', '-v', '--bash-comp', '-B', '--zsh-comp', '-Z'] def get_commands(): command_list = [] @@ -101,9 +116,14 @@ def gen_zsh_command_descriptions(command_list): def bash_completion(): args = ' '.join(get_arguments()) - options = ' '.join(get_options()) + opts_no_special = get_options() + for option in special_options: + opts_no_special.remove(option) + options = ' '.join(opts_no_special) + s_options = ' '.join(special_options) commands = ' '.join(get_commands()) return bash_template.substitute(bash_arguments=args, + bash_special_opts=s_options, bash_options=options, bash_commands=commands) From f62e6168fdc519d9aaced90fb51d85f256cafa4b Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 8 Jun 2022 08:50:20 -0700 Subject: [PATCH 27/46] fix help completions for bash --- jc/shell_completions.py | 69 ++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index 6edef54d..5551bc83 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -8,16 +8,38 @@ from .lib import all_parser_info bash_template = Template('''\ _jc() { - local cur prev words cword jc_commands jc_parsers jc_options jc_special_options + local cur prev words cword jc_commands jc_parsers jc_options \\ + jc_about_options jc_special_options jc_commands=(${bash_commands}) - jc_parsers=(${bash_arguments}) + jc_parsers=(${bash_parsers}) jc_options=(${bash_options}) - jc_special_options=(${bash_special_opts}) + jc_about_options=(${bash_about_options}) + jc_about_mod_options=(${bash_about_mod_options}) + jc_help_options=(${bash_help_options}) + jc_special_options=(${bash_special_options}) COMPREPLY=() _get_comp_words_by_ref cur prev words cword + # if jc_about_options are found anywhere in the line, then only complete from jc_about_mod_options + for i in "$${words[@]}"; do + if [[ " $${jc_about_options[*]} " =~ " $${i} " ]]; then + COMPREPLY=( $$( compgen -W "$${jc_about_mod_options[*]}" \\ + -- "$${cur}" ) ) + return 0 + fi + done + + # if jc_help_options are found anywhere in the line, then only complete with parsers + for i in "$${words[@]}"; do + if [[ " $${jc_help_options[*]} " =~ " $${i} " ]]; then + COMPREPLY=( $$( compgen -W "$${jc_parsers[*]}" \\ + -- "$${cur}" ) ) + return 0 + fi + done + # if special options are found anywhere in the line, then no more completions for i in "$${words[@]}"; do if [[ " $${jc_special_options[*]} " =~ " $${i} " ]]; then @@ -43,7 +65,7 @@ _jc() done # default completion - COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_special_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ + COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_about_options[*]} $${jc_help_options[*]} $${jc_special_options[*]} $${jc_parsers[*]} $${jc_commands[*]}" \\ -- "$${cur}" ) ) } && complete -F _jc jc @@ -77,7 +99,10 @@ _jc() { _jc ''') -special_options = ['--about', '-a', '--version', '-v', '--bash-comp', '-B', '--zsh-comp', '-Z'] +about_options = ['--about', '-a'] +about_mod_options = ['--pretty', '-p', '--yaml-out', '-y', '--monochrome', '-m', '--force-color', '-C'] +help_options = ['--help', '-h'] +special_options = ['--version', '-v', '--bash-comp', '-B', '--zsh-comp', '-Z'] def get_commands(): command_list = [] @@ -115,17 +140,31 @@ def gen_zsh_command_descriptions(command_list): def bash_completion(): - args = ' '.join(get_arguments()) + parsers_str = ' '.join(get_arguments()) opts_no_special = get_options() - for option in special_options: - opts_no_special.remove(option) - options = ' '.join(opts_no_special) - s_options = ' '.join(special_options) - commands = ' '.join(get_commands()) - return bash_template.substitute(bash_arguments=args, - bash_special_opts=s_options, - bash_options=options, - bash_commands=commands) + + for s_option in special_options: + opts_no_special.remove(s_option) + + for a_option in about_options: + opts_no_special.remove(a_option) + + for h_option in help_options: + opts_no_special.remove(h_option) + + options_str = ' '.join(opts_no_special) + about_options_str = ' '.join(about_options) + about_mod_options_str = ' '.join(about_mod_options) + help_options_str = ' '.join(help_options) + special_options_str = ' '.join(special_options) + commands_str = ' '.join(get_commands()) + return bash_template.substitute(bash_parsers=parsers_str, + bash_special_options=special_options_str, + bash_about_options=about_options_str, + bash_about_mod_options=about_mod_options_str, + bash_help_options=help_options_str, + bash_options=options_str, + bash_commands=commands_str) def zsh_completion(): From 7bc03dcf06f63e4646a65ec6fc110e8e3235a83f Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 8 Jun 2022 08:51:23 -0700 Subject: [PATCH 28/46] add local vars to bash completion --- jc/shell_completions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index 5551bc83..24b68a7f 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -9,7 +9,7 @@ bash_template = Template('''\ _jc() { local cur prev words cword jc_commands jc_parsers jc_options \\ - jc_about_options jc_special_options + jc_about_options jc_about_mod_options jc_help_options jc_special_options jc_commands=(${bash_commands}) jc_parsers=(${bash_parsers}) From 5c40b38a05c0e9eb7d26b34cc1347b3af6f84107 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 10 Jun 2022 12:02:04 -0700 Subject: [PATCH 29/46] fix help bash completions so they don't repeat parsers --- jc/shell_completions.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index 24b68a7f..ed047291 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -31,6 +31,26 @@ _jc() fi done + # if jc_help_options and a parser are found anywhere in the line, then no more completions + if + ( + for i in "$${words[@]}"; do + if [[ " $${jc_help_options[*]} " =~ " $${i} " ]]; then + return 0 + fi + done + return 1 + ) && ( + for i in "$${words[@]}"; do + if [[ " $${jc_parsers[*]} " =~ " $${i} " ]]; then + return 0 + fi + done + return 1 + ); then + return 0 + fi + # if jc_help_options are found anywhere in the line, then only complete with parsers for i in "$${words[@]}"; do if [[ " $${jc_help_options[*]} " =~ " $${i} " ]]; then @@ -55,10 +75,10 @@ _jc() fi done - # if a parser arg is found anywhere in the line, only show options + # if a parser arg is found anywhere in the line, only show options and help options for i in "$${words[@]}"; do if [[ " $${jc_parsers[*]} " =~ " $${i} " ]]; then - COMPREPLY=( $$( compgen -W "$${jc_options[*]}" \\ + COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_help_options[*]}" \\ -- "$${cur}" ) ) return 0 fi From c0da9ebd6c60a68a8af35ce82c470d929e518309 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Fri, 10 Jun 2022 17:25:19 -0700 Subject: [PATCH 30/46] only check previous words in bash completion --- jc/shell_completions.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index ed047291..12765229 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -23,7 +23,7 @@ _jc() _get_comp_words_by_ref cur prev words cword # if jc_about_options are found anywhere in the line, then only complete from jc_about_mod_options - for i in "$${words[@]}"; do + for i in "$${words[@]::$${#words[@]}-1}"; do if [[ " $${jc_about_options[*]} " =~ " $${i} " ]]; then COMPREPLY=( $$( compgen -W "$${jc_about_mod_options[*]}" \\ -- "$${cur}" ) ) @@ -34,14 +34,14 @@ _jc() # if jc_help_options and a parser are found anywhere in the line, then no more completions if ( - for i in "$${words[@]}"; do + for i in "$${words[@]::$${#words[@]}-1}"; do if [[ " $${jc_help_options[*]} " =~ " $${i} " ]]; then return 0 fi done return 1 ) && ( - for i in "$${words[@]}"; do + for i in "$${words[@]::$${#words[@]}-1}"; do if [[ " $${jc_parsers[*]} " =~ " $${i} " ]]; then return 0 fi @@ -52,7 +52,7 @@ _jc() fi # if jc_help_options are found anywhere in the line, then only complete with parsers - for i in "$${words[@]}"; do + for i in "$${words[@]::$${#words[@]}-1}"; do if [[ " $${jc_help_options[*]} " =~ " $${i} " ]]; then COMPREPLY=( $$( compgen -W "$${jc_parsers[*]}" \\ -- "$${cur}" ) ) @@ -61,14 +61,14 @@ _jc() done # if special options are found anywhere in the line, then no more completions - for i in "$${words[@]}"; do + for i in "$${words[@]::$${#words[@]}-1}"; do if [[ " $${jc_special_options[*]} " =~ " $${i} " ]]; then return 0 fi done # if magic command is found anywhere in the line, use called command's autocompletion - for i in "$${words[@]}"; do + for i in "$${words[@]::$${#words[@]}-1}"; do if [[ " $${jc_commands[*]} " =~ " $${i} " ]]; then _command return 0 @@ -76,7 +76,7 @@ _jc() done # if a parser arg is found anywhere in the line, only show options and help options - for i in "$${words[@]}"; do + for i in "$${words[@]::$${#words[@]}-1}"; do if [[ " $${jc_parsers[*]} " =~ " $${i} " ]]; then COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_help_options[*]}" \\ -- "$${cur}" ) ) From 747b255e34a66ad74e66f6fb85158c25ae190eb4 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Mon, 13 Jun 2022 21:09:37 -0700 Subject: [PATCH 31/46] zsh working same as bash except for magic command completions --- jc/shell_completions.py | 223 ++++++++++++++++++++++++++++++++++------ 1 file changed, 194 insertions(+), 29 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index 12765229..389e277f 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -80,7 +80,7 @@ _jc() if [[ " $${jc_parsers[*]} " =~ " $${i} " ]]; then COMPREPLY=( $$( compgen -W "$${jc_options[*]} $${jc_help_options[*]}" \\ -- "$${cur}" ) ) - return 0 + return 0 fi done @@ -96,24 +96,115 @@ zsh_template = Template('''\ #compdef jc _jc() { + local -a jc_commands jc_commands_describe \\ + jc_parsers jc_parsers_describe \\ + jc_options jc_options_describe \\ + jc_about_options jc_about_options_describe \\ + jc_about_mod_options jc_about_mod_options_describe \\ + jc_help_options jc_help_options_describe \\ + jc_special_options jc_special_options_describe \\ + jc_options_and_help_describe \\ + jc_default_describe + + jc_commands=(${zsh_commands}) + jc_commands_describe=( + ${zsh_commands_describe} + ) + jc_parsers=(${zsh_parsers}) + jc_parsers_describe=( + ${zsh_parsers_describe} + ) + jc_options=(${zsh_options}) + jc_options_describe=( + ${zsh_options_describe} + ) + jc_about_options=(${zsh_about_options}) + jc_about_options_describe=( + ${zsh_about_options_describe} + ) + jc_about_mod_options=(${zsh_about_mod_options}) + jc_about_mod_options_describe=( + ${zsh_about_mod_options_describe} + ) + jc_help_options=(${zsh_help_options}) + jc_help_options_describe=( + ${zsh_help_options_describe} + ) + jc_special_options=(${zsh_special_options}) + jc_special_options_describe=( + ${zsh_special_options_describe} + ) + jc_options_and_help_describe=( + ${zsh_options_and_help_describe} + ) + jc_default_describe=( + ${zsh_default_describe} + ) + + zsh_options_and_help_describe=options_and_help_describe, + zsh_default_describe=default_describe + + # if jc_about_options are found anywhere in the line, then only complete from jc_about_mod_options + for i in $${words:0:-1}; do + if (( $$jc_about_options[(Ie)$${i}] )); then + _describe 'commands' jc_about_mod_options_describe + return 0 + fi + done + + # if jc_help_options and a parser are found anywhere in the line, then no more completions + if + ( + for i in $${words:0:-1}; do + if (( $$jc_help_options[(Ie)$${i}] )); then + return 0 + fi + done + return 1 + ) && ( + for i in $${words:0:-1}; do + if (( $$jc_parsers[(Ie)$${i}] )); then + return 0 + fi + done + return 1 + ); then + return 0 + fi + + # if jc_help_options are found anywhere in the line, then only complete with parsers + for i in $${words:0:-1}; do + if (( $$jc_help_options[(Ie)$${i}] )); then + _describe 'commands' jc_parsers_describe + return 0 + fi + done + + # if special options are found anywhere in the line, then no more completions + for i in $${words:0:-1}; do + if (( $$jc_special_options[(Ie)$${i}] )); then + return 0 + fi + done # if magic command is found anywhere in the line, use called command's autocompletion + for i in $${words:0:-1}; do + if (( $$jc_commands[(Ie)$${i}] )); then + _normal -P + return 0 + fi + done - # if a parser arg is found anywhere in the line, only show options + # if a parser arg is found anywhere in the line, only show options and help options + for i in $${words:0:-1}; do + if (( $$jc_parsers[(Ie)$${i}] )); then + _describe 'commands' jc_options_and_help_describe + return 0 + fi + done # default completion - # autogenerate completions based on jc --help output - # _arguments -- - - # add commands supported by magic syntax - # local -a commands - # commands=( - # # e.g. 'arp:run arp with magic syntax.' - # ${zsh_commands} - # ) - - # _describe -t commands 'commands' commands - # return 0 + _describe 'commands' jc_default_describe } _jc @@ -142,16 +233,25 @@ def get_options(): return options_list -def get_arguments(): - arg_list = [] +def get_parsers(): + p_list = [] for cmd in all_parser_info(): if 'argument' in cmd: - arg_list.append(cmd['argument']) + p_list.append(cmd['argument']) - return arg_list + return p_list -def gen_zsh_command_descriptions(command_list): +def get_parsers_descriptions(): + pd_list = [] + for p in all_parser_info(): + if 'description' in p: + pd_list.append(f"'{p['argument']}:{p['description']}'") + + return pd_list + + +def get_zsh_command_descriptions(command_list): zsh_commands = [] for cmd in command_list: zsh_commands.append(f"""'{cmd}:run "{cmd}" command with magic syntax.'""") @@ -159,8 +259,27 @@ def gen_zsh_command_descriptions(command_list): return zsh_commands +def get_descriptions(opt_list): + """Return a list of options:description items.""" + opt_desc_list = [] + + for item in opt_list: + # get long options + if item in long_options_map: + opt_desc_list.append(f"'{item}:{long_options_map[item][1]}'") + continue + + # get short options + for k, v in long_options_map.items(): + if item[1:] == v[0]: + opt_desc_list.append(f"'{item}:{v[1]}'") + continue + + return opt_desc_list + + def bash_completion(): - parsers_str = ' '.join(get_arguments()) + parsers_str = ' '.join(get_parsers()) opts_no_special = get_options() for s_option in special_options: @@ -178,15 +297,61 @@ def bash_completion(): help_options_str = ' '.join(help_options) special_options_str = ' '.join(special_options) commands_str = ' '.join(get_commands()) - return bash_template.substitute(bash_parsers=parsers_str, - bash_special_options=special_options_str, - bash_about_options=about_options_str, - bash_about_mod_options=about_mod_options_str, - bash_help_options=help_options_str, - bash_options=options_str, - bash_commands=commands_str) + return bash_template.substitute( + bash_parsers=parsers_str, + bash_special_options=special_options_str, + bash_about_options=about_options_str, + bash_about_mod_options=about_mod_options_str, + bash_help_options=help_options_str, + bash_options=options_str, + bash_commands=commands_str + ) def zsh_completion(): - commands = '\n '.join(gen_zsh_command_descriptions(get_commands())) - return zsh_template.substitute(zsh_commands=commands) + parsers_str = ' '.join(get_parsers()) + parsers_describe = '\n '.join(get_parsers_descriptions()) + opts_no_special = get_options() + + for s_option in special_options: + opts_no_special.remove(s_option) + + for a_option in about_options: + opts_no_special.remove(a_option) + + for h_option in help_options: + opts_no_special.remove(h_option) + + options_str = ' '.join(opts_no_special) + options_describe = '\n '.join(get_descriptions(opts_no_special)) + about_options_str = ' '.join(about_options) + about_options_describe = '\n '.join(get_descriptions(about_options)) + about_mod_options_str = ' '.join(about_mod_options) + about_mod_options_describe = '\n '.join(get_descriptions(about_mod_options)) + help_options_str = ' '.join(help_options) + help_options_describe = '\n '.join(get_descriptions(help_options)) + special_options_str = ' '.join(special_options) + special_options_describe = '\n '.join(get_descriptions(special_options)) + commands_str = ' '.join(get_commands()) + commands_describe = '\n '.join(get_zsh_command_descriptions(get_commands())) + options_and_help_describe = '\n '.join([options_describe, help_options_describe]) + default_describe = '\n '.join([options_describe, about_options_describe, help_options_describe, special_options_describe, parsers_describe, commands_describe]) + + return zsh_template.substitute( + zsh_parsers=parsers_str, + zsh_parsers_describe=parsers_describe, + zsh_special_options=special_options_str, + zsh_special_options_describe=special_options_describe, + zsh_about_options=about_options_str, + zsh_about_options_describe=about_options_describe, + zsh_about_mod_options=about_mod_options_str, + zsh_about_mod_options_describe=about_mod_options_describe, + zsh_help_options=help_options_str, + zsh_help_options_describe=help_options_describe, + zsh_options=options_str, + zsh_options_describe=options_describe, + zsh_commands=commands_str, + zsh_commands_describe=commands_describe, + zsh_options_and_help_describe=options_and_help_describe, + zsh_default_describe=default_describe + ) From ca95615d7fa53dd0fc40897cca32f784056f665f Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 14 Jun 2022 07:42:55 -0700 Subject: [PATCH 32/46] partially working _normal completion for zsh --- jc/shell_completions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index 389e277f..da1dab6e 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -190,7 +190,9 @@ _jc() { # if magic command is found anywhere in the line, use called command's autocompletion for i in $${words:0:-1}; do if (( $$jc_commands[(Ie)$${i}] )); then - _normal -P + # still not working 100%. works fine as `jc dig`, but `jc -p dig` + # will only complete with files, not program-specific completions + _arguments '*::arguments:_normal' return 0 fi done From f9ae964280a4e349bcfb292802e10e8554e328c5 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 14 Jun 2022 08:49:26 -0700 Subject: [PATCH 33/46] reuse arrays in zsh completions --- jc/shell_completions.py | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index da1dab6e..e3bee1ba 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -102,9 +102,7 @@ _jc() { jc_about_options jc_about_options_describe \\ jc_about_mod_options jc_about_mod_options_describe \\ jc_help_options jc_help_options_describe \\ - jc_special_options jc_special_options_describe \\ - jc_options_and_help_describe \\ - jc_default_describe + jc_special_options jc_special_options_describe jc_commands=(${zsh_commands}) jc_commands_describe=( @@ -134,15 +132,6 @@ _jc() { jc_special_options_describe=( ${zsh_special_options_describe} ) - jc_options_and_help_describe=( - ${zsh_options_and_help_describe} - ) - jc_default_describe=( - ${zsh_default_describe} - ) - - zsh_options_and_help_describe=options_and_help_describe, - zsh_default_describe=default_describe # if jc_about_options are found anywhere in the line, then only complete from jc_about_mod_options for i in $${words:0:-1}; do @@ -200,13 +189,13 @@ _jc() { # if a parser arg is found anywhere in the line, only show options and help options for i in $${words:0:-1}; do if (( $$jc_parsers[(Ie)$${i}] )); then - _describe 'commands' jc_options_and_help_describe + _describe 'commands' jc_options_describe -- jc_help_options_describe return 0 fi done # default completion - _describe 'commands' jc_default_describe + _describe 'commands' jc_options_describe -- jc_about_options_describe -- jc_help_options_describe -- jc_special_options_describe -- jc_parsers_describe -- jc_commands_describe } _jc @@ -336,8 +325,6 @@ def zsh_completion(): special_options_describe = '\n '.join(get_descriptions(special_options)) commands_str = ' '.join(get_commands()) commands_describe = '\n '.join(get_zsh_command_descriptions(get_commands())) - options_and_help_describe = '\n '.join([options_describe, help_options_describe]) - default_describe = '\n '.join([options_describe, about_options_describe, help_options_describe, special_options_describe, parsers_describe, commands_describe]) return zsh_template.substitute( zsh_parsers=parsers_str, @@ -353,7 +340,5 @@ def zsh_completion(): zsh_options=options_str, zsh_options_describe=options_describe, zsh_commands=commands_str, - zsh_commands_describe=commands_describe, - zsh_options_and_help_describe=options_and_help_describe, - zsh_default_describe=default_describe + zsh_commands_describe=commands_describe ) From 8fba47f449ee931e6db90f95d8c8c17c9436f9e3 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 14 Jun 2022 12:42:30 -0700 Subject: [PATCH 34/46] doc update --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index aaab44a3..989aa432 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,9 @@ jc changelog -20220601 v1.20.1 (in progress) +20220614 v1.20.1 (in progress) - Add `postconf -M` parser tested on linux +- Add long options (e.g. `--help`, `--about`, `--pretty`, etc.) +- Add shell completions for Bash and Zsh - Fix `id` parser for cases where the user or group name is not present 20220531 v1.20.0 From 4b86fd8d8abb1ee1c80884f613c61dcbf93edc60 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 14 Jun 2022 16:51:45 -0700 Subject: [PATCH 35/46] manipulate words and CURRENT to fix magic completions in Zsh --- jc/shell_completions.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index e3bee1ba..a8120791 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -179,8 +179,9 @@ _jc() { # if magic command is found anywhere in the line, use called command's autocompletion for i in $${words:0:-1}; do if (( $$jc_commands[(Ie)$${i}] )); then - # still not working 100%. works fine as `jc dig`, but `jc -p dig` - # will only complete with files, not program-specific completions + shift $$(( $${#words} - 2 )) words + words[1,0]=(jc) + CURRENT=$${#words} _arguments '*::arguments:_normal' return 0 fi From c0c469ae9b6e99678134e3dbb5550817c5892ac6 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Tue, 14 Jun 2022 17:03:54 -0700 Subject: [PATCH 36/46] add comments --- jc/shell_completions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jc/shell_completions.py b/jc/shell_completions.py index a8120791..65f497db 100644 --- a/jc/shell_completions.py +++ b/jc/shell_completions.py @@ -179,9 +179,12 @@ _jc() { # if magic command is found anywhere in the line, use called command's autocompletion for i in $${words:0:-1}; do if (( $$jc_commands[(Ie)$${i}] )); then + # hack to remove options between jc and the magic command shift $$(( $${#words} - 2 )) words words[1,0]=(jc) CURRENT=$${#words} + + # run the magic command's completions _arguments '*::arguments:_normal' return 0 fi From 45f45e0511d7983420f479eea628a72cd42f3b86 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 09:18:11 -0700 Subject: [PATCH 37/46] add examples --- jc/parsers/postconf.py | 52 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/jc/parsers/postconf.py b/jc/parsers/postconf.py index 1ce6172b..0983492b 100644 --- a/jc/parsers/postconf.py +++ b/jc/parsers/postconf.py @@ -34,11 +34,55 @@ Schema: Examples: - $ postconf | jc --postconf -p - [] + $ postconf -M | jc --postconf -p + [ + { + "service_name": "smtp", + "service_type": "inet", + "private": false, + "unprivileged": null, + "chroot": true, + "wake_up_time": null, + "process_limit": null, + "command": "smtpd", + "no_wake_up_before_first_use": null + }, + { + "service_name": "pickup", + "service_type": "unix", + "private": false, + "unprivileged": null, + "chroot": true, + "wake_up_time": 60, + "process_limit": 1, + "command": "pickup", + "no_wake_up_before_first_use": false + } + ] - $ postconf | jc --postconf -p -r - [] + $ postconf -M | jc --postconf -p -r + [ + { + "service_name": "smtp", + "service_type": "inet", + "private": "n", + "unprivileged": "-", + "chroot": "y", + "wake_up_time": "-", + "process_limit": "-", + "command": "smtpd" + }, + { + "service_name": "pickup", + "service_type": "unix", + "private": "n", + "unprivileged": "-", + "chroot": "y", + "wake_up_time": "60", + "process_limit": "1", + "command": "pickup" + } + ] """ from typing import List, Dict import jc.utils From 247c43278cc95e5070e4a9e81257363a04fce5d9 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 09:22:09 -0700 Subject: [PATCH 38/46] add postconf tests --- tests/fixtures/generic/postconf-M.json | 1 + tests/test_postconf.py | 35 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/fixtures/generic/postconf-M.json create mode 100644 tests/test_postconf.py diff --git a/tests/fixtures/generic/postconf-M.json b/tests/fixtures/generic/postconf-M.json new file mode 100644 index 00000000..ef4584ab --- /dev/null +++ b/tests/fixtures/generic/postconf-M.json @@ -0,0 +1 @@ +[{"service_name":"smtp","service_type":"inet","private":false,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"smtpd","no_wake_up_before_first_use":null},{"service_name":"pickup","service_type":"unix","private":false,"unprivileged":null,"chroot":true,"wake_up_time":60,"process_limit":1,"command":"pickup","no_wake_up_before_first_use":false},{"service_name":"cleanup","service_type":"unix","private":false,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":0,"command":"cleanup","no_wake_up_before_first_use":null},{"service_name":"qmgr","service_type":"unix","private":false,"unprivileged":null,"chroot":false,"wake_up_time":300,"process_limit":1,"command":"qmgr","no_wake_up_before_first_use":false},{"service_name":"tlsmgr","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":1000,"process_limit":1,"command":"tlsmgr","no_wake_up_before_first_use":true},{"service_name":"rewrite","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"trivial-rewrite","no_wake_up_before_first_use":null},{"service_name":"bounce","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":0,"command":"bounce","no_wake_up_before_first_use":null},{"service_name":"defer","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":0,"command":"bounce","no_wake_up_before_first_use":null},{"service_name":"trace","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":0,"command":"bounce","no_wake_up_before_first_use":null},{"service_name":"verify","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":1,"command":"verify","no_wake_up_before_first_use":null},{"service_name":"flush","service_type":"unix","private":false,"unprivileged":null,"chroot":true,"wake_up_time":1000,"process_limit":0,"command":"flush","no_wake_up_before_first_use":true},{"service_name":"proxymap","service_type":"unix","private":null,"unprivileged":null,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"proxymap","no_wake_up_before_first_use":null},{"service_name":"proxywrite","service_type":"unix","private":null,"unprivileged":null,"chroot":false,"wake_up_time":null,"process_limit":1,"command":"proxymap","no_wake_up_before_first_use":null},{"service_name":"smtp","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"smtp","no_wake_up_before_first_use":null},{"service_name":"relay","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"smtp -o syslog_name=postfix/$service_name","no_wake_up_before_first_use":null},{"service_name":"showq","service_type":"unix","private":false,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"showq","no_wake_up_before_first_use":null},{"service_name":"error","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"error","no_wake_up_before_first_use":null},{"service_name":"retry","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"error","no_wake_up_before_first_use":null},{"service_name":"discard","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"discard","no_wake_up_before_first_use":null},{"service_name":"local","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"local","no_wake_up_before_first_use":null},{"service_name":"virtual","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"virtual","no_wake_up_before_first_use":null},{"service_name":"lmtp","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":null,"command":"lmtp","no_wake_up_before_first_use":null},{"service_name":"anvil","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":1,"command":"anvil","no_wake_up_before_first_use":null},{"service_name":"scache","service_type":"unix","private":null,"unprivileged":null,"chroot":true,"wake_up_time":null,"process_limit":1,"command":"scache","no_wake_up_before_first_use":null},{"service_name":"postlog","service_type":"unix-dgram","private":false,"unprivileged":null,"chroot":false,"wake_up_time":null,"process_limit":1,"command":"postlogd","no_wake_up_before_first_use":null},{"service_name":"maildrop","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"pipe flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}","no_wake_up_before_first_use":null},{"service_name":"uucp","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"pipe flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)","no_wake_up_before_first_use":null},{"service_name":"ifmail","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"pipe flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)","no_wake_up_before_first_use":null},{"service_name":"bsmtp","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"pipe flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient","no_wake_up_before_first_use":null},{"service_name":"scalemail-backend","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":2,"command":"pipe flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}","no_wake_up_before_first_use":null},{"service_name":"mailman","service_type":"unix","private":null,"unprivileged":false,"chroot":false,"wake_up_time":null,"process_limit":null,"command":"pipe flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}","no_wake_up_before_first_use":null}] diff --git a/tests/test_postconf.py b/tests/test_postconf.py new file mode 100644 index 00000000..c02dad57 --- /dev/null +++ b/tests/test_postconf.py @@ -0,0 +1,35 @@ +import os +import unittest +import json +import jc.parsers.postconf + +THIS_DIR = os.path.dirname(os.path.abspath(__file__)) + + +class MyTests(unittest.TestCase): + + def setUp(self): + # input + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/postconf-M.out'), 'r', encoding='utf-8') as f: + self.generic_postconf_m = f.read() + + # output + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/postconf-M.json'), 'r', encoding='utf-8') as f: + self.generic_postconf_m_json = json.loads(f.read()) + + + def test_postconf_nodata(self): + """ + Test 'postconf' with no data + """ + self.assertEqual(jc.parsers.postconf.parse('', quiet=True), []) + + def test_postconf(self): + """ + Test 'postconf -M' + """ + self.assertEqual(jc.parsers.postconf.parse(self.generic_postconf_m, quiet=True), self.generic_postconf_m_json) + + +if __name__ == '__main__': + unittest.main() From 4f148469d76d8ec870bc219bf88978bb4e4320ad Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 11:12:43 -0700 Subject: [PATCH 39/46] preserve keyname case with -r --- jc/parsers/asciitable.py | 13 ++++++++++-- jc/parsers/asciitable_m.py | 13 ++++++++++-- tests/test_asciitable.py | 43 ++++++++++++++++++++++++++++++++++++++ tests/test_asciitable_m.py | 28 +++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 4 deletions(-) diff --git a/jc/parsers/asciitable.py b/jc/parsers/asciitable.py index 5d4317b7..8e3f2f1d 100644 --- a/jc/parsers/asciitable.py +++ b/jc/parsers/asciitable.py @@ -54,6 +54,9 @@ etc... Headers (keys) are converted to snake-case. All values are returned as strings, except empty strings, which are converted to None/null. +> Note: To preserve the case of the keys use the `-r` cli option or +> `raw=True` argument in `parse()`. + Usage (cli): $ cat table.txt | jc --asciitable @@ -122,7 +125,7 @@ from jc.parsers.universal import sparse_table_parse class info(): """Provides parser metadata (version, author, etc.)""" - version = '1.1' + version = '1.2' description = 'ASCII and Unicode table parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -144,6 +147,12 @@ def _process(proc_data: List[Dict]) -> List[Dict]: List of Dictionaries. Structured to conform to the schema. """ + # normalize keys: convert to lowercase + for item in proc_data: + for key in item.copy(): + k_new = key.lower() + item[k_new] = item.pop(key) + return proc_data @@ -232,7 +241,7 @@ def _snake_case(line: str) -> str: padding. """ line = re.sub(r'[^a-zA-Z0-9� ]', '_', line) # special characters - line = re.sub(r'\b \b', '_', line).lower() # spaces betwee words + line = re.sub(r'\b \b', '_', line) # spaces between words return line diff --git a/jc/parsers/asciitable_m.py b/jc/parsers/asciitable_m.py index d85bfa14..52069965 100644 --- a/jc/parsers/asciitable_m.py +++ b/jc/parsers/asciitable_m.py @@ -24,6 +24,9 @@ Headers (keys) are converted to snake-case and newlines between multi-line headers are joined with an underscore. All values are returned as strings, except empty strings, which are converted to None/null. +> Note: To preserve the case of the keys use the `-r` cli option or +> `raw=True` argument in `parse()`. + > Note: table column separator characters (e.g. `|`) cannot be present > inside the cell data. If detected, a warning message will be printed to > `STDERR` and the line will be skipped. The warning message can be @@ -107,7 +110,7 @@ from jc.exceptions import ParseError class info(): """Provides parser metadata (version, author, etc.)""" - version = '1.1' + version = '1.2' description = 'multi-line ASCII and Unicode table parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -129,6 +132,12 @@ def _process(proc_data: List[Dict]) -> List[Dict]: List of Dictionaries. Structured to conform to the schema. """ + # normalize keys: convert to lowercase + for item in proc_data: + for key in item.copy(): + k_new = key.lower() + item[k_new] = item.pop(key) + return proc_data @@ -238,7 +247,7 @@ def _snake_case(line: str) -> str: """ # must include all column separator characters in regex line = re.sub(r'[^a-zA-Z0-9 |│┃┆┇┊┋╎╏║]', '_', line) - return re.sub(r'\b \b', '_', line).lower() + return re.sub(r'\b \b', '_', line) def _fixup_separators(line: str) -> str: diff --git a/tests/test_asciitable.py b/tests/test_asciitable.py index e481f1d7..64f74879 100644 --- a/tests/test_asciitable.py +++ b/tests/test_asciitable.py @@ -344,6 +344,49 @@ Internet 10.12.13.4 198 0950.5C8A.5c41 ARPA GigabitEthernet2.17 self.assertEqual(jc.parsers.asciitable.parse(input, quiet=True), expected) + def test_asciitable_no_lower_raw(self): + """ + Test 'asciitable' with a pure ASCII table that has special + characters and mixed case in the header. These should be converted to underscores + and no trailing or consecutive underscores should end up in the + resulting key names. Using `raw` in this test to preserve case. (no lower) + """ + input = ''' +Protocol Address Age (min) Hardware Addr Type Interface +Internet 10.12.13.1 98 0950.5785.5cd1 ARPA FastEthernet2.13 +Internet 10.12.13.3 131 0150.7685.14d5 ARPA GigabitEthernet2.13 +Internet 10.12.13.4 198 0950.5C8A.5c41 ARPA GigabitEthernet2.17 + ''' + + expected = [ + { + "Protocol": "Internet", + "Address": "10.12.13.1", + "Age_min": "98", + "Hardware_Addr": "0950.5785.5cd1", + "Type": "ARPA", + "Interface": "FastEthernet2.13" + }, + { + "Protocol": "Internet", + "Address": "10.12.13.3", + "Age_min": "131", + "Hardware_Addr": "0150.7685.14d5", + "Type": "ARPA", + "Interface": "GigabitEthernet2.13" + }, + { + "Protocol": "Internet", + "Address": "10.12.13.4", + "Age_min": "198", + "Hardware_Addr": "0950.5C8A.5c41", + "Type": "ARPA", + "Interface": "GigabitEthernet2.17" + } + ] + + self.assertEqual(jc.parsers.asciitable.parse(input, raw=True, quiet=True), expected) + def test_asciitable_centered_col_header(self): """ Test 'asciitable' with long centered column header which can break diff --git a/tests/test_asciitable_m.py b/tests/test_asciitable_m.py index 90248c0c..9a29945c 100644 --- a/tests/test_asciitable_m.py +++ b/tests/test_asciitable_m.py @@ -270,6 +270,34 @@ class MyTests(unittest.TestCase): self.assertEqual(jc.parsers.asciitable_m.parse(input, quiet=True), expected) + def test_asciitable_no_lower_raw(self): + """ + Test 'asciitable_m' with a pure ASCII table that has special + characters and mixed case in the header. These should be converted to underscores + and no trailing or consecutive underscores should end up in the + resulting key names. Using `raw` in this test to preserve case. (no lower) + """ + input = ''' ++----------+------------+-----------+----------------+-------+--------------------+ +| Protocol | Address | Age (min) | Hardware Addr | Type | Interface | +| | | of int | | | | ++----------+------------+-----------+----------------+-------+--------------------+ +| Internet | 10.12.13.1 | 98 | 0950.5785.5cd1 | ARPA | FastEthernet2.13 | ++----------+------------+-----------+----------------+-------+--------------------+ + ''' + expected = [ + { + "Protocol": "Internet", + "Address": "10.12.13.1", + "Age_min_of_int": "98", + "Hardware_Addr": "0950.5785.5cd1", + "Type": "ARPA", + "Interface": "FastEthernet2.13" + } + ] + + self.assertEqual(jc.parsers.asciitable_m.parse(input, raw=True, quiet=True), expected) + def test_asciitable_m_sep_char_in_cell(self): """ Test 'asciitable_m' with a column separator character inside the data From c23aacedad9fbf0ca96ed5cf5228b5c60b93ea2e Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 11:12:49 -0700 Subject: [PATCH 40/46] doc update --- CHANGELOG | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 989aa432..979aa0a5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,7 +1,9 @@ jc changelog -20220614 v1.20.1 (in progress) +20220615 v1.20.1 (in progress) - Add `postconf -M` parser tested on linux +- Update `asciitable` and `asciitable-m` parsers to preserve case in key + names when using the `-r` or `raw=True` options. - Add long options (e.g. `--help`, `--about`, `--pretty`, etc.) - Add shell completions for Bash and Zsh - Fix `id` parser for cases where the user or group name is not present From b958358389becbeb30fdd3844e25d9c71eb85615 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 11:15:26 -0700 Subject: [PATCH 41/46] update _snake_case comment --- jc/parsers/asciitable.py | 5 ++--- jc/parsers/asciitable_m.py | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/jc/parsers/asciitable.py b/jc/parsers/asciitable.py index 8e3f2f1d..724eb849 100644 --- a/jc/parsers/asciitable.py +++ b/jc/parsers/asciitable.py @@ -236,9 +236,8 @@ def _is_separator(line: str) -> bool: def _snake_case(line: str) -> str: """ - Replace spaces between words and special characters with an underscore - and set to lowercase. Ignore the replacement char (�) used for header - padding. + Replace spaces between words and special characters with an underscore. + Ignore the replacement char (�) used for header padding. """ line = re.sub(r'[^a-zA-Z0-9� ]', '_', line) # special characters line = re.sub(r'\b \b', '_', line) # spaces between words diff --git a/jc/parsers/asciitable_m.py b/jc/parsers/asciitable_m.py index 52069965..8c77ce8b 100644 --- a/jc/parsers/asciitable_m.py +++ b/jc/parsers/asciitable_m.py @@ -242,8 +242,7 @@ def _is_separator(line: str) -> bool: def _snake_case(line: str) -> str: """ - replace spaces between words and special characters with an underscore - and set to lowercase + replace spaces between words and special characters with an underscore. """ # must include all column separator characters in regex line = re.sub(r'[^a-zA-Z0-9 |│┃┆┇┊┋╎╏║]', '_', line) From 40208a9f761315588ce74aa58841eb5fafe1b1af Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 11:25:21 -0700 Subject: [PATCH 42/46] doc update --- docs/parsers/asciitable.md | 5 +++- docs/parsers/asciitable_m.md | 5 +++- docs/parsers/postconf.md | 52 +++++++++++++++++++++++++++++++++--- man/jc.1 | 2 +- 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/docs/parsers/asciitable.md b/docs/parsers/asciitable.md index bd1e9d23..16f428ae 100644 --- a/docs/parsers/asciitable.md +++ b/docs/parsers/asciitable.md @@ -59,6 +59,9 @@ etc... Headers (keys) are converted to snake-case. All values are returned as strings, except empty strings, which are converted to None/null. +> Note: To preserve the case of the keys use the `-r` cli option or +> `raw=True` argument in `parse()`. + Usage (cli): $ cat table.txt | jc --asciitable @@ -141,4 +144,4 @@ Returns: ### Parser Information Compatibility: linux, darwin, cygwin, win32, aix, freebsd -Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) +Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/asciitable_m.md b/docs/parsers/asciitable_m.md index cd034c56..05e4e353 100644 --- a/docs/parsers/asciitable_m.md +++ b/docs/parsers/asciitable_m.md @@ -29,6 +29,9 @@ Headers (keys) are converted to snake-case and newlines between multi-line headers are joined with an underscore. All values are returned as strings, except empty strings, which are converted to None/null. +> Note: To preserve the case of the keys use the `-r` cli option or +> `raw=True` argument in `parse()`. + > Note: table column separator characters (e.g. `|`) cannot be present > inside the cell data. If detected, a warning message will be printed to > `STDERR` and the line will be skipped. The warning message can be @@ -126,4 +129,4 @@ Returns: ### Parser Information Compatibility: linux, darwin, cygwin, win32, aix, freebsd -Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com) +Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com) diff --git a/docs/parsers/postconf.md b/docs/parsers/postconf.md index 6f481375..2ef586da 100644 --- a/docs/parsers/postconf.md +++ b/docs/parsers/postconf.md @@ -39,11 +39,55 @@ Schema: Examples: - $ postconf | jc --postconf -p - [] + $ postconf -M | jc --postconf -p + [ + { + "service_name": "smtp", + "service_type": "inet", + "private": false, + "unprivileged": null, + "chroot": true, + "wake_up_time": null, + "process_limit": null, + "command": "smtpd", + "no_wake_up_before_first_use": null + }, + { + "service_name": "pickup", + "service_type": "unix", + "private": false, + "unprivileged": null, + "chroot": true, + "wake_up_time": 60, + "process_limit": 1, + "command": "pickup", + "no_wake_up_before_first_use": false + } + ] - $ postconf | jc --postconf -p -r - [] + $ postconf -M | jc --postconf -p -r + [ + { + "service_name": "smtp", + "service_type": "inet", + "private": "n", + "unprivileged": "-", + "chroot": "y", + "wake_up_time": "-", + "process_limit": "-", + "command": "smtpd" + }, + { + "service_name": "pickup", + "service_type": "unix", + "private": "n", + "unprivileged": "-", + "chroot": "y", + "wake_up_time": "60", + "process_limit": "1", + "command": "pickup" + } + ] diff --git a/man/jc.1 b/man/jc.1 index 280104fb..b61e76ea 100644 --- a/man/jc.1 +++ b/man/jc.1 @@ -1,4 +1,4 @@ -.TH jc 1 2022-06-06 1.20.1 "JSON Convert" +.TH jc 1 2022-06-15 1.20.1 "JSON Convert" .SH NAME \fBjc\fP \- JSON Convert JSONifies the output of many CLI tools and file-types .SH SYNOPSIS From 43702a260b6152c5ae831cf9525114e9ff3059b0 Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 12:50:58 -0700 Subject: [PATCH 43/46] strip single quotes just like double quotes --- jc/parsers/ini.py | 21 +++++++++------- tests/fixtures/generic/ini-double-quote.ini | 4 ++++ tests/fixtures/generic/ini-double-quote.json | 1 + tests/fixtures/generic/ini-single-quote.ini | 4 ++++ tests/fixtures/generic/ini-single-quote.json | 1 + tests/test_ini.py | 25 ++++++++++++++++++++ 6 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 tests/fixtures/generic/ini-double-quote.ini create mode 100644 tests/fixtures/generic/ini-double-quote.json create mode 100644 tests/fixtures/generic/ini-single-quote.ini create mode 100644 tests/fixtures/generic/ini-single-quote.json diff --git a/jc/parsers/ini.py b/jc/parsers/ini.py index 5e2d2b0b..09313294 100644 --- a/jc/parsers/ini.py +++ b/jc/parsers/ini.py @@ -6,9 +6,10 @@ Parses standard `INI` files and files containing simple key/value pairs. - Comment prefix can be `#` or `;`. Comments must be on their own line. - If duplicate keys are found, only the last value will be used. -> Note: Values starting and ending with quotation marks will have the marks -> removed. If you would like to keep the quotation marks, use the `-r` -> command-line argument or the `raw=True` argument in `parse()`. +> Note: Values starting and ending with double or single quotation marks +> will have the marks removed. If you would like to keep the quotation +> marks, use the `-r` command-line argument or the `raw=True` argument in +> `parse()`. Usage (cli): @@ -69,7 +70,7 @@ import configparser class info(): """Provides parser metadata (version, author, etc.)""" - version = '1.6' + version = '1.7' description = 'INI file parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -99,17 +100,21 @@ def _process(proc_data): for key, value in proc_data[heading].items(): if value is not None and value.startswith('"') and value.endswith('"'): proc_data[heading][key] = value.lstrip('"').rstrip('"') + + elif value is not None and value.startswith("'") and value.endswith("'"): + proc_data[heading][key] = value.lstrip("'").rstrip("'") + elif value is None: proc_data[heading][key] = '' # simple key/value files with no headers else: - if (proc_data[heading] is not None and - proc_data[heading].startswith('"') and - proc_data[heading].endswith('"')): - + if proc_data[heading] is not None and proc_data[heading].startswith('"') and proc_data[heading].endswith('"'): proc_data[heading] = proc_data[heading].lstrip('"').rstrip('"') + elif proc_data[heading] is not None and proc_data[heading].startswith("'") and proc_data[heading].endswith("'"): + proc_data[heading] = proc_data[heading].lstrip("'").rstrip("'") + elif proc_data[heading] is None: proc_data[heading] = '' diff --git a/tests/fixtures/generic/ini-double-quote.ini b/tests/fixtures/generic/ini-double-quote.ini new file mode 100644 index 00000000..33d7c484 --- /dev/null +++ b/tests/fixtures/generic/ini-double-quote.ini @@ -0,0 +1,4 @@ +[client] +user=foo +host=localhost +password="bar" diff --git a/tests/fixtures/generic/ini-double-quote.json b/tests/fixtures/generic/ini-double-quote.json new file mode 100644 index 00000000..b2d9a17e --- /dev/null +++ b/tests/fixtures/generic/ini-double-quote.json @@ -0,0 +1 @@ +{"client":{"user":"foo","host":"localhost","password":"bar"}} diff --git a/tests/fixtures/generic/ini-single-quote.ini b/tests/fixtures/generic/ini-single-quote.ini new file mode 100644 index 00000000..5a4cbb75 --- /dev/null +++ b/tests/fixtures/generic/ini-single-quote.ini @@ -0,0 +1,4 @@ +[client] +user=foo +host=localhost +password='bar' diff --git a/tests/fixtures/generic/ini-single-quote.json b/tests/fixtures/generic/ini-single-quote.json new file mode 100644 index 00000000..b2d9a17e --- /dev/null +++ b/tests/fixtures/generic/ini-single-quote.json @@ -0,0 +1 @@ +{"client":{"user":"foo","host":"localhost","password":"bar"}} diff --git a/tests/test_ini.py b/tests/test_ini.py index f4ac1123..bd815d77 100644 --- a/tests/test_ini.py +++ b/tests/test_ini.py @@ -16,6 +16,12 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-iptelserver.ini'), 'r', encoding='utf-8') as f: self.generic_ini_iptelserver = f.read() + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-double-quote.ini'), 'r', encoding='utf-8') as f: + self.generic_ini_double_quote = f.read() + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-single-quote.ini'), 'r', encoding='utf-8') as f: + self.generic_ini_single_quote = f.read() + # output with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-test.json'), 'r', encoding='utf-8') as f: self.generic_ini_test_json = json.loads(f.read()) @@ -23,6 +29,12 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-iptelserver.json'), 'r', encoding='utf-8') as f: self.generic_ini_iptelserver_json = json.loads(f.read()) + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-double-quote.json'), 'r', encoding='utf-8') as f: + self.generic_ini_double_quote_json = json.loads(f.read()) + + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/ini-single-quote.json'), 'r', encoding='utf-8') as f: + self.generic_ini_single_quote_json = json.loads(f.read()) + def test_ini_nodata(self): """ Test the test ini file with no data @@ -53,6 +65,19 @@ duplicate_key = value2 expected = {'duplicate_key': 'value2', 'another_key': 'foo'} self.assertEqual(jc.parsers.ini.parse(data, quiet=True), expected) + def test_ini_doublequote(self): + """ + Test ini file with double quotes around a value + """ + self.assertEqual(jc.parsers.ini.parse(self.generic_ini_double_quote, quiet=True), self.generic_ini_double_quote_json) + + def test_ini_singlequote(self): + """ + Test ini file with single quotes around a value + """ + self.assertEqual(jc.parsers.ini.parse(self.generic_ini_single_quote, quiet=True), self.generic_ini_single_quote_json) + + if __name__ == '__main__': unittest.main() From 337ee73844a712e1bdd8466f383adc0ad427923e Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 12:51:42 -0700 Subject: [PATCH 44/46] doc update --- docs/parsers/ini.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/parsers/ini.md b/docs/parsers/ini.md index c45145c3..5f77a36f 100644 --- a/docs/parsers/ini.md +++ b/docs/parsers/ini.md @@ -11,9 +11,10 @@ Parses standard `INI` files and files containing simple key/value pairs. - Comment prefix can be `#` or `;`. Comments must be on their own line. - If duplicate keys are found, only the last value will be used. -> Note: Values starting and ending with quotation marks will have the marks -> removed. If you would like to keep the quotation marks, use the `-r` -> command-line argument or the `raw=True` argument in `parse()`. +> Note: Values starting and ending with double or single quotation marks +> will have the marks removed. If you would like to keep the quotation +> marks, use the `-r` command-line argument or the `raw=True` argument in +> `parse()`. Usage (cli): @@ -91,4 +92,4 @@ Returns: ### Parser Information Compatibility: linux, darwin, cygwin, win32, aix, freebsd -Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com) +Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com) From 7fd70d20884f7488fc4267116bdea2a4396eb49b Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 13:10:12 -0700 Subject: [PATCH 45/46] doc update --- CHANGELOG | 2 +- EXAMPLES.md | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 979aa0a5..4d7a93d7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ jc changelog -20220615 v1.20.1 (in progress) +20220615 v1.20.1 - Add `postconf -M` parser tested on linux - Update `asciitable` and `asciitable-m` parsers to preserve case in key names when using the `-r` or `raw=True` options. diff --git a/EXAMPLES.md b/EXAMPLES.md index 3bcee1c9..b50c64b1 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -2728,6 +2728,36 @@ pip show wrapt wheel | jc --pip-show -p # or: jc -p pip show wrapt whe } ] ``` +### postconf -M +```bash +postconf -M | jc --postconf -p # or jc -p postconf -M +``` +```json +[ + { + "service_name": "smtp", + "service_type": "inet", + "private": false, + "unprivileged": null, + "chroot": true, + "wake_up_time": null, + "process_limit": null, + "command": "smtpd", + "no_wake_up_before_first_use": null + }, + { + "service_name": "pickup", + "service_type": "unix", + "private": false, + "unprivileged": null, + "chroot": true, + "wake_up_time": 60, + "process_limit": 1, + "command": "pickup", + "no_wake_up_before_first_use": false + } +] +``` ### ps ```bash ps -ef | jc --ps -p # or: jc -p ps -ef @@ -3465,6 +3495,105 @@ timedatectl | jc --timedatectl -p # or: jc -p timedatectl "epoch_utc": 1583888001 } ``` +### tob -b +```bash +top -b -n 1 | jc --top -p # or jc -p tob -b -n 1 +``` +```json +[ + { + "time": "11:20:43", + "uptime": 118, + "users": 2, + "load_1m": 0.0, + "load_5m": 0.01, + "load_15m": 0.05, + "tasks_total": 108, + "tasks_running": 2, + "tasks_sleeping": 106, + "tasks_stopped": 0, + "tasks_zombie": 0, + "cpu_user": 5.6, + "cpu_sys": 11.1, + "cpu_nice": 0.0, + "cpu_idle": 83.3, + "cpu_wait": 0.0, + "cpu_hardware": 0.0, + "cpu_software": 0.0, + "cpu_steal": 0.0, + "mem_total": 3.7, + "mem_free": 3.3, + "mem_used": 0.2, + "mem_buff_cache": 0.2, + "swap_total": 2.0, + "swap_free": 2.0, + "swap_used": 0.0, + "mem_available": 3.3, + "processes": [ + { + "pid": 2225, + "user": "kbrazil", + "priority": 20, + "nice": 0, + "virtual_mem": 158.1, + "resident_mem": 2.2, + "shared_mem": 1.6, + "status": "running", + "percent_cpu": 12.5, + "percent_mem": 0.1, + "time_hundredths": "0:00.02", + "command": "top", + "parent_pid": 1884, + "uid": 1000, + "real_uid": 1000, + "real_user": "kbrazil", + "saved_uid": 1000, + "saved_user": "kbrazil", + "gid": 1000, + "group": "kbrazil", + "pgrp": 2225, + "tty": "pts/0", + "tty_process_gid": 2225, + "session_id": 1884, + "thread_count": 1, + "last_used_processor": 0, + "time": "0:00", + "swap": 0.0, + "code": 0.1, + "data": 1.0, + "major_page_fault_count": 0, + "minor_page_fault_count": 736, + "dirty_pages_count": 0, + "sleeping_in_function": null, + "flags": "..4.2...", + "cgroups": "1:name=systemd:/user.slice/user-1000.+", + "supplementary_gids": [ + 10, + 1000 + ], + "supplementary_groups": [ + "wheel", + "kbrazil" + ], + "thread_gid": 2225, + "environment_variables": [ + "XDG_SESSION_ID=2", + "HOSTNAME=localhost" + ], + "major_page_fault_count_delta": 0, + "minor_page_fault_count_delta": 4, + "used": 2.2, + "ipc_namespace_inode": 4026531839, + "mount_namespace_inode": 4026531840, + "net_namespace_inode": 4026531956, + "pid_namespace_inode": 4026531836, + "user_namespace_inode": 4026531837, + "nts_namespace_inode": 4026531838 + } + ] + } +] +``` ### tracepath ```bash tracepath6 3ffe:2400:0:109::2 | jc --tracepath -p From 7583f315cee2930c5e6e5faec697d59c8b2063cd Mon Sep 17 00:00:00 2001 From: Kelly Brazil Date: Wed, 15 Jun 2022 13:21:37 -0700 Subject: [PATCH 46/46] add long options tests --- tests/test_cli.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_cli.py b/tests/test_cli.py index 4079c582..07ba93d5 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -25,7 +25,10 @@ class MyTests(unittest.TestCase): 'jc -h': (False, None, None, []), 'jc -h --arp': (False, None, None, []), 'jc -h arp': (False, None, None, []), - 'jc -h arp -a': (False, None, None, []) + 'jc -h arp -a': (False, None, None, []), + 'jc --pretty dig': (True, ['dig'], '--dig', ['p']), + 'jc --pretty --monochrome --quiet --raw dig': (True, ['dig'], '--dig', ['p', 'm', 'q', 'r']), + 'jc --about --yaml-out': (False, None, None, []) } for command, expected_command in commands.items():