mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-06-17 00:07:37 +02:00
332 lines
9.1 KiB
Python
332 lines
9.1 KiB
Python
"""jc - JSON Convert lib module"""
|
|
import sys
|
|
import os
|
|
import re
|
|
import importlib
|
|
from typing import Dict, List, Iterable, Union, Iterator
|
|
from jc import appdirs
|
|
|
|
__version__ = '1.20.0'
|
|
|
|
parsers = [
|
|
'acpi',
|
|
'airport',
|
|
'airport-s',
|
|
'arp',
|
|
'asciitable',
|
|
'asciitable-m',
|
|
'blkid',
|
|
'chage',
|
|
'cksum',
|
|
'crontab',
|
|
'crontab-u',
|
|
'csv',
|
|
'csv-s',
|
|
'date',
|
|
'df',
|
|
'dig',
|
|
'dir',
|
|
'dmidecode',
|
|
'dpkg-l',
|
|
'du',
|
|
'env',
|
|
'file',
|
|
'finger',
|
|
'free',
|
|
'fstab',
|
|
'git-log',
|
|
'git-log-s',
|
|
'group',
|
|
'gshadow',
|
|
'hash',
|
|
'hashsum',
|
|
'hciconfig',
|
|
'history',
|
|
'hosts',
|
|
'id',
|
|
'ifconfig',
|
|
'ini',
|
|
'iostat',
|
|
'iostat-s',
|
|
'iptables',
|
|
'iw-scan',
|
|
'jar-manifest',
|
|
'jobs',
|
|
'kv',
|
|
'last',
|
|
'ls',
|
|
'ls-s',
|
|
'lsblk',
|
|
'lsmod',
|
|
'lsof',
|
|
'lsusb',
|
|
'mount',
|
|
'mpstat',
|
|
'mpstat-s',
|
|
'netstat',
|
|
'nmcli',
|
|
'ntpq',
|
|
'passwd',
|
|
'pidstat',
|
|
'pidstat-s',
|
|
'ping',
|
|
'ping-s',
|
|
'pip-list',
|
|
'pip-show',
|
|
'ps',
|
|
'route',
|
|
'rpm-qi',
|
|
'rsync',
|
|
'rsync-s',
|
|
'sfdisk',
|
|
'shadow',
|
|
'ss',
|
|
'stat',
|
|
'stat-s',
|
|
'sysctl',
|
|
'systemctl',
|
|
'systemctl-lj',
|
|
'systemctl-ls',
|
|
'systemctl-luf',
|
|
'systeminfo',
|
|
'time',
|
|
'timedatectl',
|
|
'top',
|
|
'top-s',
|
|
'tracepath',
|
|
'traceroute',
|
|
'ufw',
|
|
'ufw-appinfo',
|
|
'uname',
|
|
'update-alt-gs',
|
|
'update-alt-q',
|
|
'upower',
|
|
'uptime',
|
|
'vmstat',
|
|
'vmstat-s',
|
|
'w',
|
|
'wc',
|
|
'who',
|
|
'xml',
|
|
'xrandr',
|
|
'yaml',
|
|
'zipinfo'
|
|
]
|
|
|
|
def _cliname_to_modname(parser_cli_name):
|
|
"""Return real module name (dashes converted to underscores)"""
|
|
return parser_cli_name.replace('--', '').replace('-', '_')
|
|
|
|
def _modname_to_cliname(parser_mod_name):
|
|
"""Return module's cli name (underscores converted to dashes)"""
|
|
return parser_mod_name.replace('_', '-')
|
|
|
|
# Create the local_parsers list. This is a list of custom or
|
|
# override parsers from <user_data_dir>/jc/jcparsers/*.py.
|
|
# Once this list is created, extend the parsers list with it.
|
|
local_parsers = []
|
|
data_dir = appdirs.user_data_dir('jc', 'jc')
|
|
local_parsers_dir = os.path.join(data_dir, 'jcparsers')
|
|
if os.path.isdir(local_parsers_dir):
|
|
sys.path.append(data_dir)
|
|
for name in os.listdir(local_parsers_dir):
|
|
if re.match(r'\w+\.py$', name) and os.path.isfile(os.path.join(local_parsers_dir, name)):
|
|
plugin_name = name[0:-3]
|
|
local_parsers.append(_modname_to_cliname(plugin_name))
|
|
if plugin_name not in parsers:
|
|
parsers.append(_modname_to_cliname(plugin_name))
|
|
try:
|
|
del name
|
|
except Exception:
|
|
pass
|
|
|
|
def _parser_argument(parser_mod_name):
|
|
"""Return short name of the parser with dashes and with -- prefix"""
|
|
parser = _modname_to_cliname(parser_mod_name)
|
|
return f'--{parser}'
|
|
|
|
def _get_parser(parser_mod_name):
|
|
"""Return the parser module object"""
|
|
# ensure parser_mod_name is a true module name and not a cli name
|
|
parser_mod_name = _cliname_to_modname(parser_mod_name)
|
|
|
|
parser_cli_name = _modname_to_cliname(parser_mod_name)
|
|
modpath = 'jcparsers.' if parser_cli_name in local_parsers else 'jc.parsers.'
|
|
return importlib.import_module(f'{modpath}{parser_mod_name}')
|
|
|
|
def _parser_is_streaming(parser):
|
|
"""
|
|
Returns True if this is a streaming parser, else False
|
|
|
|
parser is a parser module object.
|
|
"""
|
|
if getattr(parser.info, 'streaming', None):
|
|
return True
|
|
|
|
return False
|
|
|
|
def parse(
|
|
parser_mod_name: str,
|
|
data: Union[str, Iterable[str]],
|
|
quiet: bool = False,
|
|
raw: bool = False,
|
|
ignore_exceptions: bool = None,
|
|
**kwargs
|
|
) -> Union[Dict, List[Dict], Iterator[Dict]]:
|
|
"""
|
|
Parse the string data using the supplied parser module.
|
|
|
|
This function provides a high-level API to simplify parser use. This
|
|
function will call built-in parsers and custom plugin parsers.
|
|
|
|
Example:
|
|
|
|
>>> import jc
|
|
>>> jc.parse('date', 'Tue Jan 18 10:23:07 PST 2022')
|
|
{'year': 2022, 'month': 'Jan', 'month_num': 1, 'day'...}
|
|
|
|
To get a list of available parser module names, use `parser_mod_list()`.
|
|
|
|
You can also use the lower-level parser modules directly:
|
|
|
|
>>> import jc.parsers.date
|
|
>>> jc.parsers.date.parse('Tue Jan 18 10:23:07 PST 2022')
|
|
|
|
Though, accessing plugin parsers directly is a bit more cumbersome, so
|
|
this higher-level API is recommended. Here is how you can access plugin
|
|
parsers without this API:
|
|
|
|
>>> import os
|
|
>>> import sys
|
|
>>> import jc.appdirs
|
|
>>> data_dir = jc.appdirs.user_data_dir('jc', 'jc')
|
|
>>> local_parsers_dir = os.path.join(data_dir, 'jcparsers')
|
|
>>> sys.path.append(local_parsers_dir)
|
|
>>> import my_custom_parser
|
|
>>> my_custom_parser.parse('command_data')
|
|
|
|
Parameters:
|
|
|
|
parser_mod_name: (string) name of the parser module. This
|
|
function will accept module_name,
|
|
cli-name, and --argument-name
|
|
variants of the module name.
|
|
|
|
data: (string or data to parse (string for normal
|
|
iterable) parsers, iterable of strings for
|
|
streaming parsers)
|
|
|
|
raw: (boolean) output preprocessed JSON if True
|
|
|
|
quiet: (boolean) suppress warning messages if True
|
|
|
|
ignore_exceptions: (boolean) ignore parsing exceptions if True
|
|
(streaming parsers only)
|
|
|
|
Returns:
|
|
|
|
Standard Parsers: Dictionary or List of Dictionaries
|
|
Streaming Parsers: Generator Object containing Dictionaries
|
|
"""
|
|
jc_parser = _get_parser(parser_mod_name)
|
|
|
|
if ignore_exceptions is not None:
|
|
return jc_parser.parse(data, quiet=quiet, raw=raw,
|
|
ignore_exceptions=ignore_exceptions, **kwargs)
|
|
|
|
return jc_parser.parse(data, quiet=quiet, raw=raw, **kwargs)
|
|
|
|
def parser_mod_list() -> List[str]:
|
|
"""Returns a list of all available parser module names."""
|
|
return [_cliname_to_modname(p) for p in parsers]
|
|
|
|
def plugin_parser_mod_list() -> List[str]:
|
|
"""
|
|
Returns a list of plugin parser module names. This function is a
|
|
subset of `parser_mod_list()`.
|
|
"""
|
|
return [_cliname_to_modname(p) for p in local_parsers]
|
|
|
|
def standard_parser_mod_list() -> List[str]:
|
|
"""
|
|
Returns a list of standard parser module names. This function is a
|
|
subset of `parser_mod_list()` and does not contain any streaming
|
|
parsers.
|
|
"""
|
|
plist = []
|
|
for p in parsers:
|
|
parser = _get_parser(p)
|
|
if not _parser_is_streaming(parser):
|
|
plist.append(_cliname_to_modname(p))
|
|
return plist
|
|
|
|
def streaming_parser_mod_list() -> List[str]:
|
|
"""
|
|
Returns a list of streaming parser module names. This function is a
|
|
subset of `parser_mod_list()`.
|
|
"""
|
|
plist = []
|
|
for p in parsers:
|
|
parser = _get_parser(p)
|
|
if _parser_is_streaming(parser):
|
|
plist.append(_cliname_to_modname(p))
|
|
return plist
|
|
|
|
def parser_info(parser_mod_name: str, documentation: bool = False) -> Dict:
|
|
"""
|
|
Returns a dictionary that includes the parser module metadata.
|
|
|
|
Parameters:
|
|
|
|
parser_mod_name: (string) name of the parser module. This
|
|
function will accept module_name,
|
|
cli-name, and --argument-name
|
|
variants of the module name.
|
|
|
|
documentation: (boolean) include parser docstring if True
|
|
"""
|
|
# ensure parser_mod_name is a true module name and not a cli name
|
|
parser_mod_name = _cliname_to_modname(parser_mod_name)
|
|
parser_mod = _get_parser(parser_mod_name)
|
|
info_dict: Dict = {}
|
|
|
|
if hasattr(parser_mod, 'info'):
|
|
info_dict['name'] = parser_mod_name
|
|
info_dict['argument'] = _parser_argument(parser_mod_name)
|
|
parser_entry = vars(parser_mod.info)
|
|
|
|
for k, v in parser_entry.items():
|
|
if not k.startswith('__'):
|
|
info_dict[k] = v
|
|
|
|
if _modname_to_cliname(parser_mod_name) in local_parsers:
|
|
info_dict['plugin'] = True
|
|
|
|
if documentation:
|
|
docs = parser_mod.__doc__
|
|
if not docs:
|
|
docs = 'No documentation available.\n'
|
|
info_dict['documentation'] = docs
|
|
|
|
return info_dict
|
|
|
|
def all_parser_info(documentation: bool = False) -> List[Dict]:
|
|
"""
|
|
Returns a list of dictionaries that includes metadata for all parser
|
|
modules.
|
|
|
|
Parameters:
|
|
|
|
documentation: (boolean) include parser docstrings if True
|
|
"""
|
|
return [parser_info(p, documentation=documentation) for p in parsers]
|
|
|
|
def get_help(parser_mod_name: str) -> None:
|
|
"""
|
|
Show help screen for the selected parser.
|
|
|
|
This function will accept **module_name**, **cli-name**, and
|
|
**--argument-name** variants of the module name string.
|
|
"""
|
|
help(_get_parser(parser_mod_name))
|