mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2026-04-05 17:50:11 +02:00
Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0d6a7307c | ||
|
|
53ad793ff8 | ||
|
|
ea4332d8e4 | ||
|
|
5c5ff9324f | ||
|
|
2ab6352fdb | ||
|
|
56dcbaf40c | ||
|
|
029b5abcac | ||
|
|
32521ac91a | ||
|
|
bf88407902 | ||
|
|
63cf47db63 | ||
|
|
9970866b3b | ||
|
|
d61941b276 | ||
|
|
081fdb8026 | ||
|
|
f64dfbf79d | ||
|
|
5fb73f4ad5 | ||
|
|
1c16d32420 | ||
|
|
e367e0d714 | ||
|
|
4046649e32 | ||
|
|
77fcfe439c | ||
|
|
71d1355419 | ||
|
|
d1b270f336 | ||
|
|
9190a08332 | ||
|
|
3fae50e305 | ||
|
|
3582497ed4 | ||
|
|
19a67daabf | ||
|
|
02a7e5fd8a | ||
|
|
df72b16022 | ||
|
|
61bdc13810 | ||
|
|
1350a34316 | ||
|
|
7cfe68b96a | ||
|
|
7a93a61f54 | ||
|
|
362977e598 | ||
|
|
5cac897beb | ||
|
|
cad94cc6b3 | ||
|
|
fe4e429e85 | ||
|
|
d83b10e2d5 | ||
|
|
bd2a757fcd | ||
|
|
358b69a4cb | ||
|
|
08821a1454 | ||
|
|
90277c1d87 | ||
|
|
a51e702f77 | ||
|
|
466e37128b | ||
|
|
f1ea61388f | ||
|
|
72c11fda3a | ||
|
|
d6645983ef | ||
|
|
01e911ecdb | ||
|
|
12c0b3d889 | ||
|
|
c1075e40b7 | ||
|
|
fabe3f01b7 | ||
|
|
3a2ff61899 | ||
|
|
aeff94d272 | ||
|
|
c94f5d83fa | ||
|
|
b0756fa0f9 | ||
|
|
6c85abd57b | ||
|
|
7659ae94bd | ||
|
|
e306e81e43 | ||
|
|
6d5768b26b | ||
|
|
cee9f8bf32 | ||
|
|
b8e2678c01 | ||
|
|
b0fe96ed03 | ||
|
|
bb65ec380b | ||
|
|
ae6248227b | ||
|
|
36ce3c791d | ||
|
|
5d639db5a8 | ||
|
|
63161ffdbb | ||
|
|
cf11c71831 | ||
|
|
048f8c1f4b | ||
|
|
b6b42d9071 | ||
|
|
d43863ee9f | ||
|
|
177d10577f | ||
|
|
47d8e163de | ||
|
|
e49c621e59 | ||
|
|
5e32a6d828 | ||
|
|
b1358a7eca | ||
|
|
ba89092e12 | ||
|
|
f855420a82 | ||
|
|
1589a81945 | ||
|
|
eec2583cb2 | ||
|
|
481c6a8de2 | ||
|
|
68717e8493 | ||
|
|
c524d37136 | ||
|
|
6674f549f2 | ||
|
|
ba371ec730 | ||
|
|
44d1d52426 | ||
|
|
edcca4fb96 | ||
|
|
6fbf9458d1 | ||
|
|
a476e4639b | ||
|
|
5534a1c755 | ||
|
|
c45518db70 | ||
|
|
55480c059a | ||
|
|
04a2af8681 | ||
|
|
71f672a0e0 | ||
|
|
33c40874fa | ||
|
|
b3ced64672 | ||
|
|
a60bf00d54 | ||
|
|
8d9a2744af | ||
|
|
bcd7bac950 | ||
|
|
e996b3a9f6 | ||
|
|
e207cccdc5 | ||
|
|
9776dd1082 |
4
.github/workflows/pythonapp.yml
vendored
4
.github/workflows/pythonapp.yml
vendored
@@ -13,8 +13,8 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
|
||||
os: [macos-latest, ubuntu-20.04, windows-latest]
|
||||
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
23
CHANGELOG
23
CHANGELOG
@@ -1,5 +1,28 @@
|
||||
jc changelog
|
||||
|
||||
20230111 v1.22.5
|
||||
- Add TOML file parser
|
||||
- Add INI with duplicate key support file parser
|
||||
- Add AIX support for the `arp` command parser
|
||||
- Add AIX support for the `mount` command parser
|
||||
- Fix `lsusb` command parser when extra hub port status information is output
|
||||
- Refactor `lsusb` command parser for more code reuse
|
||||
- Fix INI file parser to include top-level values with no section header
|
||||
- Fix INI file parser to not specially handle the [DEFAULT] section
|
||||
- Fix INI file and Key/Value parsers to only remove one quotation mark from the
|
||||
beginning and end of values.
|
||||
- Update copyright dates
|
||||
|
||||
20221230 v1.22.4
|
||||
- Add `iwconfig` command parser
|
||||
- Add NeXTSTEP format support to the PLIST file parser
|
||||
- Fix `proc` parser magic signature detection for `/proc/pid/stat` hacks
|
||||
- Fix `x509-cert` parser for string serial numbers
|
||||
- Add category tags to parser metadata: generic, standard, file, string, binary, command
|
||||
- Add "list parsers by category" view to help
|
||||
- Fix python 3.6-related issues
|
||||
- Add python 3.6 to automated tests
|
||||
|
||||
20221216 v1.22.3
|
||||
- Add Common Log Format and Combined Log Format file parser (standard and streaming)
|
||||
- Add PostgreSQL password file parser
|
||||
|
||||
16
EXAMPLES.md
16
EXAMPLES.md
@@ -1636,21 +1636,21 @@ cat example.ini | jc --ini -p
|
||||
```
|
||||
```json
|
||||
{
|
||||
"bitbucket.org": {
|
||||
"ServeraLiveInterval": "45",
|
||||
"DEFAULT": {
|
||||
"ServerAliveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "yes",
|
||||
"ForwardX11": "yes"
|
||||
},
|
||||
"bitbucket.org": {
|
||||
"User": "hg"
|
||||
},
|
||||
"topsecret.server.com": {
|
||||
"ServeraLiveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "no",
|
||||
"Port": "50022"
|
||||
"Port": "50022",
|
||||
"ForwardX11": "no"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
### iostat
|
||||
```bash
|
||||
|
||||
45
README.md
45
README.md
@@ -201,15 +201,17 @@ option.
|
||||
| ` --id` | `id` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/id) |
|
||||
| ` --ifconfig` | `ifconfig` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ifconfig) |
|
||||
| ` --ini` | INI file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ini) |
|
||||
| ` --ini-dup` | INI with duplicate key file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ini_dup) |
|
||||
| ` --iostat` | `iostat` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/iostat) |
|
||||
| ` --iostat-s` | `iostat` command streaming parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/iostat_s) |
|
||||
| ` --ip-address` | IPv4 and IPv6 Address string parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ip_address) |
|
||||
| ` --iptables` | `iptables` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/iptables) |
|
||||
| ` --iw-scan` | `iw dev [device] scan` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/iw_scan) |
|
||||
| ` --iwconfig` | `iwconfig` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/iwconfig) |
|
||||
| ` --jar-manifest` | Java MANIFEST.MF file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/jar_manifest) |
|
||||
| ` --jobs` | `jobs` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/jobs) |
|
||||
| ` --jwt` | JWT string parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/jwt) |
|
||||
| ` --kv` | Key/Value file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/kv) |
|
||||
| ` --kv` | Key/Value file and string parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/kv) |
|
||||
| ` --last` | `last` and `lastb` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/last) |
|
||||
| ` --ls` | `ls` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ls) |
|
||||
| ` --ls-s` | `ls` command streaming parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/ls_s) |
|
||||
@@ -265,6 +267,7 @@ option.
|
||||
| ` --time` | `/usr/bin/time` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/time) |
|
||||
| ` --timedatectl` | `timedatectl status` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/timedatectl) |
|
||||
| ` --timestamp` | Unix Epoch Timestamp string parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/timestamp) |
|
||||
| ` --toml` | TOML file parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/toml) |
|
||||
| ` --top` | `top -b` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/top) |
|
||||
| ` --top-s` | `top -b` command streaming parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/top_s) |
|
||||
| ` --tracepath` | `tracepath` and `tracepath6` command parser | [details](https://kellyjonbrazil.github.io/jc/docs/parsers/tracepath) |
|
||||
@@ -755,37 +758,31 @@ ifconfig | jc -p --ifconfig # or: jc -p ifconfig
|
||||
cat example.ini
|
||||
```
|
||||
```
|
||||
[DEFAULT]
|
||||
ServerAliveInterval = 45
|
||||
Compression = yes
|
||||
CompressionLevel = 9
|
||||
ForwardX11 = yes
|
||||
foo = fiz
|
||||
bar = buz
|
||||
|
||||
[bitbucket.org]
|
||||
User = hg
|
||||
[section1]
|
||||
fruit = apple
|
||||
color = blue
|
||||
|
||||
[topsecret.server.com]
|
||||
Port = 50022
|
||||
ForwardX11 = no
|
||||
[section2]
|
||||
fruit = pear
|
||||
color = green
|
||||
```
|
||||
```bash
|
||||
cat example.ini | jc -p --ini
|
||||
```
|
||||
```json
|
||||
{
|
||||
"bitbucket.org": {
|
||||
"ServeraLiveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "yes",
|
||||
"User": "hg"
|
||||
"foo": "fiz",
|
||||
"bar": "buz",
|
||||
"section1": {
|
||||
"fruit": "apple",
|
||||
"color": "blue"
|
||||
},
|
||||
"topsecret.server.com": {
|
||||
"ServeraLiveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "no",
|
||||
"Port": "50022"
|
||||
"section2": {
|
||||
"fruit": "pear",
|
||||
"color": "green"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1241,4 +1238,4 @@ cat istio.yaml | jc -p --yaml
|
||||
]
|
||||
```
|
||||
|
||||
© 2019-2022 Kelly Brazil
|
||||
© 2019-2023 Kelly Brazil
|
||||
@@ -3,8 +3,8 @@ _jc()
|
||||
local cur prev words cword jc_commands jc_parsers jc_options \
|
||||
jc_about_options jc_about_mod_options jc_help_options jc_special_options
|
||||
|
||||
jc_commands=(acpi airport arp blkid cbt chage cksum crontab date df dig dmidecode dpkg du env file findmnt finger free git gpg hciconfig id ifconfig iostat iptables iw jobs last lastb ls lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat netstat nmcli ntpq os-prober pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss sshd stat sum sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 udevadm ufw uname update-alternatives upower uptime vdir vmstat w wc who xrandr zipinfo)
|
||||
jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --openvpn --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo)
|
||||
jc_commands=(acpi airport arp blkid cbt chage cksum crontab date df dig dmidecode dpkg du env file findmnt finger free git gpg hciconfig id ifconfig iostat iptables iw iwconfig jobs last lastb ls lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat netstat nmcli ntpq os-prober pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss sshd stat sum sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 udevadm ufw uname update-alternatives upower uptime vdir vmstat w wc who xrandr zipinfo)
|
||||
jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --iptables --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --openvpn --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo)
|
||||
jc_options=(--force-color -C --debug -d --monochrome -m --meta-out -M --pretty -p --quiet -q --raw -r --unbuffer -u --yaml-out -y)
|
||||
jc_about_options=(--about -a)
|
||||
jc_about_mod_options=(--pretty -p --yaml-out -y --monochrome -m --force-color -C)
|
||||
|
||||
@@ -9,7 +9,7 @@ _jc() {
|
||||
jc_help_options jc_help_options_describe \
|
||||
jc_special_options jc_special_options_describe
|
||||
|
||||
jc_commands=(acpi airport arp blkid cbt chage cksum crontab date df dig dmidecode dpkg du env file findmnt finger free git gpg hciconfig id ifconfig iostat iptables iw jobs last lastb ls lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat netstat nmcli ntpq os-prober pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss sshd stat sum sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 udevadm ufw uname update-alternatives upower uptime vdir vmstat w wc who xrandr zipinfo)
|
||||
jc_commands=(acpi airport arp blkid cbt chage cksum crontab date df dig dmidecode dpkg du env file findmnt finger free git gpg hciconfig id ifconfig iostat iptables iw iwconfig jobs last lastb ls lsblk lsmod lsof lspci lsusb md5 md5sum mdadm mount mpstat netstat nmcli ntpq os-prober pidstat ping ping6 pip pip3 postconf printenv ps route rpm rsync sfdisk sha1sum sha224sum sha256sum sha384sum sha512sum shasum ss sshd stat sum sysctl systemctl systeminfo timedatectl top tracepath tracepath6 traceroute traceroute6 udevadm ufw uname update-alternatives upower uptime vdir vmstat w wc who xrandr zipinfo)
|
||||
jc_commands_describe=(
|
||||
'acpi:run "acpi" command with magic syntax.'
|
||||
'airport:run "airport" command with magic syntax.'
|
||||
@@ -38,6 +38,7 @@ _jc() {
|
||||
'iostat:run "iostat" command with magic syntax.'
|
||||
'iptables:run "iptables" command with magic syntax.'
|
||||
'iw:run "iw" command with magic syntax.'
|
||||
'iwconfig:run "iwconfig" command with magic syntax.'
|
||||
'jobs:run "jobs" command with magic syntax.'
|
||||
'last:run "last" command with magic syntax.'
|
||||
'lastb:run "lastb" command with magic syntax.'
|
||||
@@ -101,7 +102,7 @@ _jc() {
|
||||
'xrandr:run "xrandr" command with magic syntax.'
|
||||
'zipinfo:run "zipinfo" command with magic syntax.'
|
||||
)
|
||||
jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --iostat --iostat-s --ip-address --iptables --iw-scan --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --openvpn --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo)
|
||||
jc_parsers=(--acpi --airport --airport-s --arp --asciitable --asciitable-m --blkid --cbt --cef --cef-s --chage --cksum --clf --clf-s --crontab --crontab-u --csv --csv-s --date --datetime-iso --df --dig --dir --dmidecode --dpkg-l --du --email-address --env --file --findmnt --finger --free --fstab --git-log --git-log-s --git-ls-remote --gpg --group --gshadow --hash --hashsum --hciconfig --history --hosts --id --ifconfig --ini --ini-dup --iostat --iostat-s --ip-address --iptables --iw-scan --iwconfig --jar-manifest --jobs --jwt --kv --last --ls --ls-s --lsblk --lsmod --lsof --lspci --lsusb --m3u --mdadm --mount --mpstat --mpstat-s --netstat --nmcli --ntpq --openvpn --os-prober --passwd --pci-ids --pgpass --pidstat --pidstat-s --ping --ping-s --pip-list --pip-show --plist --postconf --proc --proc-buddyinfo --proc-consoles --proc-cpuinfo --proc-crypto --proc-devices --proc-diskstats --proc-filesystems --proc-interrupts --proc-iomem --proc-ioports --proc-loadavg --proc-locks --proc-meminfo --proc-modules --proc-mtrr --proc-pagetypeinfo --proc-partitions --proc-slabinfo --proc-softirqs --proc-stat --proc-swaps --proc-uptime --proc-version --proc-vmallocinfo --proc-vmstat --proc-zoneinfo --proc-driver-rtc --proc-net-arp --proc-net-dev --proc-net-dev-mcast --proc-net-if-inet6 --proc-net-igmp --proc-net-igmp6 --proc-net-ipv6-route --proc-net-netlink --proc-net-netstat --proc-net-packet --proc-net-protocols --proc-net-route --proc-net-unix --proc-pid-fdinfo --proc-pid-io --proc-pid-maps --proc-pid-mountinfo --proc-pid-numa-maps --proc-pid-smaps --proc-pid-stat --proc-pid-statm --proc-pid-status --ps --route --rpm-qi --rsync --rsync-s --semver --sfdisk --shadow --ss --sshd-conf --stat --stat-s --sysctl --syslog --syslog-s --syslog-bsd --syslog-bsd-s --systemctl --systemctl-lj --systemctl-ls --systemctl-luf --systeminfo --time --timedatectl --timestamp --toml --top --top-s --tracepath --traceroute --udevadm --ufw --ufw-appinfo --uname --update-alt-gs --update-alt-q --upower --uptime --url --vmstat --vmstat-s --w --wc --who --x509-cert --xml --xrandr --yaml --zipinfo)
|
||||
jc_parsers_describe=(
|
||||
'--acpi:`acpi` command parser'
|
||||
'--airport:`airport -I` command parser'
|
||||
@@ -150,15 +151,17 @@ _jc() {
|
||||
'--id:`id` command parser'
|
||||
'--ifconfig:`ifconfig` command parser'
|
||||
'--ini:INI file parser'
|
||||
'--ini-dup:INI with duplicate key file parser'
|
||||
'--iostat:`iostat` command parser'
|
||||
'--iostat-s:`iostat` command streaming parser'
|
||||
'--ip-address:IPv4 and IPv6 Address string parser'
|
||||
'--iptables:`iptables` command parser'
|
||||
'--iw-scan:`iw dev [device] scan` command parser'
|
||||
'--iwconfig:`iwconfig` command parser'
|
||||
'--jar-manifest:Java MANIFEST.MF file parser'
|
||||
'--jobs:`jobs` command parser'
|
||||
'--jwt:JWT string parser'
|
||||
'--kv:Key/Value file parser'
|
||||
'--kv:Key/Value file and string parser'
|
||||
'--last:`last` and `lastb` command parser'
|
||||
'--ls:`ls` command parser'
|
||||
'--ls-s:`ls` command streaming parser'
|
||||
@@ -263,6 +266,7 @@ _jc() {
|
||||
'--time:`/usr/bin/time` command parser'
|
||||
'--timedatectl:`timedatectl status` command parser'
|
||||
'--timestamp:Unix Epoch Timestamp string parser'
|
||||
'--toml:TOML file parser'
|
||||
'--top:`top -b` command parser'
|
||||
'--top-s:`top -b` command streaming parser'
|
||||
'--tracepath:`tracepath` and `tracepath6` command parser'
|
||||
@@ -289,8 +293,8 @@ _jc() {
|
||||
)
|
||||
jc_options=(--force-color -C --debug -d --monochrome -m --meta-out -M --pretty -p --quiet -q --raw -r --unbuffer -u --yaml-out -y)
|
||||
jc_options_describe=(
|
||||
'--force-color:force color output even when using pipes (overrides -m)'
|
||||
'-C:force color output even when using pipes (overrides -m)'
|
||||
'--force-color:force color output (overrides -m)'
|
||||
'-C:force color output (overrides -m)'
|
||||
'--debug:debug (double for verbose debug)'
|
||||
'-d:debug (double for verbose debug)'
|
||||
'--monochrome:monochrome output'
|
||||
@@ -321,8 +325,8 @@ _jc() {
|
||||
'-y:YAML output'
|
||||
'--monochrome:monochrome output'
|
||||
'-m:monochrome output'
|
||||
'--force-color:force color output even when using pipes (overrides -m)'
|
||||
'-C:force color output even when using pipes (overrides -m)'
|
||||
'--force-color:force color output (overrides -m)'
|
||||
'-C:force color output (overrides -m)'
|
||||
)
|
||||
jc_help_options=(--help -h)
|
||||
jc_help_options_describe=(
|
||||
|
||||
@@ -140,4 +140,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, aix, freebsd, darwin
|
||||
|
||||
Version 1.11 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.12 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -114,4 +114,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -240,4 +240,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, aix, freebsd, darwin
|
||||
|
||||
Version 2.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 2.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
|
||||
# jc.parsers.ini
|
||||
|
||||
jc - JSON Convert `INI` file parser
|
||||
jc - JSON Convert INI file parser
|
||||
|
||||
Parses standard `INI` files and files containing simple key/value pairs.
|
||||
Parses standard INI files.
|
||||
|
||||
- Delimiter can be `=` or `:`. Missing values are supported.
|
||||
- Comment prefix can be `#` or `;`. Comments must be on their own line.
|
||||
- If duplicate keys are found, only the last value will be used.
|
||||
- If any section names have the same name as a top-level key, the top-level
|
||||
key will be overwritten by the section data.
|
||||
|
||||
> Note: Values starting and ending with double or single quotation marks
|
||||
> will have the marks removed. If you would like to keep the quotation
|
||||
@@ -27,45 +29,47 @@ Usage (module):
|
||||
|
||||
Schema:
|
||||
|
||||
ini or key/value document converted to a dictionary - see the configparser
|
||||
INI document converted to a dictionary - see the python configparser
|
||||
standard library documentation for more details.
|
||||
|
||||
{
|
||||
"key1": string,
|
||||
"key2": string
|
||||
"<key1>": string,
|
||||
"<key2>": string,
|
||||
"<section1>": {
|
||||
"<key1>": string,
|
||||
"<key2>": string
|
||||
},
|
||||
"<section2>": {
|
||||
"<key1>": string,
|
||||
"<key2>": string
|
||||
}
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat example.ini
|
||||
[DEFAULT]
|
||||
ServerAliveInterval = 45
|
||||
Compression = yes
|
||||
CompressionLevel = 9
|
||||
ForwardX11 = yes
|
||||
foo = fiz
|
||||
bar = buz
|
||||
|
||||
[bitbucket.org]
|
||||
User = hg
|
||||
[section1]
|
||||
fruit = apple
|
||||
color = blue
|
||||
|
||||
[topsecret.server.com]
|
||||
Port = 50022
|
||||
ForwardX11 = no
|
||||
[section2]
|
||||
fruit = pear
|
||||
color = green
|
||||
|
||||
$ cat example.ini | jc --ini -p
|
||||
{
|
||||
"bitbucket.org": {
|
||||
"ServerAliveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "yes",
|
||||
"User": "hg"
|
||||
"foo": "fiz",
|
||||
"bar": "buz",
|
||||
"section1": {
|
||||
"fruit": "apple",
|
||||
"color": "blue"
|
||||
},
|
||||
"topsecret.server.com": {
|
||||
"ServerAliveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "no",
|
||||
"Port": "50022"
|
||||
"section2": {
|
||||
"fruit": "pear",
|
||||
"color": "green"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,9 +91,9 @@ Parameters:
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing the ini file
|
||||
Dictionary representing the INI file.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 2.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
121
docs/parsers/ini_dup.md
Normal file
121
docs/parsers/ini_dup.md
Normal file
@@ -0,0 +1,121 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.ini_dup"></a>
|
||||
|
||||
# jc.parsers.ini\_dup
|
||||
|
||||
jc - JSON Convert INI with duplicate key file parser
|
||||
|
||||
Parses standard INI files and preserves duplicate values. All values are
|
||||
contained in lists/arrays.
|
||||
|
||||
- Delimiter can be `=` or `:`. Missing values are supported.
|
||||
- Comment prefix can be `#` or `;`. Comments must be on their own line.
|
||||
- If any section names have the same name as a top-level key, the top-level
|
||||
key will be overwritten by the section data.
|
||||
- If multi-line values are used, each line will be a separate item in the
|
||||
value list. Blank lines in multi-line values are not supported.
|
||||
|
||||
> 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):
|
||||
|
||||
$ cat foo.ini | jc --ini
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('ini', ini_file_output)
|
||||
|
||||
Schema:
|
||||
|
||||
INI document converted to a dictionary - see the python configparser
|
||||
standard library documentation for more details.
|
||||
|
||||
{
|
||||
"<key1>": [
|
||||
string
|
||||
],
|
||||
"<key2>": [
|
||||
string
|
||||
],
|
||||
"<section1>": {
|
||||
"<key1>": [
|
||||
string
|
||||
],
|
||||
"<key2>": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat example.ini
|
||||
foo = fiz
|
||||
bar = buz
|
||||
|
||||
[section1]
|
||||
fruit = apple
|
||||
color = blue
|
||||
color = red
|
||||
|
||||
[section2]
|
||||
fruit = pear
|
||||
fruit = peach
|
||||
color = green
|
||||
|
||||
$ cat example.ini | jc --ini -p
|
||||
{
|
||||
"foo": [
|
||||
"fiz"
|
||||
],
|
||||
"bar": [
|
||||
"buz"
|
||||
],
|
||||
"section1": {
|
||||
"fruit": [
|
||||
"apple"
|
||||
],
|
||||
"color": [
|
||||
"blue",
|
||||
"red"
|
||||
]
|
||||
},
|
||||
"section2": {
|
||||
"fruit": [
|
||||
"pear",
|
||||
"peach"
|
||||
],
|
||||
"color": [
|
||||
"green"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
<a id="jc.parsers.ini_dup.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data, raw=False, quiet=False)
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
Dictionary representing the INI file.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
111
docs/parsers/iwconfig.md
Normal file
111
docs/parsers/iwconfig.md
Normal file
@@ -0,0 +1,111 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.iwconfig"></a>
|
||||
|
||||
# jc.parsers.iwconfig
|
||||
|
||||
jc - JSON Convert `iwconfig` command output parser
|
||||
|
||||
No `iwconfig` options are supported.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ iwconfig | jc --iwconfig
|
||||
|
||||
or
|
||||
|
||||
$ jc iwconfig
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('iwconfig', iwconfig_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"name": string,
|
||||
"protocol": string,
|
||||
"essid": string,
|
||||
"mode": string,
|
||||
"frequency": float,
|
||||
"frequency_unit": string,
|
||||
"access_point": string,
|
||||
"bit_rate": float,
|
||||
"bit_rate_unit": string,
|
||||
"tx_power": integer,
|
||||
"tx_power_unit": string,
|
||||
"retry_short_limit": integer,
|
||||
"rts_threshold": boolean,
|
||||
"fragment_threshold": boolean,
|
||||
"power_management": boolean,
|
||||
"link_quality": string,
|
||||
"signal_level": integer,
|
||||
"signal_level_unit": string,
|
||||
"rx_invalid_nwid": integer,
|
||||
"rx_invalid_crypt": integer,
|
||||
"rx_invalid_frag": integer,
|
||||
"tx_excessive_retries": integer,
|
||||
"invalid_misc": integer,
|
||||
"missed_beacon": integer
|
||||
}
|
||||
]
|
||||
|
||||
Examples:
|
||||
|
||||
$ iwconfig | jc --iwconfig -p
|
||||
[
|
||||
{
|
||||
"name": "wlp5s0",
|
||||
"protocol": "IEEE 802.11",
|
||||
"essid": "BLABLABLA",
|
||||
"mode": "Managed",
|
||||
"frequency": 5.18,
|
||||
"frequency_unit": "GHz",
|
||||
"access_point": "E6:64:DA:16:51:BF",
|
||||
"bit_rate": 6.0,
|
||||
"bit_rate_unit": "Mb/s",
|
||||
"tx_power": 30,
|
||||
"tx_power_unit": "dBm",
|
||||
"retry_short_limit": 7,
|
||||
"rts_threshold": false,
|
||||
"fragment_threshold": false,
|
||||
"power_management": true,
|
||||
"link_quality": "61/70",
|
||||
"signal_level": -49,
|
||||
"signal_level_unit": "dBm",
|
||||
"rx_invalid_nwid": 0,
|
||||
"rx_invalid_crypt": 0,
|
||||
"rx_invalid_frag": 0,
|
||||
"tx_excessive_retries": 0,
|
||||
"invalid_misc": 2095,
|
||||
"missed_beacon": 0
|
||||
}
|
||||
]
|
||||
|
||||
<a id="jc.parsers.iwconfig.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data: str,
|
||||
raw: bool = False,
|
||||
quiet: bool = False) -> List[JSONDictType]
|
||||
```
|
||||
|
||||
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 Thomas Vincent (vrince@gmail.com)
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
# jc.parsers.kv
|
||||
|
||||
jc - JSON Convert `Key/Value` file parser
|
||||
jc - JSON Convert `Key/Value` file and string parser
|
||||
|
||||
Supports files containing simple key/value pairs.
|
||||
|
||||
@@ -26,8 +26,8 @@ Usage (module):
|
||||
|
||||
Schema:
|
||||
|
||||
key/value document converted to a dictionary - see the configparser standard
|
||||
library documentation for more details.
|
||||
Key/Value document converted to a dictionary - see the python configparser
|
||||
standard library documentation for more details.
|
||||
|
||||
{
|
||||
"key1": string,
|
||||
@@ -41,6 +41,7 @@ Examples:
|
||||
name = John Doe
|
||||
address=555 California Drive
|
||||
age: 34
|
||||
|
||||
; comments can include # or ;
|
||||
# delimiter can be = or :
|
||||
# quoted values have quotation marks stripped by default
|
||||
@@ -65,8 +66,6 @@ def parse(data, raw=False, quiet=False)
|
||||
|
||||
Main text parsing function
|
||||
|
||||
Note: this is just a wrapper for jc.parsers.ini
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
@@ -75,9 +74,9 @@ Parameters:
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing the key/value file
|
||||
Dictionary representing a Key/Value pair document.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 2.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -102,6 +102,28 @@ Schema:
|
||||
]
|
||||
}
|
||||
},
|
||||
"videocontrol_descriptors": [
|
||||
{
|
||||
"<item>": {
|
||||
"value": string,
|
||||
"description": string,
|
||||
"attributes": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"videostreaming_descriptors": [
|
||||
{
|
||||
"<item>": {
|
||||
"value": string,
|
||||
"description": string,
|
||||
"attributes": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"endpoint_descriptors": [
|
||||
{
|
||||
"<item>": {
|
||||
@@ -290,4 +312,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux
|
||||
|
||||
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.3 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -25,7 +25,7 @@ Schema:
|
||||
"filesystem": string,
|
||||
"mount_point": string,
|
||||
"type": string,
|
||||
"access": [
|
||||
"options": [
|
||||
string
|
||||
]
|
||||
}
|
||||
@@ -39,7 +39,7 @@ Example:
|
||||
"filesystem": "sysfs",
|
||||
"mount_point": "/sys",
|
||||
"type": "sysfs",
|
||||
"access": [
|
||||
"options": [
|
||||
"rw",
|
||||
"nosuid",
|
||||
"nodev",
|
||||
@@ -51,7 +51,7 @@ Example:
|
||||
"filesystem": "proc",
|
||||
"mount_point": "/proc",
|
||||
"type": "proc",
|
||||
"access": [
|
||||
"options": [
|
||||
"rw",
|
||||
"nosuid",
|
||||
"nodev",
|
||||
@@ -63,7 +63,7 @@ Example:
|
||||
"filesystem": "udev",
|
||||
"mount_point": "/dev",
|
||||
"type": "devtmpfs",
|
||||
"access": [
|
||||
"options": [
|
||||
"rw",
|
||||
"nosuid",
|
||||
"relatime",
|
||||
@@ -96,6 +96,6 @@ Returns:
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, freebsd
|
||||
Compatibility: linux, darwin, freebsd, aix
|
||||
|
||||
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.8 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
jc - JSON Convert PLIST file parser
|
||||
|
||||
Converts binary and XML PLIST files.
|
||||
Converts binary, XML, and NeXTSTEP PLIST files.
|
||||
|
||||
Binary values are converted into an ASCII hex representation.
|
||||
|
||||
@@ -69,9 +69,9 @@ Parameters:
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -139,4 +139,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
81
docs/parsers/toml.md
Normal file
81
docs/parsers/toml.md
Normal file
@@ -0,0 +1,81 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.toml"></a>
|
||||
|
||||
# jc.parsers.toml
|
||||
|
||||
jc - JSON Convert TOML file parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ cat file.toml | jc --toml
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('toml', toml_file_output)
|
||||
|
||||
Schema:
|
||||
|
||||
TOML Document converted to a Dictionary.
|
||||
See https://toml.io/en/ for details.
|
||||
|
||||
{
|
||||
"key1": string/int/float/boolean/null/array/object,
|
||||
"key2": string/int/float/boolean/null/array/object
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat file.toml
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
dob = 1979-05-27T07:32:00-08:00
|
||||
|
||||
[database]
|
||||
enabled = true
|
||||
ports = [ 8000, 8001, 8002 ]
|
||||
|
||||
$ cat file.toml | jc --toml -p
|
||||
{
|
||||
"title": "TOML Example",
|
||||
"owner": {
|
||||
"name": "Tom Preston-Werner",
|
||||
"dob": 296667120,
|
||||
"dob_iso": "1979-05-27T07:32:00-08:00"
|
||||
},
|
||||
"database": {
|
||||
"enabled": true,
|
||||
"ports": [
|
||||
8000,
|
||||
8001,
|
||||
8002
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
<a id="jc.parsers.toml.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data: str, raw: bool = False, quiet: bool = False) -> JSONDictType
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
@@ -32,6 +32,7 @@ Schema:
|
||||
"tbs_certificate": {
|
||||
"version": string,
|
||||
"serial_number": string, # [0]
|
||||
"serial_number_str": string,
|
||||
"signature": {
|
||||
"algorithm": string,
|
||||
"parameters": string/null,
|
||||
@@ -43,7 +44,9 @@ Schema:
|
||||
"organization_name": array/string,
|
||||
"organizational_unit_name": array/string,
|
||||
"common_name": string,
|
||||
"email_address": string
|
||||
"email_address": string,
|
||||
"serial_number": string, # [0]
|
||||
"serial_number_str": string
|
||||
},
|
||||
"validity": {
|
||||
"not_before": integer, # [1]
|
||||
@@ -58,7 +61,9 @@ Schema:
|
||||
"organization_name": array/string,
|
||||
"organizational_unit_name": array/string,
|
||||
"common_name": string,
|
||||
"email_address": string
|
||||
"email_address": string,
|
||||
"serial_number": string, # [0]
|
||||
"serial_number_str": string
|
||||
},
|
||||
"subject_public_key_info": {
|
||||
"algorithm": {
|
||||
@@ -428,4 +433,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
||||
@@ -18,8 +18,8 @@ Usage (module):
|
||||
|
||||
Schema:
|
||||
|
||||
YAML Document converted to a Dictionary
|
||||
See https://pypi.org/project/ruamel.yaml for details
|
||||
YAML Document converted to a Dictionary.
|
||||
See https://pypi.org/project/ruamel.yaml for details.
|
||||
|
||||
[
|
||||
{
|
||||
@@ -30,7 +30,7 @@ Schema:
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat istio-mtls-permissive.yaml
|
||||
$ cat file.yaml
|
||||
apiVersion: "authentication.istio.io/v1alpha1"
|
||||
kind: "Policy"
|
||||
metadata:
|
||||
@@ -51,7 +51,7 @@ Examples:
|
||||
tls:
|
||||
mode: ISTIO_MUTUAL
|
||||
|
||||
$ cat istio-mtls-permissive.yaml | jc --yaml -p
|
||||
$ cat file.yaml | jc --yaml -p
|
||||
[
|
||||
{
|
||||
"apiVersion": "authentication.istio.io/v1alpha1",
|
||||
|
||||
@@ -99,4 +99,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin
|
||||
|
||||
Version 1.1 by Matt J (https://github.com/listuser)
|
||||
Version 1.2 by Matt J (https://github.com/listuser)
|
||||
|
||||
62
jc/cli.py
62
jc/cli.py
@@ -9,7 +9,7 @@ from datetime import datetime, timezone
|
||||
import textwrap
|
||||
import shlex
|
||||
import subprocess
|
||||
from typing import List, Union, Optional, TextIO
|
||||
from typing import List, Dict, Union, Optional, TextIO
|
||||
from types import ModuleType
|
||||
from .lib import (
|
||||
__version__, parser_info, all_parser_info, parsers, _get_parser, _parser_is_streaming,
|
||||
@@ -48,7 +48,7 @@ class info():
|
||||
author: str = 'Kelly Brazil'
|
||||
author_email: str = 'kellyjonbrazil@gmail.com'
|
||||
website: str = 'https://github.com/kellyjonbrazil/jc'
|
||||
copyright: str = '© 2019-2022 Kelly Brazil'
|
||||
copyright: str = '© 2019-2023 Kelly Brazil'
|
||||
license: str = 'MIT License'
|
||||
|
||||
|
||||
@@ -64,12 +64,12 @@ if PYGMENTS_INSTALLED:
|
||||
class JcCli():
|
||||
__slots__ = (
|
||||
'data_in', 'data_out', 'options', 'args', 'parser_module', 'parser_name', 'indent', 'pad',
|
||||
'custom_colors', 'show_hidden', 'ascii_only', 'json_separators', 'json_indent',
|
||||
'run_timestamp', 'about', 'debug', 'verbose_debug', 'force_color', 'mono', 'help_me',
|
||||
'pretty', 'quiet', 'ignore_exceptions', 'raw', 'meta_out', 'unbuffer', 'version_info',
|
||||
'yaml_output', 'bash_comp', 'zsh_comp', 'magic_found_parser', 'magic_options',
|
||||
'magic_run_command', 'magic_run_command_str', 'magic_stdout', 'magic_stderr',
|
||||
'magic_returncode'
|
||||
'custom_colors', 'show_hidden', 'show_categories', 'ascii_only', 'json_separators',
|
||||
'json_indent', 'run_timestamp', 'about', 'debug', 'verbose_debug', 'force_color', 'mono',
|
||||
'help_me', 'pretty', 'quiet', 'ignore_exceptions', 'raw', 'meta_out', 'unbuffer',
|
||||
'version_info', 'yaml_output', 'bash_comp', 'zsh_comp', 'magic_found_parser',
|
||||
'magic_options', 'magic_run_command', 'magic_run_command_str', 'magic_stdout',
|
||||
'magic_stderr', 'magic_returncode'
|
||||
)
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -83,6 +83,7 @@ class JcCli():
|
||||
self.pad: int = 0
|
||||
self.custom_colors: CustomColorType = {}
|
||||
self.show_hidden: bool = False
|
||||
self.show_categories: bool = False
|
||||
self.ascii_only: bool = False
|
||||
self.json_separators: Optional[tuple[str, str]] = (',', ':')
|
||||
self.json_indent: Optional[int] = None
|
||||
@@ -198,6 +199,41 @@ class JcCli():
|
||||
|
||||
return ptext
|
||||
|
||||
def parser_categories_text(self) -> str:
|
||||
"""Return lists of parsers by category"""
|
||||
category_text: str = ''
|
||||
padding_char: str = ' '
|
||||
all_parsers = all_parser_info(show_hidden=True, show_deprecated=False)
|
||||
generic = [{'arg': x['argument'], 'desc': x['description']} for x in all_parsers if 'generic' in x['tags']]
|
||||
standard = [{'arg': x['argument'], 'desc': x['description']} for x in all_parsers if 'standard' in x['tags']]
|
||||
command = [{'arg': x['argument'], 'desc': x['description']} for x in all_parsers if 'command' in x['tags']]
|
||||
file_str_bin = [
|
||||
{'arg': x['argument'], 'desc': x['description']} for x in all_parsers
|
||||
if 'file' in x['tags'] or
|
||||
'string' in x['tags'] or
|
||||
'binary' in x['tags']
|
||||
]
|
||||
streaming = [{'arg': x['argument'], 'desc': x['description']} for x in all_parsers if x.get('streaming')]
|
||||
categories: Dict = {
|
||||
'Generic Parsers:': generic,
|
||||
'Standard Spec Parsers:': standard,
|
||||
'File/String/Binary Parsers:': file_str_bin,
|
||||
'Streaming Parsers:': streaming,
|
||||
'Command Parsers:': command
|
||||
}
|
||||
|
||||
for cat, cat_objs in categories.items():
|
||||
category_text += f'{cat} ({len(cat_objs)})\n'
|
||||
for p in cat_objs:
|
||||
parser_arg: str = p.get('arg', 'UNKNOWN')
|
||||
parser_desc: str = p.get('desc', 'No description available.')
|
||||
padding: int = self.pad - len(parser_arg)
|
||||
padding_text: str = padding_char * padding
|
||||
category_text += f'{parser_arg}{padding_text}{parser_desc}\n'
|
||||
category_text += '\n'
|
||||
|
||||
return category_text[:-1]
|
||||
|
||||
def options_text(self) -> str:
|
||||
"""Return the argument and description information from each option"""
|
||||
otext: str = ''
|
||||
@@ -236,8 +272,6 @@ class JcCli():
|
||||
|
||||
def helptext(self) -> str:
|
||||
"""Return the help text with the list of parsers"""
|
||||
self.indent = 4
|
||||
self.pad = 20
|
||||
parsers_string: str = self.parsers_text()
|
||||
options_string: str = self.options_text()
|
||||
helptext_string: str = f'{helptext_preamble_string}{parsers_string}\nOptions:\n{options_string}\n{helptext_end_string}'
|
||||
@@ -248,6 +282,13 @@ class JcCli():
|
||||
Pages the parser documentation if a parser is found in the arguments,
|
||||
otherwise the general help text is printed.
|
||||
"""
|
||||
self.indent = 4
|
||||
self.pad = 22
|
||||
|
||||
if self.show_categories:
|
||||
utils._safe_print(self.parser_categories_text())
|
||||
return
|
||||
|
||||
for arg in self.args:
|
||||
parser_name: str = self.parser_shortname(arg)
|
||||
|
||||
@@ -655,6 +696,7 @@ class JcCli():
|
||||
self.force_color = 'C' in self.options
|
||||
self.help_me = 'h' in self.options
|
||||
self.show_hidden = self.options.count('h') > 1 # verbose help
|
||||
self.show_categories = self.options.count('h') > 2
|
||||
self.pretty = 'p' in self.options
|
||||
self.quiet = 'q' in self.options
|
||||
self.ignore_exceptions = self.options.count('q') > 1
|
||||
|
||||
@@ -3,7 +3,7 @@ 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)'],
|
||||
'--force-color': ['C', 'force color output (overrides -m)'],
|
||||
'--debug': ['d', 'debug (double for verbose debug)'],
|
||||
'--help': ['h', 'help (--help --parser_name for parser documentation)'],
|
||||
'--monochrome': ['m', 'monochrome output'],
|
||||
@@ -91,6 +91,7 @@ Examples:
|
||||
Parser Documentation:
|
||||
$ jc --help --dig
|
||||
|
||||
Show Hidden Parsers:
|
||||
$ jc -hh
|
||||
More Help:
|
||||
$ jc -hh # show hidden parsers
|
||||
$ jc -hhh # list parsers by category tags
|
||||
'''
|
||||
@@ -20,6 +20,7 @@ if sys.version_info >= (3, 8):
|
||||
"author_email": str,
|
||||
"compatible": List[str],
|
||||
"magic_commands": List[str],
|
||||
"tags": List[str],
|
||||
"documentation": str,
|
||||
"streaming": bool,
|
||||
"plugin": bool,
|
||||
|
||||
@@ -9,7 +9,7 @@ from .jc_types import ParserInfoType, JSONDictType
|
||||
from jc import appdirs
|
||||
|
||||
|
||||
__version__ = '1.22.3'
|
||||
__version__ = '1.22.5'
|
||||
|
||||
parsers: List[str] = [
|
||||
'acpi',
|
||||
@@ -59,12 +59,14 @@ parsers: List[str] = [
|
||||
'id',
|
||||
'ifconfig',
|
||||
'ini',
|
||||
'ini-dup',
|
||||
'iostat',
|
||||
'iostat-s',
|
||||
'ip-address',
|
||||
'iptables',
|
||||
'iso-datetime',
|
||||
'iw-scan',
|
||||
'iwconfig',
|
||||
'jar-manifest',
|
||||
'jobs',
|
||||
'jwt',
|
||||
@@ -173,6 +175,7 @@ parsers: List[str] = [
|
||||
'time',
|
||||
'timedatectl',
|
||||
'timestamp',
|
||||
'toml',
|
||||
'top',
|
||||
'top-s',
|
||||
'tracepath',
|
||||
|
||||
@@ -233,6 +233,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['acpi']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -86,6 +86,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['darwin']
|
||||
magic_commands = ['airport -I']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -115,6 +115,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['darwin']
|
||||
magic_commands = ['airport -s']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -119,12 +119,13 @@ import jc.parsers.universal
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.11'
|
||||
version = '1.12'
|
||||
description = '`arp` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'aix', 'freebsd', 'darwin']
|
||||
magic_commands = ['arp']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
@@ -221,14 +222,26 @@ def parse(
|
||||
else:
|
||||
for line in cleandata:
|
||||
splitline = line.split()
|
||||
if '<incomplete>' not in splitline:
|
||||
|
||||
# Ignore AIX bucket information
|
||||
if 'bucket:' in splitline[0]:
|
||||
continue
|
||||
elif 'There' in splitline[0] and 'are' in splitline[1]:
|
||||
continue
|
||||
|
||||
# AIX uses (incomplete)
|
||||
elif '<incomplete>' not in splitline and '(incomplete)' not in splitline:
|
||||
output_line = {
|
||||
'name': splitline[0],
|
||||
'address': splitline[1].lstrip('(').rstrip(')'),
|
||||
'hwtype': splitline[4].lstrip('[').rstrip(']'),
|
||||
'hwaddress': splitline[3],
|
||||
'iface': splitline[6],
|
||||
}
|
||||
# Handle permanence and ignore interface in AIX
|
||||
if 'permanent' in splitline:
|
||||
output_line['permanent'] = True
|
||||
elif 'in' not in splitline[6]: # AIX doesn't show interface
|
||||
output_line['iface'] = splitline[6]
|
||||
|
||||
else:
|
||||
output_line = {
|
||||
@@ -236,8 +249,10 @@ def parse(
|
||||
'address': splitline[1].lstrip('(').rstrip(')'),
|
||||
'hwtype': None,
|
||||
'hwaddress': None,
|
||||
'iface': splitline[5],
|
||||
}
|
||||
# AIX doesn't show interface
|
||||
if len(splitline) >= 5:
|
||||
output_line['iface'] = splitline[5]
|
||||
|
||||
raw_output.append(output_line)
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['generic', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -115,6 +115,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['generic', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -127,6 +127,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['blkid']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -106,6 +106,7 @@ class info():
|
||||
author_email = 'andreas.weiden@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
magic_commands = ['cbt']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -129,6 +129,8 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using the pycef library at https://github.com/DavidJBianco/pycef/releases/tag/v1.11-2'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using the pycef library at https://github.com/DavidJBianco/pycef/releases/tag/v1.11-2'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['chage --list', 'chage -l']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -60,6 +60,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
|
||||
magic_commands = ['cksum', 'sum']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -179,6 +179,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -95,6 +95,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -180,6 +180,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'aix', 'freebsd']
|
||||
magic_commands = ['crontab']
|
||||
tags = ['file', 'command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -176,6 +176,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'aix', 'freebsd']
|
||||
tags = ['file', 'command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -86,6 +86,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using the python standard csv library'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -69,6 +69,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using the python standard csv library'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -84,6 +84,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
magic_commands = ['date']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -75,6 +75,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using the pyiso8601 library from https://github.com/micktwomey/pyiso8601/releases/tag/1.0.2'
|
||||
compatible = ['linux', 'aix', 'freebsd', 'darwin', 'win32', 'cygwin']
|
||||
tags = ['standard', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -105,6 +105,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
magic_commands = ['df']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -328,6 +328,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'aix', 'freebsd', 'darwin', 'win32', 'cygwin']
|
||||
magic_commands = ['dig']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -126,6 +126,7 @@ class info():
|
||||
author = 'Rasheed Elsaleh'
|
||||
author_email = 'rasheed@rebelliondefense.com'
|
||||
compatible = ['win32']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -131,6 +131,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['dmidecode']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -138,6 +138,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['dpkg -l']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -98,6 +98,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'aix', 'freebsd']
|
||||
magic_commands = ['du']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -47,6 +47,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -78,6 +78,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
magic_commands = ['env', 'printenv']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -69,6 +69,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'aix', 'freebsd', 'darwin']
|
||||
magic_commands = ['file']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -93,12 +93,13 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
version = '1.1'
|
||||
description = '`findmnt` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['findmnt']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
@@ -140,7 +141,7 @@ def _process(proc_data: List[JSONDictType]) -> List[JSONDictType]:
|
||||
return proc_data
|
||||
|
||||
|
||||
def _replace(matchobj: re.Match) -> str:
|
||||
def _replace(matchobj):
|
||||
if matchobj:
|
||||
matchlen = len(matchobj.group(1))
|
||||
return ' ' * matchlen + '/'
|
||||
|
||||
@@ -98,6 +98,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'freebsd']
|
||||
magic_commands = ['finger']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -48,6 +48,9 @@ class info():
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
|
||||
# tags options: generic, standard, file, string, binary, command
|
||||
tags = ['command']
|
||||
magic_commands = ['foo']
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,9 @@ class info():
|
||||
|
||||
# compatible options: linux, darwin, cygwin, win32, aix, freebsd
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
|
||||
# tags options: generic, standard, file, string, binary, command
|
||||
tags = ['command']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['free']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -90,6 +90,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'freebsd']
|
||||
tags = ['file']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -159,6 +159,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
magic_commands = ['git log']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -93,6 +93,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['command']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -72,6 +72,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
magic_commands = ['git ls-remote']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -126,6 +126,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['gpg --with-colons']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -114,6 +114,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'aix', 'freebsd']
|
||||
tags = ['file']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -82,6 +82,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'aix', 'freebsd']
|
||||
tags = ['file']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -43,6 +43,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -76,6 +76,7 @@ class info():
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
|
||||
magic_commands = ['md5sum', 'md5', 'shasum', 'sha1sum', 'sha224sum',
|
||||
'sha256sum', 'sha384sum', 'sha512sum']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -323,6 +323,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['hciconfig']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -69,6 +69,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Optimizations by https://github.com/philippeitis'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -79,6 +79,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['file']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -112,6 +112,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'aix', 'freebsd']
|
||||
magic_commands = ['id']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -219,12 +219,13 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '2.1'
|
||||
version = '2.2'
|
||||
description = '`ifconfig` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'aix', 'freebsd', 'darwin']
|
||||
magic_commands = ['ifconfig']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
@@ -326,7 +327,7 @@ def _process(proc_data: List[JSONDictType]) -> List[JSONDictType]:
|
||||
return proc_data
|
||||
|
||||
|
||||
def _bundle_match(pattern_list: List[re.Pattern], string: str) -> Optional[re.Match]:
|
||||
def _bundle_match(pattern_list, string):
|
||||
"""Returns a match object if a string matches one of a list of patterns.
|
||||
If no match is found, returns None"""
|
||||
for pattern in pattern_list:
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
"""jc - JSON Convert `INI` file parser
|
||||
"""jc - JSON Convert INI file parser
|
||||
|
||||
Parses standard `INI` files and files containing simple key/value pairs.
|
||||
Parses standard INI files.
|
||||
|
||||
- Delimiter can be `=` or `:`. Missing values are supported.
|
||||
- Comment prefix can be `#` or `;`. Comments must be on their own line.
|
||||
- If duplicate keys are found, only the last value will be used.
|
||||
- If any section names have the same name as a top-level key, the top-level
|
||||
key will be overwritten by the section data.
|
||||
|
||||
> Note: Values starting and ending with double or single quotation marks
|
||||
> will have the marks removed. If you would like to keep the quotation
|
||||
@@ -22,65 +24,82 @@ Usage (module):
|
||||
|
||||
Schema:
|
||||
|
||||
ini or key/value document converted to a dictionary - see the configparser
|
||||
INI document converted to a dictionary - see the python configparser
|
||||
standard library documentation for more details.
|
||||
|
||||
{
|
||||
"key1": string,
|
||||
"key2": string
|
||||
"<key1>": string,
|
||||
"<key2>": string,
|
||||
"<section1>": {
|
||||
"<key1>": string,
|
||||
"<key2>": string
|
||||
},
|
||||
"<section2>": {
|
||||
"<key1>": string,
|
||||
"<key2>": string
|
||||
}
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat example.ini
|
||||
[DEFAULT]
|
||||
ServerAliveInterval = 45
|
||||
Compression = yes
|
||||
CompressionLevel = 9
|
||||
ForwardX11 = yes
|
||||
foo = fiz
|
||||
bar = buz
|
||||
|
||||
[bitbucket.org]
|
||||
User = hg
|
||||
[section1]
|
||||
fruit = apple
|
||||
color = blue
|
||||
|
||||
[topsecret.server.com]
|
||||
Port = 50022
|
||||
ForwardX11 = no
|
||||
[section2]
|
||||
fruit = pear
|
||||
color = green
|
||||
|
||||
$ cat example.ini | jc --ini -p
|
||||
{
|
||||
"bitbucket.org": {
|
||||
"ServerAliveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "yes",
|
||||
"User": "hg"
|
||||
"foo": "fiz",
|
||||
"bar": "buz",
|
||||
"section1": {
|
||||
"fruit": "apple",
|
||||
"color": "blue"
|
||||
},
|
||||
"topsecret.server.com": {
|
||||
"ServerAliveInterval": "45",
|
||||
"Compression": "yes",
|
||||
"CompressionLevel": "9",
|
||||
"ForwardX11": "no",
|
||||
"Port": "50022"
|
||||
"section2": {
|
||||
"fruit": "pear",
|
||||
"color": "green"
|
||||
}
|
||||
}
|
||||
"""
|
||||
import jc.utils
|
||||
import configparser
|
||||
import uuid
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.8'
|
||||
version = '2.0'
|
||||
description = 'INI file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using configparser from the standard library'
|
||||
details = 'Using configparser from the python standard library'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def _remove_quotes(value):
|
||||
if value is None:
|
||||
value = ''
|
||||
|
||||
elif value.startswith('"') and value.endswith('"'):
|
||||
value = value[1:-1]
|
||||
|
||||
elif value.startswith("'") and value.endswith("'"):
|
||||
value = value[1:-1]
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def _process(proc_data):
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
@@ -91,32 +110,16 @@ def _process(proc_data):
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing an ini or simple key/value pair document.
|
||||
Dictionary representing the INI file.
|
||||
"""
|
||||
# remove quotation marks from beginning and end of values
|
||||
for heading in proc_data:
|
||||
# standard ini files with headers
|
||||
if isinstance(proc_data[heading], dict):
|
||||
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('"')
|
||||
for k, v in proc_data.items():
|
||||
if isinstance(v, dict):
|
||||
for key, value in v.items():
|
||||
v[key] = _remove_quotes(value)
|
||||
continue
|
||||
|
||||
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('"'):
|
||||
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] = ''
|
||||
proc_data[k] = _remove_quotes(v)
|
||||
|
||||
return proc_data
|
||||
|
||||
@@ -133,7 +136,7 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing the ini file
|
||||
Dictionary representing the INI file.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
@@ -142,25 +145,36 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
ini = configparser.ConfigParser(allow_no_value=True,
|
||||
interpolation=None,
|
||||
strict=False)
|
||||
ini_parser = configparser.ConfigParser(
|
||||
allow_no_value=True,
|
||||
interpolation=None,
|
||||
default_section=None,
|
||||
strict=False
|
||||
)
|
||||
|
||||
# don't convert keys to lower-case:
|
||||
ini.optionxform = lambda option: option
|
||||
ini_parser.optionxform = lambda option: option
|
||||
|
||||
try:
|
||||
ini.read_string(data)
|
||||
raw_output = {s: dict(ini.items(s)) for s in ini.sections()}
|
||||
ini_parser.read_string(data)
|
||||
raw_output = {s: dict(ini_parser.items(s)) for s in ini_parser.sections()}
|
||||
|
||||
except configparser.MissingSectionHeaderError:
|
||||
data = '[data]\n' + data
|
||||
ini.read_string(data)
|
||||
output_dict = {s: dict(ini.items(s)) for s in ini.sections()}
|
||||
for key, value in output_dict['data'].items():
|
||||
raw_output[key] = value
|
||||
# find a top-level section name that will not collide with any existing ones
|
||||
while True:
|
||||
my_uuid = str(uuid.uuid4())
|
||||
if my_uuid not in data:
|
||||
break
|
||||
|
||||
data = f'[{my_uuid}]\n' + data
|
||||
ini_parser.read_string(data)
|
||||
temp_dict = {s: dict(ini_parser.items(s)) for s in ini_parser.sections()}
|
||||
|
||||
# move items under fake top-level sections to the root
|
||||
raw_output = temp_dict.pop(my_uuid)
|
||||
|
||||
# get the rest of the sections
|
||||
raw_output.update(temp_dict)
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
|
||||
if raw:
|
||||
return raw_output
|
||||
else:
|
||||
return _process(raw_output)
|
||||
|
||||
225
jc/parsers/ini_dup.py
Normal file
225
jc/parsers/ini_dup.py
Normal file
@@ -0,0 +1,225 @@
|
||||
"""jc - JSON Convert INI with duplicate key file parser
|
||||
|
||||
Parses standard INI files and preserves duplicate values. All values are
|
||||
contained in lists/arrays.
|
||||
|
||||
- Delimiter can be `=` or `:`. Missing values are supported.
|
||||
- Comment prefix can be `#` or `;`. Comments must be on their own line.
|
||||
- If any section names have the same name as a top-level key, the top-level
|
||||
key will be overwritten by the section data.
|
||||
- If multi-line values are used, each line will be a separate item in the
|
||||
value list. Blank lines in multi-line values are not supported.
|
||||
|
||||
> 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):
|
||||
|
||||
$ cat foo.ini | jc --ini
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('ini', ini_file_output)
|
||||
|
||||
Schema:
|
||||
|
||||
INI document converted to a dictionary - see the python configparser
|
||||
standard library documentation for more details.
|
||||
|
||||
{
|
||||
"<key1>": [
|
||||
string
|
||||
],
|
||||
"<key2>": [
|
||||
string
|
||||
],
|
||||
"<section1>": {
|
||||
"<key1>": [
|
||||
string
|
||||
],
|
||||
"<key2>": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ cat example.ini
|
||||
foo = fiz
|
||||
bar = buz
|
||||
|
||||
[section1]
|
||||
fruit = apple
|
||||
color = blue
|
||||
color = red
|
||||
|
||||
[section2]
|
||||
fruit = pear
|
||||
fruit = peach
|
||||
color = green
|
||||
|
||||
$ cat example.ini | jc --ini -p
|
||||
{
|
||||
"foo": [
|
||||
"fiz"
|
||||
],
|
||||
"bar": [
|
||||
"buz"
|
||||
],
|
||||
"section1": {
|
||||
"fruit": [
|
||||
"apple"
|
||||
],
|
||||
"color": [
|
||||
"blue",
|
||||
"red"
|
||||
]
|
||||
},
|
||||
"section2": {
|
||||
"fruit": [
|
||||
"pear",
|
||||
"peach"
|
||||
],
|
||||
"color": [
|
||||
"green"
|
||||
]
|
||||
}
|
||||
}
|
||||
"""
|
||||
import jc.utils
|
||||
import configparser
|
||||
import uuid
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = 'INI with duplicate key file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Using configparser from the python standard library'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'file', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
class MultiDict(dict):
|
||||
# https://stackoverflow.com/a/38286559/12303989
|
||||
def __setitem__(self, key, value):
|
||||
if key in self:
|
||||
if isinstance(value, list):
|
||||
self[key].extend(value)
|
||||
|
||||
elif isinstance(value, str):
|
||||
if len(self[key])>1:
|
||||
return
|
||||
|
||||
else:
|
||||
super().__setitem__(key, value)
|
||||
|
||||
|
||||
def _remove_quotes(value):
|
||||
if value is None:
|
||||
value = ''
|
||||
|
||||
elif value.startswith('"') and value.endswith('"'):
|
||||
value = value[1:-1]
|
||||
|
||||
elif value.startswith("'") and value.endswith("'"):
|
||||
value = value[1:-1]
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def _process(proc_data):
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (Dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing the INI file.
|
||||
"""
|
||||
# remove quotation marks from beginning and end of values
|
||||
for k, v in proc_data.items():
|
||||
if isinstance(v, dict):
|
||||
for key, value in v.items():
|
||||
if isinstance(value, list):
|
||||
v[key] = [_remove_quotes(x) for x in value]
|
||||
else:
|
||||
v[key] = _remove_quotes(value)
|
||||
continue
|
||||
|
||||
elif isinstance(v, list):
|
||||
proc_data[k] = [_remove_quotes(x) for x in v]
|
||||
|
||||
else:
|
||||
proc_data[k] = _remove_quotes(v)
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
def parse(data, raw=False, quiet=False):
|
||||
"""
|
||||
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:
|
||||
|
||||
Dictionary representing the INI file.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output = {}
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
ini_parser = configparser.ConfigParser(
|
||||
dict_type = MultiDict,
|
||||
allow_no_value=True,
|
||||
interpolation=None,
|
||||
default_section=None,
|
||||
empty_lines_in_values=False,
|
||||
strict=False
|
||||
)
|
||||
|
||||
# don't convert keys to lower-case:
|
||||
ini_parser.optionxform = lambda option: option
|
||||
|
||||
try:
|
||||
ini_parser.read_string(data)
|
||||
raw_output = {s: dict(ini_parser.items(s)) for s in ini_parser.sections()}
|
||||
|
||||
except configparser.MissingSectionHeaderError:
|
||||
# find a top-level section name that will not collide with any existing ones
|
||||
while True:
|
||||
my_uuid = str(uuid.uuid4())
|
||||
if my_uuid not in data:
|
||||
break
|
||||
|
||||
data = f'[{my_uuid}]\n' + data
|
||||
ini_parser.read_string(data)
|
||||
temp_dict = {s: dict(ini_parser.items(s)) for s in ini_parser.sections()}
|
||||
|
||||
# move items under fake top-level sections to the root
|
||||
raw_output = temp_dict.pop(my_uuid)
|
||||
|
||||
# get the rest of the sections
|
||||
raw_output.update(temp_dict)
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
@@ -166,6 +166,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['iostat']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -113,6 +113,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
tags = ['command']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -538,6 +538,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -169,6 +169,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['iptables']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -17,6 +17,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'Deprecated - please use datetime-iso'
|
||||
compatible = ['linux', 'aix', 'freebsd', 'darwin', 'win32', 'cygwin']
|
||||
tags = ['standard', 'string']
|
||||
deprecated = True
|
||||
|
||||
|
||||
|
||||
@@ -129,6 +129,7 @@ class info():
|
||||
details = 'Enhancements by Philipp Schmitt (https://pschmitt.dev/)'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['iw dev']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
202
jc/parsers/iwconfig.py
Normal file
202
jc/parsers/iwconfig.py
Normal file
@@ -0,0 +1,202 @@
|
||||
"""jc - JSON Convert `iwconfig` command output parser
|
||||
|
||||
No `iwconfig` options are supported.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ iwconfig | jc --iwconfig
|
||||
|
||||
or
|
||||
|
||||
$ jc iwconfig
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('iwconfig', iwconfig_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"name": string,
|
||||
"protocol": string,
|
||||
"essid": string,
|
||||
"mode": string,
|
||||
"frequency": float,
|
||||
"frequency_unit": string,
|
||||
"access_point": string,
|
||||
"bit_rate": float,
|
||||
"bit_rate_unit": string,
|
||||
"tx_power": integer,
|
||||
"tx_power_unit": string,
|
||||
"retry_short_limit": integer,
|
||||
"rts_threshold": boolean,
|
||||
"fragment_threshold": boolean,
|
||||
"power_management": boolean,
|
||||
"link_quality": string,
|
||||
"signal_level": integer,
|
||||
"signal_level_unit": string,
|
||||
"rx_invalid_nwid": integer,
|
||||
"rx_invalid_crypt": integer,
|
||||
"rx_invalid_frag": integer,
|
||||
"tx_excessive_retries": integer,
|
||||
"invalid_misc": integer,
|
||||
"missed_beacon": integer
|
||||
}
|
||||
]
|
||||
|
||||
Examples:
|
||||
|
||||
$ iwconfig | jc --iwconfig -p
|
||||
[
|
||||
{
|
||||
"name": "wlp5s0",
|
||||
"protocol": "IEEE 802.11",
|
||||
"essid": "BLABLABLA",
|
||||
"mode": "Managed",
|
||||
"frequency": 5.18,
|
||||
"frequency_unit": "GHz",
|
||||
"access_point": "E6:64:DA:16:51:BF",
|
||||
"bit_rate": 6.0,
|
||||
"bit_rate_unit": "Mb/s",
|
||||
"tx_power": 30,
|
||||
"tx_power_unit": "dBm",
|
||||
"retry_short_limit": 7,
|
||||
"rts_threshold": false,
|
||||
"fragment_threshold": false,
|
||||
"power_management": true,
|
||||
"link_quality": "61/70",
|
||||
"signal_level": -49,
|
||||
"signal_level_unit": "dBm",
|
||||
"rx_invalid_nwid": 0,
|
||||
"rx_invalid_crypt": 0,
|
||||
"rx_invalid_frag": 0,
|
||||
"tx_excessive_retries": 0,
|
||||
"invalid_misc": 2095,
|
||||
"missed_beacon": 0
|
||||
}
|
||||
]
|
||||
"""
|
||||
import re
|
||||
from typing import List, Dict
|
||||
from jc.jc_types import JSONDictType
|
||||
import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`iwconfig` command parser'
|
||||
author = 'Thomas Vincent'
|
||||
author_email = 'vrince@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['iwconfig']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def _process(proc_data: List[JSONDictType]) -> List[JSONDictType]:
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
int_list = [
|
||||
'signal_level', 'rx_invalid_nwid', 'rx_invalid_crypt', 'rx_invalid_frag',
|
||||
'tx_excessive_retries', 'invalid_misc', 'missed_beacon', 'tx_power', 'retry_short_limit'
|
||||
]
|
||||
float_list = ['frequency', 'bit_rate']
|
||||
bool_list = ['rts_threshold', 'fragment_threshold', 'power_management']
|
||||
|
||||
proc_data = [ { key: int(value) if key in int_list else value for key, value in proc_data_item.items() } for proc_data_item in proc_data ]
|
||||
proc_data = [ { key: float(value) if key in float_list else value for key, value in proc_data_item.items() } for proc_data_item in proc_data ]
|
||||
proc_data = [ { key: value == 'on' if key in bool_list else value for key, value in proc_data_item .items() } for proc_data_item in proc_data ]
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
def parse(
|
||||
data: str,
|
||||
raw: bool = False,
|
||||
quiet: bool = False
|
||||
) -> List[JSONDictType]:
|
||||
"""
|
||||
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[Dict] = []
|
||||
|
||||
re_interface = re.compile(r'^(?P<name>[a-zA-Z0-9:._-]+)\s+(?P<protocol>([a-zA-Z0-9]+\s)*[a-zA-Z0-9.]+)\s+ESSID:\"(?P<essid>[a-zA-Z0-9:._\s]+)\"')
|
||||
re_mode = re.compile(r'Mode:(?P<mode>\w+)')
|
||||
re_frequency = re.compile(r'Frequency:(?P<frequency>[0-9.]+)\s(?P<frequency_unit>\w+)')
|
||||
re_access_point = re.compile(r'Access Point:\s*(?P<access_point>[0-9A-F:]+)')
|
||||
re_bit_rate = re.compile(r'Bit Rate=(?P<bit_rate>[0-9.]+)\s(?P<bit_rate_unit>[\w\/]+)')
|
||||
re_tx_power= re.compile(r'Tx-Power=(?P<tx_power>[-0-9]+)\s(?P<tx_power_unit>[\w]+)')
|
||||
re_retry_short_limit = re.compile(r'Retry short limit:(?P<retry_short_limit>[0-9\/]+)')
|
||||
re_rts_threshold = re.compile(r'RTS thr:(?P<rts_threshold>(off|on))')
|
||||
re_fragment_threshold = re.compile(r'Fragment thr:(?P<fragment_threshold>(off|on))')
|
||||
re_power_management = re.compile(r'Power Management:(?P<power_management>(off|on))')
|
||||
re_link_quality = re.compile(r'Link Quality=(?P<link_quality>[0-9\/]+)')
|
||||
re_signal_level = re.compile(r'Signal level=(?P<signal_level>[-0-9]+)\s(?P<signal_level_unit>[\w]+)')
|
||||
re_rx_invalid_nwid = re.compile(r'Rx invalid nwid:(?P<rx_invalid_nwid>[-0-9]+)')
|
||||
re_rx_invalid_crypt = re.compile(r'Rx invalid crypt:(?P<rx_invalid_crypt>[-0-9]+)')
|
||||
re_rx_invalid_frag = re.compile(r'Rx invalid frag:(?P<rx_invalid_frag>[-0-9]+)')
|
||||
re_tx_excessive_retries = re.compile(r'Tx excessive retries:(?P<tx_excessive_retries>[-0-9]+)')
|
||||
re_invalid_misc = re.compile(r'Invalid misc:(?P<invalid_misc>[0-9]+)')
|
||||
re_missed_beacon = re.compile(r'Missed beacon:(?P<missed_beacon>[0-9]+)')
|
||||
|
||||
re_all = [
|
||||
re_mode, re_frequency, re_access_point, re_bit_rate, re_tx_power,
|
||||
re_retry_short_limit, re_rts_threshold, re_fragment_threshold, re_power_management,
|
||||
re_link_quality, re_signal_level, re_rx_invalid_nwid, re_rx_invalid_crypt,
|
||||
re_rx_invalid_frag, re_tx_excessive_retries, re_invalid_misc, re_missed_beacon
|
||||
]
|
||||
|
||||
interface_item = None
|
||||
if jc.utils.has_data(data):
|
||||
for line in filter(None, data.splitlines()):
|
||||
|
||||
# Find new interface lines
|
||||
interface_match = re.search(re_interface, line)
|
||||
if interface_match:
|
||||
if interface_item is not None:
|
||||
raw_output.append(interface_item)
|
||||
|
||||
interface_item = dict()
|
||||
interface_item.update(interface_match.groupdict())
|
||||
continue
|
||||
|
||||
# we do not have any interface yet continue to search for it --> next line
|
||||
if interface_item is None:
|
||||
continue
|
||||
|
||||
# Filling interface with whatever we can find
|
||||
for re_entry in re_all:
|
||||
match = re.search(re_entry, line)
|
||||
if match:
|
||||
interface_item.update(match.groupdict())
|
||||
|
||||
if interface_item is not None:
|
||||
raw_output.append(interface_item)
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
@@ -83,6 +83,7 @@ class info():
|
||||
author = 'Matt J'
|
||||
author_email = 'https://github.com/listuser'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['file']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -99,6 +99,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
|
||||
magic_commands = ['jobs']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -56,6 +56,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['standard', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""jc - JSON Convert `Key/Value` file parser
|
||||
"""jc - JSON Convert `Key/Value` file and string parser
|
||||
|
||||
Supports files containing simple key/value pairs.
|
||||
|
||||
@@ -21,8 +21,8 @@ Usage (module):
|
||||
|
||||
Schema:
|
||||
|
||||
key/value document converted to a dictionary - see the configparser standard
|
||||
library documentation for more details.
|
||||
Key/Value document converted to a dictionary - see the python configparser
|
||||
standard library documentation for more details.
|
||||
|
||||
{
|
||||
"key1": string,
|
||||
@@ -36,6 +36,7 @@ Examples:
|
||||
name = John Doe
|
||||
address=555 California Drive
|
||||
age: 34
|
||||
|
||||
; comments can include # or ;
|
||||
# delimiter can be = or :
|
||||
# quoted values have quotation marks stripped by default
|
||||
@@ -50,27 +51,54 @@ Examples:
|
||||
"occupation": "Engineer"
|
||||
}
|
||||
"""
|
||||
import jc.utils
|
||||
import configparser
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.2'
|
||||
description = 'Key/Value file parser'
|
||||
version = '2.0'
|
||||
description = 'Key/Value file and string parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
details = 'This is a wrapper for the INI parser'
|
||||
details = 'Using configparser from the python standard library'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['generic', 'file', 'string']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def _process(proc_data):
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (Dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing a Key/Value pair document.
|
||||
"""
|
||||
# remove quotation marks from beginning and end of values
|
||||
for key in proc_data:
|
||||
if proc_data[key] is None:
|
||||
proc_data[key] = ''
|
||||
|
||||
elif proc_data[key].startswith('"') and proc_data[key].endswith('"'):
|
||||
proc_data[key] = proc_data[key][1:-1]
|
||||
|
||||
elif proc_data[key].startswith("'") and proc_data[key].endswith("'"):
|
||||
proc_data[key] = proc_data[key][1:-1]
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
def parse(data, raw=False, quiet=False):
|
||||
"""
|
||||
Main text parsing function
|
||||
|
||||
Note: this is just a wrapper for jc.parsers.ini
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
@@ -79,7 +107,30 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary representing the key/value file
|
||||
Dictionary representing a Key/Value pair document.
|
||||
"""
|
||||
import jc.parsers.ini
|
||||
return jc.parsers.ini.parse(data, raw=raw, quiet=quiet)
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output = {}
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
kv_parser = configparser.ConfigParser(
|
||||
allow_no_value=True,
|
||||
interpolation=None,
|
||||
default_section=None,
|
||||
strict=False
|
||||
)
|
||||
|
||||
# don't convert keys to lower-case:
|
||||
kv_parser.optionxform = lambda option: option
|
||||
|
||||
data = '[data]\n' + data
|
||||
kv_parser.read_string(data)
|
||||
output_dict = {s: dict(kv_parser.items(s)) for s in kv_parser.sections()}
|
||||
for key, value in output_dict['data'].items():
|
||||
raw_output[key] = value
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ class info():
|
||||
details = 'Enhancements by https://github.com/zerolagtime'
|
||||
compatible = ['linux', 'darwin', 'aix', 'freebsd']
|
||||
magic_commands = ['last', 'lastb']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -124,6 +124,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
|
||||
magic_commands = ['ls', 'vdir']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -82,6 +82,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'aix', 'freebsd']
|
||||
tags = ['command']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -281,6 +281,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['lsblk']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -132,6 +132,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['lsmod']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -126,6 +126,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'aix', 'freebsd']
|
||||
magic_commands = ['lsof']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -129,6 +129,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['lspci']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -97,6 +97,28 @@ Schema:
|
||||
]
|
||||
}
|
||||
},
|
||||
"videocontrol_descriptors": [
|
||||
{
|
||||
"<item>": {
|
||||
"value": string,
|
||||
"description": string,
|
||||
"attributes": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"videostreaming_descriptors": [
|
||||
{
|
||||
"<item>": {
|
||||
"value": string,
|
||||
"description": string,
|
||||
"attributes": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"endpoint_descriptors": [
|
||||
{
|
||||
"<item>": {
|
||||
@@ -269,12 +291,13 @@ from jc.exceptions import ParseError
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.2'
|
||||
version = '1.3'
|
||||
description = '`lsusb` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['lsusb']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
@@ -306,6 +329,145 @@ class _NestedDict(dict):
|
||||
return self.setdefault(key, _NestedDict())
|
||||
|
||||
|
||||
class _root_obj:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.list = []
|
||||
|
||||
def _entries_for_this_bus_exist(self, bus_idx):
|
||||
"""Returns true if there are object entries for the corresponding bus index"""
|
||||
for item in self.list:
|
||||
keyname = tuple(item.keys())[0]
|
||||
|
||||
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _update_output(self, bus_idx, output_line):
|
||||
"""modifies output_line dictionary for the corresponding bus index.
|
||||
output_line is the self.output_line attribute from the _lsusb object."""
|
||||
for item in self.list:
|
||||
keyname = tuple(item.keys())[0]
|
||||
|
||||
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx:
|
||||
# is this a top level value or an attribute?
|
||||
if item[keyname]['_state']['attribute_value']:
|
||||
last_item = item[keyname]['_state']['last_item']
|
||||
if 'attributes' not in output_line[f'{self.name}'][last_item]:
|
||||
output_line[f'{self.name}'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {item[keyname].get("value", "")} {item[keyname].get("description", "")}'.strip()
|
||||
output_line[f'{self.name}'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
output_line[f'{self.name}'].update(item)
|
||||
del output_line[f'{self.name}'][keyname]['_state']
|
||||
|
||||
|
||||
class _descriptor_obj:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.list = []
|
||||
|
||||
def _entries_for_this_bus_and_interface_idx_exist(self, bus_idx, iface_idx):
|
||||
"""Returns true if there are object entries for the corresponding bus index
|
||||
and interface index"""
|
||||
for item in self.list:
|
||||
keyname = tuple(item.keys())[0]
|
||||
|
||||
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx \
|
||||
and item[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _update_output(self, bus_idx, iface_idx, output_line):
|
||||
"""modifies output_line dictionary for the corresponding bus index and
|
||||
interface index. output_line is the i_desc_obj object."""
|
||||
for item in self.list:
|
||||
keyname = tuple(item.keys())[0]
|
||||
|
||||
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx \
|
||||
and item[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if item[keyname]['_state']['attribute_value']:
|
||||
last_item = item[keyname]['_state']['last_item']
|
||||
if 'attributes' not in output_line[f'{self.name}'][last_item]:
|
||||
output_line[f'{self.name}'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {item[keyname].get("value", "")} {item[keyname].get("description", "")}'.strip()
|
||||
output_line[f'{self.name}'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
output_line[f'{self.name}'].update(item)
|
||||
del output_line[f'{self.name}'][keyname]['_state']
|
||||
|
||||
|
||||
class _descriptor_list:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.list = []
|
||||
|
||||
def _entries_for_this_bus_and_interface_idx_exist(self, bus_idx, iface_idx):
|
||||
"""Returns true if there are object entries for the corresponding bus index
|
||||
and interface index"""
|
||||
for item in self.list:
|
||||
keyname = tuple(item.keys())[0]
|
||||
|
||||
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx \
|
||||
and item[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _get_objects_list(self, bus_idx, iface_idx):
|
||||
"""Returns a list of descriptor object dictionaries for the corresponding
|
||||
bus index and interface index"""
|
||||
object_collection = []
|
||||
|
||||
# find max number of items in this object that match the bus_idx and iface_idx
|
||||
num_of_items = -1
|
||||
for item in self.list:
|
||||
keyname = tuple(item.keys())[0]
|
||||
|
||||
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx \
|
||||
and item[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
num_of_items = item[keyname]['_state'][f'{self.name}_idx']
|
||||
|
||||
# create and return the collection of objects that match the bus_idx and iface_idx
|
||||
if num_of_items > -1:
|
||||
for obj_idx in range(num_of_items + 1):
|
||||
this_object = {}
|
||||
for item in self.list:
|
||||
keyname = tuple(item.keys())[0]
|
||||
|
||||
if '_state' in item[keyname] and item[keyname]['_state']['bus_idx'] == bus_idx \
|
||||
and item[keyname]['_state']['interface_descriptor_idx'] == iface_idx \
|
||||
and item[keyname]['_state'][f'{self.name}_idx'] == obj_idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if item[keyname]['_state']['attribute_value']:
|
||||
last_item = item[keyname]['_state']['last_item']
|
||||
if 'attributes' not in this_object[last_item]:
|
||||
this_object[last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {item[keyname].get("value", "")} {item[keyname].get("description", "")}'.strip()
|
||||
this_object[last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
this_object.update(item)
|
||||
del item[keyname]['_state']
|
||||
|
||||
object_collection.append(this_object)
|
||||
|
||||
return object_collection
|
||||
|
||||
|
||||
class _LsUsb():
|
||||
def __init__(self):
|
||||
self.raw_output = []
|
||||
@@ -313,27 +475,37 @@ class _LsUsb():
|
||||
|
||||
self.section = ''
|
||||
self.old_section = ''
|
||||
|
||||
# section_header is formatted with the correct spacing to be used with
|
||||
# jc.parsers.universal.sparse_table_parse(). Pad end of string to be at least len of 25
|
||||
# this value changes for different sections (e.g. videocontrol & videostreaming)
|
||||
self.normal_section_header = 'key val description'
|
||||
self.larger_section_header = 'key val description'
|
||||
|
||||
self.bus_idx = -1
|
||||
self.interface_descriptor_idx = -1
|
||||
self.endpoint_descriptor_idx = -1
|
||||
self.videocontrol_interface_descriptor_idx = -1
|
||||
self.videostreaming_interface_descriptor_idx = -1
|
||||
self.last_item = ''
|
||||
self.last_indent = 0
|
||||
self.attribute_value = False
|
||||
|
||||
self.bus_list = []
|
||||
self.device_descriptor_list = []
|
||||
self.configuration_descriptor_list = []
|
||||
self.interface_association_list = []
|
||||
self.device_descriptor = _root_obj('device_descriptor')
|
||||
self.configuration_descriptor = _root_obj('configuration_descriptor')
|
||||
self.interface_association = _root_obj('interface_association')
|
||||
self.interface_descriptor_list = []
|
||||
self.interface_descriptor_attribute_list = []
|
||||
self.cdc_header_list = []
|
||||
self.cdc_call_management_list = []
|
||||
self.cdc_acm_list = []
|
||||
self.cdc_union_list = []
|
||||
self.endpoint_descriptor_list = []
|
||||
self.hid_device_descriptor_list = []
|
||||
self.report_descriptors_list = []
|
||||
self.hub_descriptor_list = []
|
||||
self.cdc_header = _descriptor_obj('cdc_header')
|
||||
self.cdc_call_management = _descriptor_obj('cdc_call_management')
|
||||
self.cdc_acm = _descriptor_obj('cdc_acm')
|
||||
self.cdc_union = _descriptor_obj('cdc_union')
|
||||
self.endpoint_descriptors = _descriptor_list('endpoint_descriptor')
|
||||
self.videocontrol_interface_descriptors = _descriptor_list('videocontrol_interface_descriptor')
|
||||
self.videostreaming_interface_descriptors = _descriptor_list('videostreaming_interface_descriptor')
|
||||
self.hid_device_descriptor = _descriptor_obj('hid_device_descriptor')
|
||||
# self.report_descriptors_list = [] # not implemented
|
||||
self.hub_descriptor = _root_obj('hub_descriptor')
|
||||
self.hub_port_status_list = []
|
||||
self.device_qualifier_list = []
|
||||
self.device_status_list = []
|
||||
@@ -354,14 +526,21 @@ class _LsUsb():
|
||||
# determine whether this is a top-level value item or lower-level attribute
|
||||
if indent > self.last_indent and self.old_section == self.section:
|
||||
self.attribute_value = True
|
||||
elif indent == self.last_indent and self.attribute_value and self.old_section == self.section:
|
||||
|
||||
elif indent == self.last_indent and self.attribute_value \
|
||||
and self.old_section == self.section:
|
||||
|
||||
self.attribute_value = True
|
||||
|
||||
else:
|
||||
self.attribute_value = False
|
||||
|
||||
# section_header is formatted with the correct spacing to be used with
|
||||
# jc.parsers.universal.sparse_table_parse(). Pad end of string to be at least len of 25
|
||||
section_header = 'key val description'
|
||||
section_header = self.normal_section_header
|
||||
|
||||
if self.section == 'videocontrol_interface_descriptor' \
|
||||
or self.section == 'videostreaming_interface_descriptor':
|
||||
|
||||
section_header = self.larger_section_header
|
||||
|
||||
temp_obj = [section_header, line.strip() + (' ' * 25)]
|
||||
temp_obj = sparse_table_parse(temp_obj)
|
||||
@@ -376,7 +555,9 @@ class _LsUsb():
|
||||
'last_item': self.last_item,
|
||||
'bus_idx': self.bus_idx,
|
||||
'interface_descriptor_idx': self.interface_descriptor_idx,
|
||||
'endpoint_descriptor_idx': self.endpoint_descriptor_idx
|
||||
'endpoint_descriptor_idx': self.endpoint_descriptor_idx,
|
||||
'videocontrol_interface_descriptor_idx': self.videocontrol_interface_descriptor_idx,
|
||||
'videostreaming_interface_descriptor_idx': self.videostreaming_interface_descriptor_idx
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,12 +609,15 @@ class _LsUsb():
|
||||
self.attribute_value = False
|
||||
return True
|
||||
|
||||
# bus information is on the same line so need to extract data immediately and set indexes
|
||||
# bus information is on the same line so need to extract data
|
||||
# immediately and set indexes
|
||||
if line.startswith('Bus '):
|
||||
self.section = 'bus'
|
||||
self.bus_idx += 1
|
||||
self.interface_descriptor_idx = -1
|
||||
self.endpoint_descriptor_idx = -1
|
||||
self.videocontrol_interface_descriptor_idx = -1
|
||||
self.videostreaming_interface_descriptor_idx = -1
|
||||
self.attribute_value = False
|
||||
line_split = line.strip().split(maxsplit=6)
|
||||
self.bus_list.append(
|
||||
@@ -441,7 +625,8 @@ class _LsUsb():
|
||||
'bus': line_split[1],
|
||||
'device': line_split[3][:-1],
|
||||
'id': line_split[5],
|
||||
'description': (line_split[6:7] or [None])[0], # way to get a list item or None
|
||||
# way to get a list item or None
|
||||
'description': (line_split[6:7] or [None])[0],
|
||||
'_state': {
|
||||
'bus_idx': self.bus_idx
|
||||
}
|
||||
@@ -449,22 +634,36 @@ class _LsUsb():
|
||||
)
|
||||
return True
|
||||
|
||||
# This section is a list, so need to update indexes
|
||||
# These sections are lists, so need to update indexes
|
||||
if line.startswith(' Interface Descriptor:'):
|
||||
self.section = 'interface_descriptor'
|
||||
self.interface_descriptor_idx += 1
|
||||
self.endpoint_descriptor_idx = -1
|
||||
self.videocontrol_interface_descriptor_idx = -1
|
||||
self.videostreaming_interface_descriptor_idx = -1
|
||||
self.attribute_value = False
|
||||
return True
|
||||
|
||||
# This section is a list, so need to update the index
|
||||
if line.startswith(' Endpoint Descriptor:'):
|
||||
self.section = 'endpoint_descriptor'
|
||||
self.endpoint_descriptor_idx += 1
|
||||
self.attribute_value = False
|
||||
return True
|
||||
|
||||
# some device status information is displayed on the initial line so need to extract immediately
|
||||
if line.startswith(' VideoControl Interface Descriptor:'):
|
||||
self.section = 'videocontrol_interface_descriptor'
|
||||
self.videocontrol_interface_descriptor_idx += 1
|
||||
self.attribute_value = False
|
||||
return True
|
||||
|
||||
if line.startswith(' VideoStreaming Interface Descriptor:'):
|
||||
self.section = 'videostreaming_interface_descriptor'
|
||||
self.videostreaming_interface_descriptor_idx += 1
|
||||
self.attribute_value = False
|
||||
return True
|
||||
|
||||
# some device status information is displayed on the initial line so
|
||||
# need to extract immediately
|
||||
if line.startswith('Device Status:'):
|
||||
self.section = 'device_status'
|
||||
self.attribute_value = False
|
||||
@@ -506,18 +705,20 @@ class _LsUsb():
|
||||
|
||||
def _populate_lists(self, line):
|
||||
section_list_map = {
|
||||
'device_descriptor': self.device_descriptor_list,
|
||||
'configuration_descriptor': self.configuration_descriptor_list,
|
||||
'interface_association': self.interface_association_list,
|
||||
'device_descriptor': self.device_descriptor.list,
|
||||
'configuration_descriptor': self.configuration_descriptor.list,
|
||||
'interface_association': self.interface_association.list,
|
||||
'interface_descriptor': self.interface_descriptor_list,
|
||||
'cdc_header': self.cdc_header_list,
|
||||
'cdc_call_management': self.cdc_call_management_list,
|
||||
'cdc_acm': self.cdc_acm_list,
|
||||
'cdc_union': self.cdc_union_list,
|
||||
'hid_device_descriptor': self.hid_device_descriptor_list,
|
||||
'report_descriptors': self.report_descriptors_list,
|
||||
'endpoint_descriptor': self.endpoint_descriptor_list,
|
||||
'hub_descriptor': self.hub_descriptor_list,
|
||||
'cdc_header': self.cdc_header.list,
|
||||
'cdc_call_management': self.cdc_call_management.list,
|
||||
'cdc_acm': self.cdc_acm.list,
|
||||
'cdc_union': self.cdc_union.list,
|
||||
'hid_device_descriptor': self.hid_device_descriptor.list,
|
||||
# 'report_descriptors': self.report_descriptors_list, # not implemented
|
||||
'videocontrol_interface_descriptor': self.videocontrol_interface_descriptors.list,
|
||||
'videostreaming_interface_descriptor': self.videostreaming_interface_descriptors.list,
|
||||
'endpoint_descriptor': self.endpoint_descriptors.list,
|
||||
'hub_descriptor': self.hub_descriptor.list,
|
||||
'device_qualifier': self.device_qualifier_list
|
||||
}
|
||||
|
||||
@@ -527,7 +728,9 @@ class _LsUsb():
|
||||
return True
|
||||
|
||||
# special handling of these sections
|
||||
if line.startswith(' ') and self.section == 'hub_port_status':
|
||||
if line.startswith(' ') and not line.startswith(' ') \
|
||||
and self.section == 'hub_port_status':
|
||||
|
||||
self.hub_port_status_list.append(self._add_hub_port_status_attributes(line))
|
||||
return True
|
||||
|
||||
@@ -546,6 +749,10 @@ class _LsUsb():
|
||||
['device_descriptor']['configuration_descriptor']['interface_association'] = {}
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'] = []
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0] = {}
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0]['videocontrol_interface_descriptors'] = []
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0]['videocontrol_interface_descriptors'][0] = {}
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0]['videostreaming_interface_descriptors'] = []
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0]['videostreaming_interface_descriptors'][0] = {}
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0]['cdc_header'] = {}
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0]['cdc_call_management'] = {}
|
||||
['device_descriptor']['configuration_descriptor']['interface_descriptors'][0]['cdc_acm'] = {}
|
||||
@@ -567,81 +774,56 @@ class _LsUsb():
|
||||
del item['_state']
|
||||
self.output_line.update(item)
|
||||
|
||||
for dd in self.device_descriptor_list:
|
||||
keyname = tuple(dd.keys())[0]
|
||||
if '_state' in dd[keyname] and dd[keyname]['_state']['bus_idx'] == idx:
|
||||
# add initial root-level keys
|
||||
if self.device_descriptor._entries_for_this_bus_exist(idx):
|
||||
self.device_descriptor._update_output(idx, self.output_line)
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if dd[keyname]['_state']['attribute_value']:
|
||||
last_item = dd[keyname]['_state']['last_item']
|
||||
if 'attributes' not in self.output_line['device_descriptor'][last_item]:
|
||||
self.output_line['device_descriptor'][last_item]['attributes'] = []
|
||||
if self.configuration_descriptor._entries_for_this_bus_exist(idx):
|
||||
self.configuration_descriptor._update_output(
|
||||
idx, self.output_line['device_descriptor']
|
||||
)
|
||||
|
||||
this_attribute = f'{keyname} {dd[keyname].get("value", "")} {dd[keyname].get("description", "")}'.strip()
|
||||
self.output_line['device_descriptor'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
if self.interface_association._entries_for_this_bus_exist(idx):
|
||||
self.interface_association._update_output(
|
||||
idx, self.output_line['device_descriptor']['configuration_descriptor']
|
||||
)
|
||||
|
||||
self.output_line['device_descriptor'].update(dd)
|
||||
del self.output_line['device_descriptor'][keyname]['_state']
|
||||
|
||||
for cd in self.configuration_descriptor_list:
|
||||
keyname = tuple(cd.keys())[0]
|
||||
if '_state' in cd[keyname] and cd[keyname]['_state']['bus_idx'] == idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if cd[keyname]['_state']['attribute_value']:
|
||||
last_item = cd[keyname]['_state']['last_item']
|
||||
if 'attributes' not in self.output_line['device_descriptor']['configuration_descriptor'][last_item]:
|
||||
self.output_line['device_descriptor']['configuration_descriptor'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {cd[keyname].get("value", "")} {cd[keyname].get("description", "")}'.strip()
|
||||
self.output_line['device_descriptor']['configuration_descriptor'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
self.output_line['device_descriptor']['configuration_descriptor'].update(cd)
|
||||
del self.output_line['device_descriptor']['configuration_descriptor'][keyname]['_state']
|
||||
|
||||
for ia in self.interface_association_list:
|
||||
keyname = tuple(ia.keys())[0]
|
||||
if '_state' in ia[keyname] and ia[keyname]['_state']['bus_idx'] == idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if ia[keyname]['_state']['attribute_value']:
|
||||
last_item = ia[keyname]['_state']['last_item']
|
||||
if 'attributes' not in self.output_line['device_descriptor']['configuration_descriptor']['interface_association'][last_item]:
|
||||
self.output_line['device_descriptor']['configuration_descriptor']['interface_association'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {ia[keyname].get("value", "")} {ia[keyname].get("description", "")}'.strip()
|
||||
self.output_line['device_descriptor']['configuration_descriptor']['interface_association'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
self.output_line['device_descriptor']['configuration_descriptor']['interface_association'].update(ia)
|
||||
del self.output_line['device_descriptor']['configuration_descriptor']['interface_association'][keyname]['_state']
|
||||
|
||||
# add interface_descriptor key if it doesn't exist and there are entries for this bus
|
||||
# add interface_descriptor key if it doesn't exist and there
|
||||
# are entries for this bus
|
||||
for iface_attrs in self.interface_descriptor_list:
|
||||
keyname = tuple(iface_attrs.keys())[0]
|
||||
if '_state' in iface_attrs[keyname] and iface_attrs[keyname]['_state']['bus_idx'] == idx:
|
||||
|
||||
if '_state' in iface_attrs[keyname] \
|
||||
and iface_attrs[keyname]['_state']['bus_idx'] == idx:
|
||||
|
||||
self.output_line['device_descriptor']['configuration_descriptor']['interface_descriptors'] = []
|
||||
|
||||
# find max index for this bus idx, then iterate over that range
|
||||
i_desc_iters = -1
|
||||
for iface_attrs in self.interface_descriptor_list:
|
||||
keyname = tuple(iface_attrs.keys())[0]
|
||||
if '_state' in iface_attrs[keyname] and iface_attrs[keyname]['_state']['bus_idx'] == idx:
|
||||
|
||||
if '_state' in iface_attrs[keyname] \
|
||||
and iface_attrs[keyname]['_state']['bus_idx'] == idx:
|
||||
|
||||
i_desc_iters = iface_attrs[keyname]['_state']['interface_descriptor_idx']
|
||||
|
||||
# create the interface descriptor object
|
||||
if i_desc_iters > -1:
|
||||
for iface_idx in range(i_desc_iters + 1):
|
||||
i_desc_obj = _NestedDict()
|
||||
|
||||
for iface_attrs in self.interface_descriptor_list:
|
||||
keyname = tuple(iface_attrs.keys())[0]
|
||||
if '_state' in iface_attrs[keyname] and iface_attrs[keyname]['_state']['bus_idx'] == idx and iface_attrs[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
if '_state' in iface_attrs[keyname] \
|
||||
and iface_attrs[keyname]['_state']['bus_idx'] == idx \
|
||||
and iface_attrs[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if iface_attrs[keyname]['_state']['attribute_value']:
|
||||
last_item = iface_attrs[keyname]['_state']['last_item']
|
||||
|
||||
if 'attributes' not in i_desc_obj[last_item]:
|
||||
i_desc_obj[last_item]['attributes'] = []
|
||||
|
||||
@@ -652,168 +834,70 @@ class _LsUsb():
|
||||
del iface_attrs[keyname]['_state']
|
||||
i_desc_obj.update(iface_attrs)
|
||||
|
||||
# add other nodes to the object (cdc_header, endpoint descriptors, etc.)
|
||||
for ch in self.cdc_header_list:
|
||||
keyname = tuple(ch.keys())[0]
|
||||
if '_state' in ch[keyname] and ch[keyname]['_state']['bus_idx'] == idx and ch[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
# add the rest of the interface descriptor keys to the object
|
||||
if self.cdc_header._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
self.cdc_header._update_output(idx, iface_idx, i_desc_obj)
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if ch[keyname]['_state']['attribute_value']:
|
||||
last_item = ch[keyname]['_state']['last_item']
|
||||
if 'attributes' not in i_desc_obj['cdc_header'][last_item]:
|
||||
i_desc_obj['cdc_header'][last_item]['attributes'] = []
|
||||
if self.cdc_call_management._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
self.cdc_call_management._update_output(idx, iface_idx, i_desc_obj)
|
||||
|
||||
this_attribute = f'{keyname} {ch[keyname].get("value", "")} {ch[keyname].get("description", "")}'.strip()
|
||||
i_desc_obj['cdc_header'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
if self.cdc_acm._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
self.cdc_acm._update_output(idx, iface_idx, i_desc_obj)
|
||||
|
||||
i_desc_obj['cdc_header'].update(ch)
|
||||
del i_desc_obj['cdc_header'][keyname]['_state']
|
||||
if self.cdc_union._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
self.cdc_union._update_output(idx, iface_idx, i_desc_obj)
|
||||
|
||||
for ccm in self.cdc_call_management_list:
|
||||
keyname = tuple(ccm.keys())[0]
|
||||
if '_state' in ccm[keyname] and ccm[keyname]['_state']['bus_idx'] == idx and ccm[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
if self.hid_device_descriptor._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
self.hid_device_descriptor._update_output(idx, iface_idx, i_desc_obj)
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if ccm[keyname]['_state']['attribute_value']:
|
||||
last_item = ccm[keyname]['_state']['last_item']
|
||||
if 'attributes' not in i_desc_obj['cdc_call_management'][last_item]:
|
||||
i_desc_obj['cdc_call_management'][last_item]['attributes'] = []
|
||||
# Not Implemented: Report Descriptors (need more samples)
|
||||
# for rd in self.report_descriptors_list:
|
||||
# keyname = tuple(rd.keys())[0]
|
||||
# if '_state' in rd[keyname] and rd[keyname]['_state']['bus_idx'] == idx and rd[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
# i_desc_obj['hid_device_descriptor']['report_descriptors'].update(rd)
|
||||
# del i_desc_obj['hid_device_descriptor']['report_descriptors'][keyname]['_state']
|
||||
|
||||
this_attribute = f'{keyname} {ccm[keyname].get("value", "")} {ccm[keyname].get("description", "")}'.strip()
|
||||
i_desc_obj['cdc_call_management'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
if self.videocontrol_interface_descriptors._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
i_desc_obj['videocontrol_interface_descriptors'] = []
|
||||
i_desc_obj['videocontrol_interface_descriptors'].extend(
|
||||
self.videocontrol_interface_descriptors._get_objects_list(idx, iface_idx)
|
||||
)
|
||||
|
||||
i_desc_obj['cdc_call_management'].update(ccm)
|
||||
del i_desc_obj['cdc_call_management'][keyname]['_state']
|
||||
if self.videostreaming_interface_descriptors._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
i_desc_obj['videostreaming_interface_descriptors'] = []
|
||||
i_desc_obj['videostreaming_interface_descriptors'].extend(
|
||||
self.videostreaming_interface_descriptors._get_objects_list(idx, iface_idx)
|
||||
)
|
||||
|
||||
for ca in self.cdc_acm_list:
|
||||
keyname = tuple(ca.keys())[0]
|
||||
if '_state' in ca[keyname] and ca[keyname]['_state']['bus_idx'] == idx and ca[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if ca[keyname]['_state']['attribute_value']:
|
||||
last_item = ca[keyname]['_state']['last_item']
|
||||
if 'attributes' not in i_desc_obj['cdc_acm'][last_item]:
|
||||
i_desc_obj['cdc_acm'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {ca[keyname].get("value", "")} {ca[keyname].get("description", "")}'.strip()
|
||||
i_desc_obj['cdc_acm'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
i_desc_obj['cdc_acm'].update(ca)
|
||||
del i_desc_obj['cdc_acm'][keyname]['_state']
|
||||
|
||||
for cu in self.cdc_union_list:
|
||||
keyname = tuple(cu.keys())[0]
|
||||
if '_state' in cu[keyname] and cu[keyname]['_state']['bus_idx'] == idx and cu[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if cu[keyname]['_state']['attribute_value']:
|
||||
last_item = cu[keyname]['_state']['last_item']
|
||||
if 'attributes' not in i_desc_obj['cdc_union'][last_item]:
|
||||
i_desc_obj['cdc_union'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {cu[keyname].get("value", "")} {cu[keyname].get("description", "")}'.strip()
|
||||
i_desc_obj['cdc_union'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
i_desc_obj['cdc_union'].update(cu)
|
||||
del i_desc_obj['cdc_union'][keyname]['_state']
|
||||
|
||||
for hidd in self.hid_device_descriptor_list:
|
||||
keyname = tuple(hidd.keys())[0]
|
||||
if '_state' in hidd[keyname] and hidd[keyname]['_state']['bus_idx'] == idx and hidd[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if hidd[keyname]['_state']['attribute_value']:
|
||||
last_item = hidd[keyname]['_state']['last_item']
|
||||
if 'attributes' not in i_desc_obj['hid_device_descriptor'][last_item]:
|
||||
i_desc_obj['hid_device_descriptor'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {hidd[keyname].get("value", "")} {hidd[keyname].get("description", "")}'.strip()
|
||||
i_desc_obj['hid_device_descriptor'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
i_desc_obj['hid_device_descriptor'].update(hidd)
|
||||
del i_desc_obj['hid_device_descriptor'][keyname]['_state']
|
||||
|
||||
# Not Implemented: Report Descriptors (need more samples)
|
||||
# for rd in self.report_descriptors_list:
|
||||
# keyname = tuple(rd.keys())[0]
|
||||
# if '_state' in rd[keyname] and rd[keyname]['_state']['bus_idx'] == idx and rd[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
# i_desc_obj['hid_device_descriptor']['report_descriptors'].update(rd)
|
||||
# del i_desc_obj['hid_device_descriptor']['report_descriptors'][keyname]['_state']
|
||||
|
||||
# add endpoint_descriptor key if it doesn't exist and there are entries for this interface_descriptor
|
||||
for endpoint_attrs in self.endpoint_descriptor_list:
|
||||
keyname = tuple(endpoint_attrs.keys())[0]
|
||||
if '_state' in endpoint_attrs[keyname] and endpoint_attrs[keyname]['_state']['bus_idx'] == idx and endpoint_attrs[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
i_desc_obj['endpoint_descriptors'] = []
|
||||
|
||||
# find max index for this endpoint_descriptor idx, then iterate over that range
|
||||
e_desc_iters = -1
|
||||
for endpoint_attrs in self.endpoint_descriptor_list:
|
||||
keyname = tuple(endpoint_attrs.keys())[0]
|
||||
if '_state' in endpoint_attrs[keyname] and endpoint_attrs[keyname]['_state']['bus_idx'] == idx and endpoint_attrs[keyname]['_state']['interface_descriptor_idx'] == iface_idx:
|
||||
e_desc_iters = endpoint_attrs[keyname]['_state']['endpoint_descriptor_idx']
|
||||
|
||||
# create the endpoint descriptor object
|
||||
if e_desc_iters > -1:
|
||||
for endpoint_idx in range(e_desc_iters + 1):
|
||||
e_desc_obj = {}
|
||||
for endpoint_attrs in self.endpoint_descriptor_list:
|
||||
keyname = tuple(endpoint_attrs.keys())[0]
|
||||
if '_state' in endpoint_attrs[keyname] and endpoint_attrs[keyname]['_state']['bus_idx'] == idx and endpoint_attrs[keyname]['_state']['interface_descriptor_idx'] == iface_idx and endpoint_attrs[keyname]['_state']['endpoint_descriptor_idx'] == endpoint_idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if endpoint_attrs[keyname]['_state']['attribute_value']:
|
||||
last_item = endpoint_attrs[keyname]['_state']['last_item']
|
||||
if 'attributes' not in e_desc_obj[last_item]:
|
||||
e_desc_obj[last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {endpoint_attrs[keyname].get("value", "")} {endpoint_attrs[keyname].get("description", "")}'.strip()
|
||||
e_desc_obj[last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
e_desc_obj.update(endpoint_attrs)
|
||||
del endpoint_attrs[keyname]['_state']
|
||||
|
||||
i_desc_obj['endpoint_descriptors'].append(e_desc_obj)
|
||||
if self.endpoint_descriptors._entries_for_this_bus_and_interface_idx_exist(idx, iface_idx):
|
||||
i_desc_obj['endpoint_descriptors'] = []
|
||||
i_desc_obj['endpoint_descriptors'].extend(
|
||||
self.endpoint_descriptors._get_objects_list(idx, iface_idx)
|
||||
)
|
||||
|
||||
# add the object to the list of interface descriptors
|
||||
self.output_line['device_descriptor']['configuration_descriptor']['interface_descriptors'].append(i_desc_obj)
|
||||
|
||||
for hd in self.hub_descriptor_list:
|
||||
keyname = tuple(hd.keys())[0]
|
||||
if '_state' in hd[keyname] and hd[keyname]['_state']['bus_idx'] == idx:
|
||||
|
||||
# is this a top level value or an attribute?
|
||||
if hd[keyname]['_state']['attribute_value']:
|
||||
last_item = hd[keyname]['_state']['last_item']
|
||||
if 'attributes' not in self.output_line['hub_descriptor'][last_item]:
|
||||
self.output_line['hub_descriptor'][last_item]['attributes'] = []
|
||||
|
||||
this_attribute = f'{keyname} {hd[keyname].get("value", "")} {hd[keyname].get("description", "")}'.strip()
|
||||
self.output_line['hub_descriptor'][last_item]['attributes'].append(this_attribute)
|
||||
continue
|
||||
|
||||
self.output_line['hub_descriptor'].update(hd)
|
||||
del self.output_line['hub_descriptor'][keyname]['_state']
|
||||
# add final root-level keys
|
||||
if self.hub_descriptor._entries_for_this_bus_exist(idx):
|
||||
self.hub_descriptor._update_output(idx, self.output_line)
|
||||
|
||||
for hps in self.hub_port_status_list:
|
||||
keyname = tuple(hps.keys())[0]
|
||||
|
||||
if '_state' in hps[keyname] and hps[keyname]['_state']['bus_idx'] == idx:
|
||||
self.output_line['hub_descriptor']['hub_port_status'].update(hps)
|
||||
del self.output_line['hub_descriptor']['hub_port_status'][keyname]['_state']
|
||||
|
||||
for dq in self.device_qualifier_list:
|
||||
keyname = tuple(dq.keys())[0]
|
||||
|
||||
if '_state' in dq[keyname] and dq[keyname]['_state']['bus_idx'] == idx:
|
||||
self.output_line['device_qualifier'].update(dq)
|
||||
del self.output_line['device_qualifier'][keyname]['_state']
|
||||
|
||||
for ds in self.device_status_list:
|
||||
|
||||
if '_state' in ds and ds['_state']['bus_idx'] == idx:
|
||||
self.output_line['device_status'].update(ds)
|
||||
del self.output_line['device_status']['_state']
|
||||
|
||||
@@ -71,6 +71,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
tags = ['file']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -235,6 +235,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['mdadm']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -20,7 +20,7 @@ Schema:
|
||||
"filesystem": string,
|
||||
"mount_point": string,
|
||||
"type": string,
|
||||
"access": [
|
||||
"options": [
|
||||
string
|
||||
]
|
||||
}
|
||||
@@ -34,7 +34,7 @@ Example:
|
||||
"filesystem": "sysfs",
|
||||
"mount_point": "/sys",
|
||||
"type": "sysfs",
|
||||
"access": [
|
||||
"options": [
|
||||
"rw",
|
||||
"nosuid",
|
||||
"nodev",
|
||||
@@ -46,7 +46,7 @@ Example:
|
||||
"filesystem": "proc",
|
||||
"mount_point": "/proc",
|
||||
"type": "proc",
|
||||
"access": [
|
||||
"options": [
|
||||
"rw",
|
||||
"nosuid",
|
||||
"nodev",
|
||||
@@ -58,7 +58,7 @@ Example:
|
||||
"filesystem": "udev",
|
||||
"mount_point": "/dev",
|
||||
"type": "devtmpfs",
|
||||
"access": [
|
||||
"options": [
|
||||
"rw",
|
||||
"nosuid",
|
||||
"relatime",
|
||||
@@ -75,12 +75,13 @@ import jc.utils
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.7'
|
||||
version = '1.8'
|
||||
description = '`mount` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
compatible = ['linux', 'darwin', 'freebsd', 'aix']
|
||||
magic_commands = ['mount']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
@@ -137,10 +138,38 @@ def _linux_parse(data):
|
||||
output_line['filesystem'] = parsed_line[0]
|
||||
output_line['mount_point'] = parsed_line[2]
|
||||
output_line['type'] = parsed_line[4]
|
||||
output_line['options'] = parsed_line[5].lstrip('(').rstrip(')').split(',')
|
||||
|
||||
options = parsed_line[5].lstrip('(').rstrip(')').split(',')
|
||||
output.append(output_line)
|
||||
|
||||
output_line['options'] = options
|
||||
return output
|
||||
|
||||
def _aix_parse(data):
|
||||
output = []
|
||||
|
||||
# AIX mount command starts with these headers:
|
||||
# node mounted mounted over vfs date options
|
||||
# -------- --------------- --------------- ------ ------------ ---------------
|
||||
# Remove them
|
||||
data.pop(0)
|
||||
data.pop(0)
|
||||
|
||||
for entry in data:
|
||||
output_line = {}
|
||||
parsed_line = entry.split()
|
||||
|
||||
# AIX mount entries have the remote node as the zeroth element. If the
|
||||
# mount is local, the zeroth element is the filesystem instead. We can
|
||||
# detect this by the lenth of the list. For local mounts, length is 7,
|
||||
# and for remote mounts, the length is 8. In the remote case, pop off
|
||||
# the zeroth element. Then parsed_line has a consistent format.
|
||||
if len(parsed_line) == 8:
|
||||
parsed_line.pop(0)
|
||||
|
||||
output_line['filesystem'] = parsed_line[0]
|
||||
output_line['mount_point'] = parsed_line[1]
|
||||
output_line['type'] = parsed_line[2]
|
||||
output_line['options'] = parsed_line[6].lstrip('(').rstrip(')').split(',')
|
||||
|
||||
output.append(output_line)
|
||||
|
||||
@@ -170,9 +199,12 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
# check for OSX output
|
||||
# check for OSX and AIX output
|
||||
if ' type ' not in cleandata[0]:
|
||||
raw_output = _osx_parse(cleandata)
|
||||
if 'node' in cleandata[0]:
|
||||
raw_output = _aix_parse(cleandata)
|
||||
else:
|
||||
raw_output = _osx_parse(cleandata)
|
||||
|
||||
else:
|
||||
raw_output = _linux_parse(cleandata)
|
||||
|
||||
@@ -122,6 +122,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['mpstat']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
@@ -106,6 +106,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
tags = ['command']
|
||||
streaming = True
|
||||
|
||||
|
||||
|
||||
@@ -361,6 +361,7 @@ class info():
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'freebsd']
|
||||
magic_commands = ['netstat']
|
||||
tags = ['command']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user