mirror of
https://github.com/kellyjonbrazil/jc.git
synced 2025-06-19 00:17:51 +02:00
62
CHANGELOG
62
CHANGELOG
@ -1,5 +1,17 @@
|
||||
jc changelog
|
||||
|
||||
20220425 v1.18.7
|
||||
- Add git log command parser
|
||||
- Add update-alternatives --query parser
|
||||
- Add update-alternatives --get-selections parser
|
||||
- Fix key/value and ini parsers to allow duplicate keys
|
||||
- Fix yaml file parser for files including timestamp objects
|
||||
- Fix UnicodeDecodeError on some systems where LANG=C is set and unicode
|
||||
characters are in the output
|
||||
- Update xrandr parser: add a 'rotation' field
|
||||
- Fix failing tests by moving template files
|
||||
- Add python interpreter version and path to -v and -a output
|
||||
|
||||
20220325 v1.18.6
|
||||
- Add pidstat command parser tested on linux
|
||||
- Add pidstat command streaming parser tested on linux
|
||||
@ -361,16 +373,16 @@ jc changelog
|
||||
- Add axfr support for dig command parser
|
||||
|
||||
20200312 v1.9.2
|
||||
- Updated arp parser to fix OSX detection for some edge cases
|
||||
- Update arp parser to fix OSX detection for some edge cases
|
||||
|
||||
20200312 v1.9.1
|
||||
- Updated file command parser to make filename splitting more robust
|
||||
- Update file command parser to make filename splitting more robust
|
||||
|
||||
20200311 v1.9.0
|
||||
- Added ntpq command parser
|
||||
- Added timedatectl status command parser
|
||||
- Added airport -I and airport -s command parser
|
||||
- Added file command parser
|
||||
- Add ntpq command parser
|
||||
- Add timedatectl status command parser
|
||||
- Add airport -I and airport -s command parser
|
||||
- Add file command parser
|
||||
- Optimized history command parser by https://github.com/philippeitis
|
||||
- Magic syntax fix for certain edge cases
|
||||
|
||||
@ -378,23 +390,23 @@ jc changelog
|
||||
- CLI optimizations by https://github.com/philippeitis
|
||||
- Refactored magic syntax function and added tests (https://github.com/philippeitis)
|
||||
- Github actions for CI testing on multiple platforms by https://github.com/philippeitis
|
||||
- Updated ls parser to fix parsing error in OSX with -lR when there are empty folders
|
||||
- Update ls parser to fix parsing error in OSX with -lR when there are empty folders
|
||||
|
||||
20200303 v1.8.0
|
||||
- Added blkid command parser
|
||||
- Added last and lastb command parser
|
||||
- Added who command parser
|
||||
- Added CSV file parser
|
||||
- Added /etc/passwd file parser
|
||||
- Added /etc/shadow file parser
|
||||
- Added /etc/group file parser
|
||||
- Added /etc/gshadow file parser
|
||||
- Add blkid command parser
|
||||
- Add last and lastb command parser
|
||||
- Add who command parser
|
||||
- Add CSV file parser
|
||||
- Add /etc/passwd file parser
|
||||
- Add /etc/shadow file parser
|
||||
- Add /etc/group file parser
|
||||
- Add /etc/gshadow file parser
|
||||
|
||||
20200227 v1.7.5
|
||||
- Updated ls parser to support filenames with newline characters
|
||||
- Update ls parser to support filenames with newline characters
|
||||
|
||||
20200219 v1.7.4
|
||||
- Updated ls parser to support multiple directories, globbing, and -R (recursive)
|
||||
- Update ls parser to support multiple directories, globbing, and -R (recursive)
|
||||
|
||||
20200211 v1.7.3
|
||||
- Add alternative 'magic' syntax: e.g. `jc ls -al`
|
||||
@ -411,8 +423,8 @@ jc changelog
|
||||
- Add crontab file parser with user support (tested on linux)
|
||||
- Add __version__ variable to parser modules
|
||||
- Add exit code on error
|
||||
- Updated history parser to output "line" as an integer
|
||||
- Updated compatibility list for some parsers
|
||||
- Update history parser to output "line" as an integer
|
||||
- Update compatibility list for some parsers
|
||||
- Bugfix in crontab file parser: header insertion was clobbering first row
|
||||
- Just-in-time loading of parser modules instead of loading all at start
|
||||
|
||||
@ -425,7 +437,7 @@ jc changelog
|
||||
- Add tests for ls, dig, ps, w, uptime on OSX
|
||||
- Add about option
|
||||
- Add universal parsers to refactor repetitive code
|
||||
- Updated ifconfig parser to output 'state' as an array
|
||||
- Update ifconfig parser to output 'state' as an array
|
||||
|
||||
20191117 v1.5.1
|
||||
- Add ss parser
|
||||
@ -438,11 +450,11 @@ jc changelog
|
||||
- Add -d option to debug parsing issues
|
||||
- Add compatibility warnings to stderr
|
||||
- Add documentation
|
||||
- Updated iptables parser to allow --line-numbers option
|
||||
- Updated lsblk parser to allow parsing of added columns
|
||||
- Updated mount parser: changed 'access' field name to 'options'
|
||||
- Updated netstat parser to allow parsing of unix sockets and raw network connections
|
||||
- Updated w parser to fix unaligned data where blanks are possible
|
||||
- Update iptables parser to allow --line-numbers option
|
||||
- Update lsblk parser to allow parsing of added columns
|
||||
- Update mount parser: changed 'access' field name to 'options'
|
||||
- Update netstat parser to allow parsing of unix sockets and raw network connections
|
||||
- Update w parser to fix unaligned data where blanks are possible
|
||||
- Clean up code and reorganize package
|
||||
|
||||
20191031 v1.1.1
|
||||
|
63
EXAMPLES.md
63
EXAMPLES.md
@ -3645,6 +3645,69 @@ uname -a | jc --uname -p # or: jc -p uname -a
|
||||
"kernel_version": "#74-Ubuntu SMP Tue Sep 17 17:06:04 UTC 2019"
|
||||
}
|
||||
```
|
||||
### update-alternatives --get-selections
|
||||
```bash
|
||||
update-alternatives --get-selections | jc --update-alt-gs -p # or: jc -p update-alternatives --get-selections
|
||||
```
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "arptables",
|
||||
"status": "auto",
|
||||
"current": "/usr/sbin/arptables-nft"
|
||||
},
|
||||
{
|
||||
"name": "awk",
|
||||
"status": "auto",
|
||||
"current": "/usr/bin/gawk"
|
||||
}
|
||||
]
|
||||
```
|
||||
### update-alternatives --query
|
||||
```bash
|
||||
update-alternatives --query editor | jc --update-alt-q -p # or: jc -p update-alternatives --query editor
|
||||
```
|
||||
```json
|
||||
{
|
||||
"name": "editor",
|
||||
"link": "/usr/bin/editor",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/editor.1.gz"
|
||||
},
|
||||
{
|
||||
"name": "editor.da.1.gz",
|
||||
"path": "/usr/share/man/da/man1/editor.1.gz"
|
||||
}
|
||||
],
|
||||
"status": "auto",
|
||||
"best": "/bin/nano",
|
||||
"value": "/bin/nano",
|
||||
"alternatives": [
|
||||
{
|
||||
"name": "/bin/ed",
|
||||
"priority": -100,
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/ed.1.gz"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "/bin/nano",
|
||||
"priority": 40,
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/nano.1.gz"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### upower
|
||||
```bash
|
||||
upower -i /org/freedesktop/UPower/devices/battery | jc --upower -p # or jc -p upower -i /org/freedesktop/UPower/devices/battery
|
||||
|
11
README.md
11
README.md
@ -107,7 +107,7 @@ pip3 install jc
|
||||
### OS Package Repositories
|
||||
|
||||
| OS | Command |
|
||||
|-----------------------|-------------------------------------------------------------------------------|
|
||||
|--------------------------------------|-------------------------------------------------------------------------------|
|
||||
| Debian/Ubuntu linux | `apt-get install jc` |
|
||||
| Fedora linux | `dnf install jc` |
|
||||
| openSUSE linux | `zypper install jc` |
|
||||
@ -167,6 +167,7 @@ option.
|
||||
- `--finger` enables the `finger` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/finger))
|
||||
- `--free` enables the `free` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/free))
|
||||
- `--fstab` enables the `/etc/fstab` file parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/fstab))
|
||||
- `--git-log` enables the `git log` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/git_log))
|
||||
- `--group` enables the `/etc/group` file parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/group))
|
||||
- `--gshadow` enables the `/etc/gshadow` file parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/gshadow))
|
||||
- `--hash` enables the `hash` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/hash))
|
||||
@ -227,6 +228,8 @@ option.
|
||||
- `--ufw` enables the `ufw status` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/ufw))
|
||||
- `--ufw-appinfo` enables the `ufw app info [application]` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/ufw_appinfo))
|
||||
- `--uname` enables the `uname -a` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/uname))
|
||||
- `--update-alt-gs` enables the `update-alternatives --get-selections` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/update_alt_gs))
|
||||
- `--update-alt-q` enables the `update-alternatives --query` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/update_alt_q))
|
||||
- `--upower` enables the `upower` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/upower))
|
||||
- `--uptime` enables the `uptime` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/uptime))
|
||||
- `--vmstat` enables the `vmstat` command parser ([documentation](https://kellyjonbrazil.github.io/jc/docs/parsers/vmstat))
|
||||
@ -399,9 +402,9 @@ Local parser plugins are standard python module files. Use the
|
||||
or [`jc/parsers/foo_s.py (streaming)`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/foo_s.py)
|
||||
parser as a template and simply place a `.py` file in the `jcparsers` subfolder.
|
||||
|
||||
Local plugin filenames must be valid python module names, therefore must consist
|
||||
entirely of alphanumerics and start with a letter. Local plugins may override
|
||||
default parsers.
|
||||
Local plugin filenames must be valid python module names and therefore must
|
||||
start with a letter and consist entirely of alphanumerics. Local plugins
|
||||
may override default parsers.
|
||||
|
||||
> Note: The application data directory follows the
|
||||
[XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
|
||||
|
36
docgen.sh
36
docgen.sh
@ -76,20 +76,30 @@ EOF
|
||||
)
|
||||
|
||||
cd jc
|
||||
echo Building docs for: package
|
||||
pydoc-markdown -m jc "${readme_config}" > ../docs/readme.md
|
||||
(
|
||||
echo Building docs for: package
|
||||
pydoc-markdown -m jc "${readme_config}" > ../docs/readme.md; echo "+++ package docs complete"
|
||||
) &
|
||||
|
||||
echo Building docs for: lib
|
||||
pydoc-markdown -m jc.lib "${toc_config}" > ../docs/lib.md
|
||||
(
|
||||
echo Building docs for: lib
|
||||
pydoc-markdown -m jc.lib "${toc_config}" > ../docs/lib.md; echo "+++ lib docs complete"
|
||||
) &
|
||||
|
||||
echo Building docs for: utils
|
||||
pydoc-markdown -m jc.utils "${toc_config}" > ../docs/utils.md
|
||||
(
|
||||
echo Building docs for: utils
|
||||
pydoc-markdown -m jc.utils "${toc_config}" > ../docs/utils.md; echo "+++ utils docs complete"
|
||||
) &
|
||||
|
||||
echo Building docs for: streaming
|
||||
pydoc-markdown -m jc.streaming "${toc_config}" > ../docs/streaming.md
|
||||
(
|
||||
echo Building docs for: streaming
|
||||
pydoc-markdown -m jc.streaming "${toc_config}" > ../docs/streaming.md; echo "+++ streaming docs complete"
|
||||
) &
|
||||
|
||||
echo Building docs for: universal parser
|
||||
pydoc-markdown -m jc.parsers.universal "${toc_config}" > ../docs/parsers/universal.md
|
||||
(
|
||||
echo Building docs for: universal parser
|
||||
pydoc-markdown -m jc.parsers.universal "${toc_config}" > ../docs/parsers/universal.md; echo "+++ universal parser docs complete"
|
||||
) &
|
||||
|
||||
# a bit of inception here... jc is being used to help
|
||||
# automate the generation of its own documentation. :)
|
||||
@ -103,7 +113,7 @@ do
|
||||
done < <(jc -a | jq -c '.parsers[] | select(.plugin != true)')
|
||||
|
||||
for parser in "${parsers[@]}"
|
||||
do
|
||||
do (
|
||||
parser_name=$(jq -r '.name' <<< "$parser")
|
||||
compatible=$(jq -r '.compatible | join(", ")' <<< "$parser")
|
||||
version=$(jq -r '.version' <<< "$parser")
|
||||
@ -117,4 +127,8 @@ do
|
||||
echo "Compatibility: ${compatible}" >> ../docs/parsers/"${parser_name}".md
|
||||
echo >> ../docs/parsers/"${parser_name}".md
|
||||
echo "Version ${version} by ${author} (${author_email})" >> ../docs/parsers/"${parser_name}".md
|
||||
echo "+++ ${parser_name} docs complete"
|
||||
) &
|
||||
done
|
||||
wait
|
||||
echo "Document Generation Complete"
|
||||
|
@ -68,7 +68,7 @@ Parameters:
|
||||
variants of the module name.
|
||||
|
||||
data: (string or data to parse (string for normal
|
||||
iterator) parsers, iterator of strings for
|
||||
iterable) parsers, iterable of strings for
|
||||
streaming parsers)
|
||||
|
||||
raw: (boolean) output preprocessed JSON if True
|
||||
|
175
docs/parsers/git_log.md
Normal file
175
docs/parsers/git_log.md
Normal file
@ -0,0 +1,175 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.git_log"></a>
|
||||
|
||||
# jc.parsers.git\_log
|
||||
|
||||
jc - JSON Convert `git log` command output parser
|
||||
|
||||
Can be used with the following format options:
|
||||
- `oneline`
|
||||
- `short`
|
||||
- `medium`
|
||||
- `full`
|
||||
- `fuller`
|
||||
|
||||
Additional options supported:
|
||||
- `--stat`
|
||||
- `--shortstat`
|
||||
|
||||
The `epoch` calculated timestamp field is naive. (i.e. based on the
|
||||
local time of the system the parser is run on)
|
||||
|
||||
The `epoch_utc` calculated timestamp field is timezone-aware and is
|
||||
only available if the timezone field is UTC.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ git log | jc --git-log
|
||||
|
||||
or
|
||||
|
||||
$ jc git log
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('git_log', git_log_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"commit": string,
|
||||
"author": string,
|
||||
"author_email": string,
|
||||
"date": string,
|
||||
"epoch": integer, [0]
|
||||
"epoch_utc": integer, [1]
|
||||
"commit_by": string,
|
||||
"commit_by_email": string,
|
||||
"commit_by_date": string,
|
||||
"message": string,
|
||||
"stats" : {
|
||||
"files_changed": integer,
|
||||
"insertions": integer,
|
||||
"deletions": integer,
|
||||
"files": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
[0] naive timestamp if "date" field is parsable, else null
|
||||
[1] timezone aware timestamp availabe for UTC, else null
|
||||
|
||||
Examples:
|
||||
|
||||
$ git log --stat | jc --git-log -p
|
||||
[
|
||||
{
|
||||
"commit": "728d882ed007b3c8b785018874a0eb06e1143b66",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:50:19 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": 2,
|
||||
"insertions": 90,
|
||||
"deletions": 12,
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"jc/parsers/git_log.py"
|
||||
]
|
||||
},
|
||||
"message": "add timestamp docs and examples",
|
||||
"epoch": 1650462619,
|
||||
"epoch_utc": null
|
||||
},
|
||||
{
|
||||
"commit": "b53e42aca623181aa9bc72194e6eeef1e9a3a237",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:44:42 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": 5,
|
||||
"insertions": 29,
|
||||
"deletions": 6,
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"docs/utils.md",
|
||||
"jc/parsers/git_log.py",
|
||||
"jc/utils.py",
|
||||
"man/jc.1"
|
||||
]
|
||||
},
|
||||
"message": "add calculated timestamp",
|
||||
"epoch": 1650462282,
|
||||
"epoch_utc": null
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
$ git log --stat | jc --git-log -p -r
|
||||
[
|
||||
{
|
||||
"commit": "728d882ed007b3c8b785018874a0eb06e1143b66",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:50:19 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": "2",
|
||||
"insertions": "90",
|
||||
"deletions": "12",
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"jc/parsers/git_log.py"
|
||||
]
|
||||
},
|
||||
"message": "add timestamp docs and examples"
|
||||
},
|
||||
{
|
||||
"commit": "b53e42aca623181aa9bc72194e6eeef1e9a3a237",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:44:42 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": "5",
|
||||
"insertions": "29",
|
||||
"deletions": "6",
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"docs/utils.md",
|
||||
"jc/parsers/git_log.py",
|
||||
"jc/utils.py",
|
||||
"man/jc.1"
|
||||
]
|
||||
},
|
||||
"message": "add calculated timestamp"
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
<a id="jc.parsers.git_log.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict]
|
||||
```
|
||||
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
@ -6,12 +6,14 @@
|
||||
jc - JSON Convert `INI` file parser
|
||||
|
||||
Parses standard `INI` files and files containing simple key/value pairs.
|
||||
Delimiter can be `=` or `:`. Missing values are supported. Comment prefix
|
||||
can be `#` or `;`. Comments must be on their own line.
|
||||
|
||||
Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
- 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.
|
||||
|
||||
> Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
@ -89,4 +91,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.5 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
@ -5,13 +5,15 @@
|
||||
|
||||
jc - JSON Convert `Key/Value` file parser
|
||||
|
||||
Supports files containing simple key/value pairs. Delimiter can be `=` or
|
||||
`:`. Missing values are supported. Comment prefix can be `#` or `;`.
|
||||
Comments must be on their own line.
|
||||
Supports files containing simple key/value pairs.
|
||||
|
||||
Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
- 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.
|
||||
|
||||
> Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
@ -78,4 +80,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.1 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.2 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
71
docs/parsers/update_alt_gs.md
Normal file
71
docs/parsers/update_alt_gs.md
Normal file
@ -0,0 +1,71 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.update_alt_gs"></a>
|
||||
|
||||
# jc.parsers.update\_alt\_gs
|
||||
|
||||
jc - JSON Convert `update-alternatives --get-selections` command output parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ update-alternatives --get-selections | jc --update-alt-gs
|
||||
|
||||
or
|
||||
|
||||
$ jc update-alternatives --get-selections
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('update-alt-gs',
|
||||
update_alternatives_get_selections_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"name": string,
|
||||
"status": string,
|
||||
"current": string
|
||||
}
|
||||
]
|
||||
|
||||
Examples:
|
||||
|
||||
$ update-alternatives --get-selections | jc --update-alt-gs -p
|
||||
[
|
||||
{
|
||||
"name": "arptables",
|
||||
"status": "auto",
|
||||
"current": "/usr/sbin/arptables-nft"
|
||||
},
|
||||
{
|
||||
"name": "awk",
|
||||
"status": "auto",
|
||||
"current": "/usr/bin/gawk"
|
||||
}
|
||||
]
|
||||
|
||||
<a id="jc.parsers.update_alt_gs.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data: str, raw: bool = False, quiet: bool = False) -> List[Dict]
|
||||
```
|
||||
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
157
docs/parsers/update_alt_q.md
Normal file
157
docs/parsers/update_alt_q.md
Normal file
@ -0,0 +1,157 @@
|
||||
[Home](https://kellyjonbrazil.github.io/jc/)
|
||||
<a id="jc.parsers.update_alt_q"></a>
|
||||
|
||||
# jc.parsers.update\_alt\_q
|
||||
|
||||
jc - JSON Convert `update-alternatives --query` command output parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ update-alternatives --query | jc --update-alt-q
|
||||
|
||||
or
|
||||
|
||||
$ jc update-alternatives --query
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('update_alt_q',
|
||||
update_alternatives_query_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"name": string,
|
||||
"link": string,
|
||||
"slaves": [
|
||||
{
|
||||
"name": string,
|
||||
"path": string
|
||||
}
|
||||
],
|
||||
"status": string,
|
||||
"best": string,
|
||||
"value": string, # (null if 'none')
|
||||
"alternatives": [
|
||||
{
|
||||
"alternative": string,
|
||||
"priority": integer,
|
||||
"slaves": [
|
||||
{
|
||||
"name": string,
|
||||
"path": string
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ update-alternatives --query editor | jc --update-alt-q -p
|
||||
{
|
||||
"name": "editor",
|
||||
"link": "/usr/bin/editor",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/editor.1.gz"
|
||||
},
|
||||
{
|
||||
"name": "editor.da.1.gz",
|
||||
"path": "/usr/share/man/da/man1/editor.1.gz"
|
||||
}
|
||||
],
|
||||
"status": "auto",
|
||||
"best": "/bin/nano",
|
||||
"value": "/bin/nano",
|
||||
"alternatives": [
|
||||
{
|
||||
"alternative": "/bin/ed",
|
||||
"priority": -100,
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/ed.1.gz"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"alternative": "/bin/nano",
|
||||
"priority": 40,
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/nano.1.gz"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ update-alternatives --query | jc --update-alt-q -p -r
|
||||
{
|
||||
"name": "editor",
|
||||
"link": "/usr/bin/editor",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/editor.1.gz"
|
||||
},
|
||||
{
|
||||
"name": "editor.da.1.gz",
|
||||
"path": "/usr/share/man/da/man1/editor.1.gz"
|
||||
}
|
||||
],
|
||||
"status": "auto",
|
||||
"best": "/bin/nano",
|
||||
"value": "/bin/nano",
|
||||
"alternatives": [
|
||||
{
|
||||
"alternative": "/bin/ed",
|
||||
"priority": "-100",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/ed.1.gz"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"alternative": "/bin/nano",
|
||||
"priority": "40",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/nano.1.gz"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
<a id="jc.parsers.update_alt_q.parse"></a>
|
||||
|
||||
### parse
|
||||
|
||||
```python
|
||||
def parse(data: str, raw: bool = False, quiet: bool = False) -> Dict
|
||||
```
|
||||
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
|
||||
### Parser Information
|
||||
Compatibility: linux
|
||||
|
||||
Version 1.0 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
@ -54,7 +54,8 @@ Schema:
|
||||
"offset_width": integer,
|
||||
"offset_height": integer,
|
||||
"dimension_width": integer,
|
||||
"dimension_height": integer
|
||||
"dimension_height": integer,
|
||||
"rotation": string
|
||||
}
|
||||
],
|
||||
"unassociated_devices": [
|
||||
@ -130,7 +131,8 @@ Examples:
|
||||
"offset_width": 0,
|
||||
"offset_height": 0,
|
||||
"dimension_width": 310,
|
||||
"dimension_height": 170
|
||||
"dimension_height": 170,
|
||||
"rotation": "normal"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -160,4 +162,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, aix, freebsd
|
||||
|
||||
Version 1.0 by Kevin Lyter (lyter_git at sent.com)
|
||||
Version 1.1 by Kevin Lyter (lyter_git at sent.com)
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
jc - JSON Convert `YAML` file parser
|
||||
|
||||
Note: datetime objects will be converted to strings.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ cat foo.yaml | jc --yaml
|
||||
@ -107,4 +109,4 @@ Returns:
|
||||
### Parser Information
|
||||
Compatibility: linux, darwin, cygwin, win32, aix, freebsd
|
||||
|
||||
Version 1.6 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
Version 1.7 by Kelly Brazil (kellyjonbrazil@gmail.com)
|
||||
|
@ -187,7 +187,7 @@ class timestamp()
|
||||
|
||||
```python
|
||||
def __init__(datetime_string: str,
|
||||
format_hint: Union[List, Tuple, None] = None) -> None
|
||||
format_hint: Optional[Iterable] = None) -> None
|
||||
```
|
||||
|
||||
Input a datetime text string of several formats and convert to a
|
||||
@ -198,7 +198,7 @@ Parameters:
|
||||
datetime_string (str): a string representation of a
|
||||
datetime in several supported formats
|
||||
|
||||
format_hint (list | tuple): an optional list of format ID
|
||||
format_hint (iterable): an optional iterable of format ID
|
||||
integers to instruct the timestamp object to try those
|
||||
formats first in the order given. Other formats will be
|
||||
tried after the format hint list is exhausted. This can
|
||||
|
41
jc/cli.py
41
jc/cli.py
@ -37,7 +37,7 @@ class info():
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
website = 'https://github.com/kellyjonbrazil/jc'
|
||||
copyright = '© 2019-2022 Kelly Brazil'
|
||||
copyright = f'© 2019-2022 Kelly Brazil'
|
||||
license = 'MIT License'
|
||||
|
||||
|
||||
@ -84,6 +84,16 @@ if PYGMENTS_INSTALLED:
|
||||
}
|
||||
|
||||
|
||||
def asciify(string):
|
||||
"""
|
||||
Return a string downgraded from Unicode to ASCII with some simple
|
||||
conversions.
|
||||
"""
|
||||
string = string.replace('©', '(c)')
|
||||
string = ascii(string)
|
||||
return string.replace(r'\n', '\n')
|
||||
|
||||
|
||||
def set_env_colors(env_colors=None):
|
||||
"""
|
||||
Return a dictionary to be used in Pygments custom style class.
|
||||
@ -177,6 +187,8 @@ def about_jc():
|
||||
'website': info.website,
|
||||
'copyright': info.copyright,
|
||||
'license': info.license,
|
||||
'python_version': '.'.join((str(sys.version_info.major), str(sys.version_info.minor), str(sys.version_info.micro))),
|
||||
'python_path': sys.executable,
|
||||
'parser_count': len(all_parser_info()),
|
||||
'parsers': all_parser_info()
|
||||
}
|
||||
@ -249,8 +261,12 @@ def help_doc(options):
|
||||
|
||||
def versiontext():
|
||||
"""Return the version text"""
|
||||
py_ver = '.'.join((str(sys.version_info.major), str(sys.version_info.minor), str(sys.version_info.micro)))
|
||||
versiontext_string = f'''\
|
||||
jc version {info.version}
|
||||
jc version: {info.version}
|
||||
python interpreter version: {py_ver}
|
||||
python path: {sys.executable}
|
||||
|
||||
{info.website}
|
||||
{info.copyright}'''
|
||||
return textwrap.dedent(versiontext_string)
|
||||
@ -273,10 +289,23 @@ def json_out(data, pretty=False, env_colors=None, mono=False, piped_out=False):
|
||||
class JcStyle(Style):
|
||||
styles = set_env_colors(env_colors)
|
||||
|
||||
return str(highlight(json.dumps(data, indent=indent, separators=separators, ensure_ascii=False),
|
||||
try:
|
||||
return str(highlight(json.dumps(data,
|
||||
indent=indent,
|
||||
separators=separators,
|
||||
ensure_ascii=False),
|
||||
JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
|
||||
except UnicodeEncodeError:
|
||||
return str(highlight(json.dumps(data,
|
||||
indent=indent,
|
||||
separators=separators,
|
||||
ensure_ascii=True),
|
||||
JsonLexer(), Terminal256Formatter(style=JcStyle))[0:-1])
|
||||
|
||||
try:
|
||||
return json.dumps(data, indent=indent, separators=separators, ensure_ascii=False)
|
||||
except UnicodeEncodeError:
|
||||
return json.dumps(data, indent=indent, separators=separators, ensure_ascii=True)
|
||||
|
||||
|
||||
def magic_parser(args):
|
||||
@ -422,11 +451,17 @@ def main():
|
||||
sys.exit(0)
|
||||
|
||||
if help_me:
|
||||
try:
|
||||
print(help_doc(sys.argv))
|
||||
except UnicodeEncodeError:
|
||||
print(asciify(help_doc(sys.argv)))
|
||||
sys.exit(0)
|
||||
|
||||
if version_info:
|
||||
try:
|
||||
print(versiontext())
|
||||
except UnicodeEncodeError:
|
||||
print(asciify(versiontext()))
|
||||
sys.exit(0)
|
||||
|
||||
# if magic syntax used, try to run the command and error if it's not found, etc.
|
||||
|
@ -6,7 +6,7 @@ import importlib
|
||||
from typing import Dict, List, Iterable, Union, Iterator
|
||||
from jc import appdirs
|
||||
|
||||
__version__ = '1.18.6'
|
||||
__version__ = '1.18.7'
|
||||
|
||||
parsers = [
|
||||
'acpi',
|
||||
@ -33,6 +33,7 @@ parsers = [
|
||||
'finger',
|
||||
'free',
|
||||
'fstab',
|
||||
'git-log',
|
||||
'group',
|
||||
'gshadow',
|
||||
'hash',
|
||||
@ -93,6 +94,8 @@ parsers = [
|
||||
'ufw',
|
||||
'ufw-appinfo',
|
||||
'uname',
|
||||
'update-alt-gs',
|
||||
'update-alt-q',
|
||||
'upower',
|
||||
'uptime',
|
||||
'vmstat',
|
||||
@ -206,7 +209,7 @@ def parse(
|
||||
variants of the module name.
|
||||
|
||||
data: (string or data to parse (string for normal
|
||||
iterator) parsers, iterator of strings for
|
||||
iterable) parsers, iterable of strings for
|
||||
streaming parsers)
|
||||
|
||||
raw: (boolean) output preprocessed JSON if True
|
||||
|
329
jc/parsers/git_log.py
Normal file
329
jc/parsers/git_log.py
Normal file
@ -0,0 +1,329 @@
|
||||
"""jc - JSON Convert `git log` command output parser
|
||||
|
||||
Can be used with the following format options:
|
||||
- `oneline`
|
||||
- `short`
|
||||
- `medium`
|
||||
- `full`
|
||||
- `fuller`
|
||||
|
||||
Additional options supported:
|
||||
- `--stat`
|
||||
- `--shortstat`
|
||||
|
||||
The `epoch` calculated timestamp field is naive. (i.e. based on the
|
||||
local time of the system the parser is run on)
|
||||
|
||||
The `epoch_utc` calculated timestamp field is timezone-aware and is
|
||||
only available if the timezone field is UTC.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ git log | jc --git-log
|
||||
|
||||
or
|
||||
|
||||
$ jc git log
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('git_log', git_log_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"commit": string,
|
||||
"author": string,
|
||||
"author_email": string,
|
||||
"date": string,
|
||||
"epoch": integer, [0]
|
||||
"epoch_utc": integer, [1]
|
||||
"commit_by": string,
|
||||
"commit_by_email": string,
|
||||
"commit_by_date": string,
|
||||
"message": string,
|
||||
"stats" : {
|
||||
"files_changed": integer,
|
||||
"insertions": integer,
|
||||
"deletions": integer,
|
||||
"files": [
|
||||
string
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
[0] naive timestamp if "date" field is parsable, else null
|
||||
[1] timezone aware timestamp availabe for UTC, else null
|
||||
|
||||
Examples:
|
||||
|
||||
$ git log --stat | jc --git-log -p
|
||||
[
|
||||
{
|
||||
"commit": "728d882ed007b3c8b785018874a0eb06e1143b66",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:50:19 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": 2,
|
||||
"insertions": 90,
|
||||
"deletions": 12,
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"jc/parsers/git_log.py"
|
||||
]
|
||||
},
|
||||
"message": "add timestamp docs and examples",
|
||||
"epoch": 1650462619,
|
||||
"epoch_utc": null
|
||||
},
|
||||
{
|
||||
"commit": "b53e42aca623181aa9bc72194e6eeef1e9a3a237",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:44:42 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": 5,
|
||||
"insertions": 29,
|
||||
"deletions": 6,
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"docs/utils.md",
|
||||
"jc/parsers/git_log.py",
|
||||
"jc/utils.py",
|
||||
"man/jc.1"
|
||||
]
|
||||
},
|
||||
"message": "add calculated timestamp",
|
||||
"epoch": 1650462282,
|
||||
"epoch_utc": null
|
||||
},
|
||||
...
|
||||
]
|
||||
|
||||
$ git log --stat | jc --git-log -p -r
|
||||
[
|
||||
{
|
||||
"commit": "728d882ed007b3c8b785018874a0eb06e1143b66",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:50:19 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": "2",
|
||||
"insertions": "90",
|
||||
"deletions": "12",
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"jc/parsers/git_log.py"
|
||||
]
|
||||
},
|
||||
"message": "add timestamp docs and examples"
|
||||
},
|
||||
{
|
||||
"commit": "b53e42aca623181aa9bc72194e6eeef1e9a3a237",
|
||||
"author": "Kelly Brazil",
|
||||
"author_email": "kellyjonbrazil@gmail.com",
|
||||
"date": "Wed Apr 20 09:44:42 2022 -0400",
|
||||
"stats": {
|
||||
"files_changed": "5",
|
||||
"insertions": "29",
|
||||
"deletions": "6",
|
||||
"files": [
|
||||
"docs/parsers/git_log.md",
|
||||
"docs/utils.md",
|
||||
"jc/parsers/git_log.py",
|
||||
"jc/utils.py",
|
||||
"man/jc.1"
|
||||
]
|
||||
},
|
||||
"message": "add calculated timestamp"
|
||||
},
|
||||
...
|
||||
]
|
||||
"""
|
||||
import re
|
||||
from typing import List, Dict
|
||||
import jc.utils
|
||||
|
||||
hash_pattern = re.compile(r'([0-9]|[a-f])+')
|
||||
changes_pattern = re.compile(r'\s(?P<files>\d+)\s+(files? changed),\s+(?P<insertions>\d+)\s(insertions?\(\+\))?(,\s+)?(?P<deletions>\d+)?(\s+deletions?\(\-\))?')
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`git log` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux', 'darwin', 'cygwin', 'win32', 'aix', 'freebsd']
|
||||
magic_commands = ['git log']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def _process(proc_data: List[Dict]) -> List[Dict]:
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (List of Dictionaries) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Structured to conform to the schema.
|
||||
"""
|
||||
int_list = ['files_changed', 'insertions', 'deletions']
|
||||
|
||||
for entry in proc_data:
|
||||
if 'date' in entry:
|
||||
ts = jc.utils.timestamp(entry['date'], format_hint=(1100,))
|
||||
entry['epoch'] = ts.naive
|
||||
entry['epoch_utc'] = ts.utc
|
||||
|
||||
if 'stats' in entry:
|
||||
for key in entry['stats']:
|
||||
if key in int_list:
|
||||
entry['stats'][key] = jc.utils.convert_to_int(entry['stats'][key])
|
||||
return proc_data
|
||||
|
||||
|
||||
def _is_commit_hash(hash_string: str) -> bool:
|
||||
# 0c55240e9da30ac4293dc324f1094de2abd3da91
|
||||
if len(hash_string) != 40:
|
||||
return False
|
||||
|
||||
if hash_pattern.match(hash_string):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def parse(
|
||||
data: str,
|
||||
raw: bool = False,
|
||||
quiet: bool = False
|
||||
) -> List[Dict]:
|
||||
"""
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output: List = []
|
||||
output_line: Dict = {}
|
||||
message_lines: List[str] = []
|
||||
file_list: List[str] = []
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in data.splitlines():
|
||||
line_list = line.split(maxsplit=1)
|
||||
|
||||
# oneline style
|
||||
if line_list and _is_commit_hash(line_list[0]):
|
||||
if output_line:
|
||||
if file_list:
|
||||
output_line['stats']['files'] = file_list
|
||||
|
||||
raw_output.append(output_line)
|
||||
output_line = {}
|
||||
message_lines = []
|
||||
file_list = []
|
||||
output_line = {
|
||||
'commit': line_list[0],
|
||||
'message': line_list[1]
|
||||
}
|
||||
continue
|
||||
|
||||
# all other styles
|
||||
if line.startswith('commit '):
|
||||
if output_line:
|
||||
if message_lines:
|
||||
output_line['message'] = '\n'.join(message_lines)
|
||||
|
||||
if file_list:
|
||||
output_line['stats']['files'] = file_list
|
||||
|
||||
raw_output.append(output_line)
|
||||
output_line = {}
|
||||
message_lines = []
|
||||
file_list = []
|
||||
output_line['commit'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Merge: '):
|
||||
output_line['merge'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Author: '):
|
||||
values = line_list[1].rsplit(maxsplit=1)
|
||||
output_line['author'] = values[0]
|
||||
output_line['author_email'] = values[1].strip('<').strip('>')
|
||||
continue
|
||||
|
||||
if line.startswith('Date: '):
|
||||
output_line['date'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('AuthorDate: '):
|
||||
output_line['date'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('CommitDate: '):
|
||||
output_line['commit_by_date'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Commit: '):
|
||||
values = line_list[1].rsplit(maxsplit=1)
|
||||
output_line['commit_by'] = values[0]
|
||||
output_line['commit_by_email'] = values[1].strip('<').strip('>')
|
||||
continue
|
||||
|
||||
if line.startswith(' '):
|
||||
message_lines.append(line.strip())
|
||||
continue
|
||||
|
||||
if line.startswith(' ') and 'changed, ' not in line:
|
||||
# this is a file name
|
||||
file_name = line.split('|')[0].strip()
|
||||
file_list.append(file_name)
|
||||
continue
|
||||
|
||||
if line.startswith(' ') and 'changed, ' in line:
|
||||
# this is the stat summary
|
||||
changes = changes_pattern.match(line)
|
||||
if changes:
|
||||
files = changes['files']
|
||||
insertions = changes['insertions']
|
||||
deletions = changes['deletions']
|
||||
|
||||
output_line['stats'] = {
|
||||
'files_changed': files or '0',
|
||||
'insertions': insertions or '0',
|
||||
'deletions': deletions or '0'
|
||||
}
|
||||
|
||||
if output_line:
|
||||
if message_lines:
|
||||
output_line['message'] = '\n'.join(message_lines)
|
||||
|
||||
if file_list:
|
||||
output_line['stats']['files'] = file_list
|
||||
|
||||
raw_output.append(output_line)
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
@ -1,12 +1,14 @@
|
||||
"""jc - JSON Convert `INI` file parser
|
||||
|
||||
Parses standard `INI` files and files containing simple key/value pairs.
|
||||
Delimiter can be `=` or `:`. Missing values are supported. Comment prefix
|
||||
can be `#` or `;`. Comments must be on their own line.
|
||||
|
||||
Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
- 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.
|
||||
|
||||
> Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
@ -67,7 +69,7 @@ import configparser
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.5'
|
||||
version = '1.6'
|
||||
description = 'INI file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@ -135,7 +137,9 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
ini = configparser.ConfigParser(allow_no_value=True, interpolation=None)
|
||||
ini = configparser.ConfigParser(allow_no_value=True,
|
||||
interpolation=None,
|
||||
strict=False)
|
||||
try:
|
||||
ini.read_string(data)
|
||||
raw_output = {s: dict(ini.items(s)) for s in ini.sections()}
|
||||
|
@ -1,12 +1,14 @@
|
||||
"""jc - JSON Convert `Key/Value` file parser
|
||||
|
||||
Supports files containing simple key/value pairs. Delimiter can be `=` or
|
||||
`:`. Missing values are supported. Comment prefix can be `#` or `;`.
|
||||
Comments must be on their own line.
|
||||
Supports files containing simple key/value pairs.
|
||||
|
||||
Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
- 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.
|
||||
|
||||
> Note: Values starting and ending with quotation marks will have the marks
|
||||
removed. If you would like to keep the quotation marks, use the `-r`
|
||||
command-line argument or the `raw=True` argument in `parse()`.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
@ -52,7 +54,7 @@ Examples:
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.1'
|
||||
version = '1.2'
|
||||
description = 'Key/Value file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
|
111
jc/parsers/update_alt_gs.py
Normal file
111
jc/parsers/update_alt_gs.py
Normal file
@ -0,0 +1,111 @@
|
||||
"""jc - JSON Convert `update-alternatives --get-selections` command output parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ update-alternatives --get-selections | jc --update-alt-gs
|
||||
|
||||
or
|
||||
|
||||
$ jc update-alternatives --get-selections
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('update-alt-gs',
|
||||
update_alternatives_get_selections_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
[
|
||||
{
|
||||
"name": string,
|
||||
"status": string,
|
||||
"current": string
|
||||
}
|
||||
]
|
||||
|
||||
Examples:
|
||||
|
||||
$ update-alternatives --get-selections | jc --update-alt-gs -p
|
||||
[
|
||||
{
|
||||
"name": "arptables",
|
||||
"status": "auto",
|
||||
"current": "/usr/sbin/arptables-nft"
|
||||
},
|
||||
{
|
||||
"name": "awk",
|
||||
"status": "auto",
|
||||
"current": "/usr/bin/gawk"
|
||||
}
|
||||
]
|
||||
"""
|
||||
from typing import List, Dict
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`update-alternatives --get-selections` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['update-alternatives --get-selections']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def _process(proc_data: List[Dict]) -> List[Dict]:
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (List of Dictionaries) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Structured to conform to the schema.
|
||||
"""
|
||||
# nothing to process
|
||||
return proc_data
|
||||
|
||||
|
||||
def parse(
|
||||
data: str,
|
||||
raw: bool = False,
|
||||
quiet: bool = False
|
||||
) -> List[Dict]:
|
||||
"""
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
List of Dictionaries. Raw or processed structured data.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output: List = []
|
||||
output_line = {}
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
line_list = line.split(maxsplit=2)
|
||||
output_line = {
|
||||
"name": line_list[0],
|
||||
"status": line_list[1],
|
||||
"current": line_list[2]
|
||||
}
|
||||
raw_output.append(output_line)
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
261
jc/parsers/update_alt_q.py
Normal file
261
jc/parsers/update_alt_q.py
Normal file
@ -0,0 +1,261 @@
|
||||
"""jc - JSON Convert `update-alternatives --query` command output parser
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ update-alternatives --query | jc --update-alt-q
|
||||
|
||||
or
|
||||
|
||||
$ jc update-alternatives --query
|
||||
|
||||
Usage (module):
|
||||
|
||||
import jc
|
||||
result = jc.parse('update_alt_q',
|
||||
update_alternatives_query_command_output)
|
||||
|
||||
Schema:
|
||||
|
||||
{
|
||||
"name": string,
|
||||
"link": string,
|
||||
"slaves": [
|
||||
{
|
||||
"name": string,
|
||||
"path": string
|
||||
}
|
||||
],
|
||||
"status": string,
|
||||
"best": string,
|
||||
"value": string, # (null if 'none')
|
||||
"alternatives": [
|
||||
{
|
||||
"alternative": string,
|
||||
"priority": integer,
|
||||
"slaves": [
|
||||
{
|
||||
"name": string,
|
||||
"path": string
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Examples:
|
||||
|
||||
$ update-alternatives --query editor | jc --update-alt-q -p
|
||||
{
|
||||
"name": "editor",
|
||||
"link": "/usr/bin/editor",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/editor.1.gz"
|
||||
},
|
||||
{
|
||||
"name": "editor.da.1.gz",
|
||||
"path": "/usr/share/man/da/man1/editor.1.gz"
|
||||
}
|
||||
],
|
||||
"status": "auto",
|
||||
"best": "/bin/nano",
|
||||
"value": "/bin/nano",
|
||||
"alternatives": [
|
||||
{
|
||||
"alternative": "/bin/ed",
|
||||
"priority": -100,
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/ed.1.gz"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"alternative": "/bin/nano",
|
||||
"priority": 40,
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/nano.1.gz"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
$ update-alternatives --query | jc --update-alt-q -p -r
|
||||
{
|
||||
"name": "editor",
|
||||
"link": "/usr/bin/editor",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/editor.1.gz"
|
||||
},
|
||||
{
|
||||
"name": "editor.da.1.gz",
|
||||
"path": "/usr/share/man/da/man1/editor.1.gz"
|
||||
}
|
||||
],
|
||||
"status": "auto",
|
||||
"best": "/bin/nano",
|
||||
"value": "/bin/nano",
|
||||
"alternatives": [
|
||||
{
|
||||
"alternative": "/bin/ed",
|
||||
"priority": "-100",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/ed.1.gz"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"alternative": "/bin/nano",
|
||||
"priority": "40",
|
||||
"slaves": [
|
||||
{
|
||||
"name": "editor.1.gz",
|
||||
"path": "/usr/share/man/man1/nano.1.gz"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
from typing import List, Dict
|
||||
import jc.utils
|
||||
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.0'
|
||||
description = '`update-alternatives --query` command parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
compatible = ['linux']
|
||||
magic_commands = ['update-alternatives --query']
|
||||
|
||||
|
||||
__version__ = info.version
|
||||
|
||||
|
||||
def _process(proc_data: Dict) -> Dict:
|
||||
"""
|
||||
Final processing to conform to the schema.
|
||||
|
||||
Parameters:
|
||||
|
||||
proc_data: (Dictionary) raw structured data to process
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Structured to conform to the schema.
|
||||
"""
|
||||
int_list = ['priority']
|
||||
|
||||
if 'value' in proc_data:
|
||||
if proc_data['value'] == 'none':
|
||||
proc_data['value'] = None
|
||||
|
||||
if 'alternatives' in proc_data:
|
||||
for index, alt in enumerate(proc_data['alternatives']):
|
||||
for key in alt:
|
||||
if key in int_list:
|
||||
proc_data['alternatives'][index][key] = jc.utils.convert_to_int(proc_data['alternatives'][index][key])
|
||||
|
||||
return proc_data
|
||||
|
||||
|
||||
def parse(
|
||||
data: str,
|
||||
raw: bool = False,
|
||||
quiet: bool = False
|
||||
) -> Dict:
|
||||
"""
|
||||
Main text parsing function
|
||||
|
||||
Parameters:
|
||||
|
||||
data: (string) text data to parse
|
||||
raw: (boolean) unprocessed output if True
|
||||
quiet: (boolean) suppress warning messages if True
|
||||
|
||||
Returns:
|
||||
|
||||
Dictionary. Raw or processed structured data.
|
||||
"""
|
||||
jc.utils.compatibility(__name__, info.compatible, quiet)
|
||||
jc.utils.input_type_check(data)
|
||||
|
||||
raw_output: Dict = {}
|
||||
slaves: List = []
|
||||
alt_obj: Dict = {}
|
||||
|
||||
if jc.utils.has_data(data):
|
||||
|
||||
for line in filter(None, data.splitlines()):
|
||||
line_list = line.split(maxsplit=1)
|
||||
|
||||
if line.startswith('Name: '):
|
||||
raw_output['name'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Link: '):
|
||||
raw_output['link'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Slaves:'):
|
||||
continue
|
||||
|
||||
if line.startswith(' '):
|
||||
s_name = line_list[0].strip()
|
||||
s_path = line_list[1]
|
||||
slaves.append(
|
||||
{
|
||||
"name": s_name,
|
||||
"path": s_path
|
||||
}
|
||||
)
|
||||
continue
|
||||
|
||||
if line.startswith('Status: '):
|
||||
if slaves:
|
||||
raw_output['slaves'] = slaves
|
||||
slaves = []
|
||||
raw_output['status'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Best: '):
|
||||
raw_output['best'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Value: '):
|
||||
raw_output['value'] = line_list[1]
|
||||
continue
|
||||
|
||||
if line.startswith('Alternative: '):
|
||||
if not 'alternatives' in raw_output:
|
||||
raw_output['alternatives'] = []
|
||||
|
||||
if slaves:
|
||||
alt_obj['slaves'] = slaves
|
||||
raw_output['alternatives'].append(alt_obj)
|
||||
slaves = []
|
||||
|
||||
alt_obj = {"alternative": line_list[1]}
|
||||
continue
|
||||
|
||||
if line.startswith('Priority: '):
|
||||
alt_obj['priority'] = line_list[1]
|
||||
continue
|
||||
|
||||
if alt_obj:
|
||||
if slaves:
|
||||
alt_obj['slaves'] = slaves
|
||||
raw_output['alternatives'].append(alt_obj)
|
||||
|
||||
return raw_output if raw else _process(raw_output)
|
@ -49,7 +49,8 @@ Schema:
|
||||
"offset_width": integer,
|
||||
"offset_height": integer,
|
||||
"dimension_width": integer,
|
||||
"dimension_height": integer
|
||||
"dimension_height": integer,
|
||||
"rotation": string
|
||||
}
|
||||
],
|
||||
"unassociated_devices": [
|
||||
@ -125,7 +126,8 @@ Examples:
|
||||
"offset_width": 0,
|
||||
"offset_height": 0,
|
||||
"dimension_width": 310,
|
||||
"dimension_height": 170
|
||||
"dimension_height": 170,
|
||||
"rotation": "normal"
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -140,7 +142,7 @@ import jc.utils
|
||||
class info:
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
|
||||
version = "1.0"
|
||||
version = "1.1"
|
||||
description = "`xrandr` command parser"
|
||||
author = "Kevin Lyter"
|
||||
author_email = "lyter_git at sent.com"
|
||||
@ -252,6 +254,7 @@ _device_pattern = (
|
||||
+ "(?P<is_primary> primary)? ?"
|
||||
+ "((?P<resolution_width>\d+)x(?P<resolution_height>\d+)"
|
||||
+ "\+(?P<offset_width>\d+)\+(?P<offset_height>\d+))? "
|
||||
+ "(?P<rotation>(inverted|left|right))? ?"
|
||||
+ "\(normal left inverted right x axis y axis\)"
|
||||
+ "( ((?P<dimension_width>\d+)mm x (?P<dimension_height>\d+)mm)?)?"
|
||||
)
|
||||
@ -275,9 +278,10 @@ def _parse_device(next_lines: List[str], quiet: bool = False) -> Optional[Device
|
||||
"is_primary": matches["is_primary"] is not None
|
||||
and len(matches["is_primary"]) > 0,
|
||||
"device_name": matches["device_name"],
|
||||
"rotation": matches["rotation"] or "normal",
|
||||
}
|
||||
for k, v in matches.items():
|
||||
if k not in {"is_connected", "is_primary", "device_name"}:
|
||||
if k not in {"is_connected", "is_primary", "device_name", "rotation"}:
|
||||
try:
|
||||
if v:
|
||||
device[k] = int(v)
|
||||
|
@ -1,5 +1,7 @@
|
||||
"""jc - JSON Convert `YAML` file parser
|
||||
|
||||
Note: datetime objects will be converted to strings.
|
||||
|
||||
Usage (cli):
|
||||
|
||||
$ cat foo.yaml | jc --yaml
|
||||
@ -85,7 +87,7 @@ from jc.exceptions import LibraryNotInstalled
|
||||
|
||||
class info():
|
||||
"""Provides parser metadata (version, author, etc.)"""
|
||||
version = '1.6'
|
||||
version = '1.7'
|
||||
description = 'YAML file parser'
|
||||
author = 'Kelly Brazil'
|
||||
author_email = 'kellyjonbrazil@gmail.com'
|
||||
@ -147,6 +149,11 @@ def parse(data, raw=False, quiet=False):
|
||||
|
||||
yaml = YAML(typ='safe')
|
||||
|
||||
# modify the timestamp constructor to output datetime objects as
|
||||
# strings since JSON does not support datetime objects
|
||||
yaml.constructor.yaml_constructors['tag:yaml.org,2002:timestamp'] = \
|
||||
yaml.constructor.yaml_constructors['tag:yaml.org,2002:str']
|
||||
|
||||
for document in yaml.load_all(data):
|
||||
raw_output.append(document)
|
||||
|
||||
|
@ -6,7 +6,7 @@ import shutil
|
||||
from datetime import datetime, timezone
|
||||
from textwrap import TextWrapper
|
||||
from functools import lru_cache
|
||||
from typing import List, Tuple, Union, Optional
|
||||
from typing import List, Iterable, Union, Optional
|
||||
|
||||
|
||||
def warning_message(message_lines: List[str]) -> None:
|
||||
@ -233,7 +233,7 @@ def input_type_check(data: str) -> None:
|
||||
class timestamp:
|
||||
def __init__(self,
|
||||
datetime_string: str,
|
||||
format_hint: Union[List, Tuple, None] = None
|
||||
format_hint: Optional[Iterable] = None
|
||||
) -> None:
|
||||
"""
|
||||
Input a datetime text string of several formats and convert to a
|
||||
@ -244,7 +244,7 @@ class timestamp:
|
||||
datetime_string (str): a string representation of a
|
||||
datetime in several supported formats
|
||||
|
||||
format_hint (list | tuple): an optional list of format ID
|
||||
format_hint (iterable): an optional iterable of format ID
|
||||
integers to instruct the timestamp object to try those
|
||||
formats first in the order given. Other formats will be
|
||||
tried after the format hint list is exhausted. This can
|
||||
@ -361,6 +361,7 @@ class timestamp:
|
||||
|
||||
formats = [
|
||||
{'id': 1000, 'format': '%a %b %d %H:%M:%S %Y', 'locale': None}, # manual C locale format conversion: Tue Mar 23 16:12:11 2021 or Tue Mar 23 16:12:11 IST 2021
|
||||
{'id': 1100, 'format': '%a %b %d %H:%M:%S %Y %z', 'locale': None}, # git date output: Thu Mar 5 09:17:40 2020 -0800
|
||||
{'id': 1500, 'format': '%Y-%m-%d %H:%M', 'locale': None}, # en_US.UTF-8 local format (found in who cli output): 2021-03-23 00:14
|
||||
{'id': 1600, 'format': '%m/%d/%Y %I:%M %p', 'locale': None}, # Windows english format (found in dir cli output): 12/07/2019 02:09 AM
|
||||
{'id': 1700, 'format': '%m/%d/%Y, %I:%M:%S %p', 'locale': None}, # Windows english format wint non-UTC tz (found in systeminfo cli output): 3/22/2021, 1:15:51 PM (UTC-0600)
|
||||
|
17
man/jc.1
17
man/jc.1
@ -1,4 +1,4 @@
|
||||
.TH jc 1 2022-03-25 1.18.6 "JSON Convert"
|
||||
.TH jc 1 2022-04-25 1.18.7 "JSON Convert"
|
||||
.SH NAME
|
||||
jc \- JSONifies the output of many CLI tools and file-types
|
||||
.SH SYNOPSIS
|
||||
@ -137,6 +137,11 @@ CSV file streaming parser
|
||||
\fB--fstab\fP
|
||||
`/etc/fstab` file parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--git-log\fP
|
||||
`git log` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--group\fP
|
||||
@ -437,6 +442,16 @@ Key/Value file parser
|
||||
\fB--uname\fP
|
||||
`uname -a` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--update-alt-gs\fP
|
||||
`update-alternatives --get-selections` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--update-alt-q\fP
|
||||
`update-alternatives --query` command parser
|
||||
|
||||
.TP
|
||||
.B
|
||||
\fB--upower\fP
|
||||
|
2
setup.py
2
setup.py
@ -5,7 +5,7 @@ with open('README.md', 'r') as f:
|
||||
|
||||
setuptools.setup(
|
||||
name='jc',
|
||||
version='1.18.6',
|
||||
version='1.18.7',
|
||||
author='Kelly Brazil',
|
||||
author_email='kellyjonbrazil@gmail.com',
|
||||
description='Converts the output of popular command-line tools and file-types to JSON.',
|
||||
|
@ -107,11 +107,11 @@ pip3 install jc
|
||||
### OS Package Repositories
|
||||
|
||||
| OS | Command |
|
||||
|-----------------------|-------------------------------------------------------------------------------|
|
||||
|--------------------------------------|-------------------------------------------------------------------------------|
|
||||
| Debian/Ubuntu linux | `apt-get install jc` |
|
||||
| Fedora linux | `dnf install jc` |
|
||||
| openSUSE linux | `zypper install jc` |
|
||||
| Arch linux | `pacman -S jc` |
|
||||
| Archlinux User Repositories (AUR) | `paru -S jc` or `aura -A jc` or `yay -S jc` |
|
||||
| NixOS linux | `nix-env -iA nixpkgs.jc` or `nix-env -iA nixos.jc` |
|
||||
| Guix System linux | `guix install jc` |
|
||||
| macOS | `brew install jc` |
|
||||
@ -305,9 +305,9 @@ Local parser plugins are standard python module files. Use the
|
||||
or [`jc/parsers/foo_s.py (streaming)`](https://github.com/kellyjonbrazil/jc/blob/master/jc/parsers/foo_s.py)
|
||||
parser as a template and simply place a `.py` file in the `jcparsers` subfolder.
|
||||
|
||||
Local plugin filenames must be valid python module names, therefore must consist
|
||||
entirely of alphanumerics and start with a letter. Local plugins may override
|
||||
default parsers.
|
||||
Local plugin filenames must be valid python module names and therefore must
|
||||
start with a letter and consist entirely of alphanumerics. Local plugins
|
||||
may override default parsers.
|
||||
|
||||
> Note: The application data directory follows the
|
||||
[XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html)
|
||||
|
1
tests/fixtures/generic/git-log-full-shortstat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-full-shortstat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
19602
tests/fixtures/generic/git-log-full-shortstat.out
vendored
Normal file
19602
tests/fixtures/generic/git-log-full-shortstat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-full-stat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-full-stat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
28851
tests/fixtures/generic/git-log-full-stat.out
vendored
Normal file
28851
tests/fixtures/generic/git-log-full-stat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-full.json
vendored
Normal file
1
tests/fixtures/generic/git-log-full.json
vendored
Normal file
File diff suppressed because one or more lines are too long
14966
tests/fixtures/generic/git-log-full.out
vendored
Normal file
14966
tests/fixtures/generic/git-log-full.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-fuller-shortstat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-fuller-shortstat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
24468
tests/fixtures/generic/git-log-fuller-shortstat.out
vendored
Normal file
24468
tests/fixtures/generic/git-log-fuller-shortstat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-fuller-stat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-fuller-stat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
33717
tests/fixtures/generic/git-log-fuller-stat.out
vendored
Normal file
33717
tests/fixtures/generic/git-log-fuller-stat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-fuller.json
vendored
Normal file
1
tests/fixtures/generic/git-log-fuller.json
vendored
Normal file
File diff suppressed because one or more lines are too long
19832
tests/fixtures/generic/git-log-fuller.out
vendored
Normal file
19832
tests/fixtures/generic/git-log-fuller.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-medium-shortstat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-medium-shortstat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
19602
tests/fixtures/generic/git-log-medium-shortstat.out
vendored
Normal file
19602
tests/fixtures/generic/git-log-medium-shortstat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-medium-stat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-medium-stat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
28851
tests/fixtures/generic/git-log-medium-stat.out
vendored
Normal file
28851
tests/fixtures/generic/git-log-medium-stat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-medium.json
vendored
Normal file
1
tests/fixtures/generic/git-log-medium.json
vendored
Normal file
File diff suppressed because one or more lines are too long
14966
tests/fixtures/generic/git-log-medium.out
vendored
Normal file
14966
tests/fixtures/generic/git-log-medium.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-oneline-shortstat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-oneline-shortstat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
4751
tests/fixtures/generic/git-log-oneline-shortstat.out
vendored
Normal file
4751
tests/fixtures/generic/git-log-oneline-shortstat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-oneline-stat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-oneline-stat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
14000
tests/fixtures/generic/git-log-oneline-stat.out
vendored
Normal file
14000
tests/fixtures/generic/git-log-oneline-stat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-oneline.json
vendored
Normal file
1
tests/fixtures/generic/git-log-oneline.json
vendored
Normal file
File diff suppressed because one or more lines are too long
2433
tests/fixtures/generic/git-log-oneline.out
vendored
Normal file
2433
tests/fixtures/generic/git-log-oneline.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-short-shortstat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-short-shortstat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
16916
tests/fixtures/generic/git-log-short-shortstat.out
vendored
Normal file
16916
tests/fixtures/generic/git-log-short-shortstat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-short-stat.json
vendored
Normal file
1
tests/fixtures/generic/git-log-short-stat.json
vendored
Normal file
File diff suppressed because one or more lines are too long
26165
tests/fixtures/generic/git-log-short-stat.out
vendored
Normal file
26165
tests/fixtures/generic/git-log-short-stat.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log-short.json
vendored
Normal file
1
tests/fixtures/generic/git-log-short.json
vendored
Normal file
File diff suppressed because one or more lines are too long
12280
tests/fixtures/generic/git-log-short.out
vendored
Normal file
12280
tests/fixtures/generic/git-log-short.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/git-log.json
vendored
Normal file
1
tests/fixtures/generic/git-log.json
vendored
Normal file
File diff suppressed because one or more lines are too long
14966
tests/fixtures/generic/git-log.out
vendored
Normal file
14966
tests/fixtures/generic/git-log.out
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
tests/fixtures/generic/update-alternatives-get-selections.json
vendored
Normal file
1
tests/fixtures/generic/update-alternatives-get-selections.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
[{"name":"arptables","status":"auto","current":"/usr/sbin/arptables-nft"},{"name":"awk","status":"auto","current":"/usr/bin/gawk"},{"name":"builtins.7.gz","status":"auto","current":"/usr/share/man/man7/bash-builtins.7.gz"},{"name":"c++","status":"auto","current":"/usr/bin/g++"},{"name":"c89","status":"auto","current":"/usr/bin/c89-gcc"},{"name":"c99","status":"auto","current":"/usr/bin/c99-gcc"},{"name":"cc","status":"auto","current":"/usr/bin/gcc"},{"name":"cpp","status":"auto","current":"/usr/bin/cpp"},{"name":"ebtables","status":"auto","current":"/usr/sbin/ebtables-nft"},{"name":"editor","status":"auto","current":"/bin/nano"},{"name":"ex","status":"auto","current":"/usr/bin/vim.basic"},{"name":"fakeroot","status":"auto","current":"/usr/bin/fakeroot-sysv"},{"name":"ftp","status":"auto","current":"/usr/bin/netkit-ftp"},{"name":"infobrowser","status":"auto","current":"/usr/bin/info"},{"name":"ip6tables","status":"auto","current":"/usr/sbin/ip6tables-nft"},{"name":"iptables","status":"auto","current":"/usr/sbin/iptables-nft"},{"name":"jsondiff","status":"auto","current":"/usr/bin/json-patch-jsondiff"},{"name":"lzma","status":"auto","current":"/usr/bin/xz"},{"name":"mt","status":"auto","current":"/bin/mt-gnu"},{"name":"nc","status":"auto","current":"/bin/nc.openbsd"},{"name":"newt-palette","status":"auto","current":"/etc/newt/palette.ubuntu"},{"name":"pager","status":"auto","current":"/usr/bin/less"},{"name":"pico","status":"auto","current":"/bin/nano"},{"name":"pinentry","status":"auto","current":"/usr/bin/pinentry-curses"},{"name":"rcp","status":"auto","current":"/usr/bin/scp"},{"name":"rlogin","status":"auto","current":"/usr/bin/slogin"},{"name":"rmt","status":"auto","current":"/usr/sbin/rmt-tar"},{"name":"rsh","status":"auto","current":"/usr/bin/ssh"},{"name":"rview","status":"auto","current":"/usr/bin/vim.basic"},{"name":"rvim","status":"auto","current":"/usr/bin/vim.basic"},{"name":"sar","status":"auto","current":"/usr/bin/sar.sysstat"},{"name":"telnet","status":"auto","current":"/usr/bin/telnet.netkit"},{"name":"text.plymouth","status":"auto","current":"/usr/share/plymouth/themes/ubuntu-text/ubuntu-text.plymouth"},{"name":"traceroute6","status":"auto","current":"/usr/bin/traceroute6.iputils"},{"name":"vi","status":"auto","current":"/usr/bin/vim.basic"},{"name":"view","status":"auto","current":"/usr/bin/vim.basic"},{"name":"vim","status":"auto","current":"/usr/bin/vim.basic"},{"name":"vimdiff","status":"auto","current":"/usr/bin/vim.basic"},{"name":"vtrgb","status":"auto","current":"/etc/console-setup/vtrgb"},{"name":"w","status":"auto","current":"/usr/bin/w.procps"},{"name":"write","status":"auto","current":"/usr/bin/write.ul"}]
|
41
tests/fixtures/generic/update-alternatives-get-selections.out
vendored
Normal file
41
tests/fixtures/generic/update-alternatives-get-selections.out
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
arptables auto /usr/sbin/arptables-nft
|
||||
awk auto /usr/bin/gawk
|
||||
builtins.7.gz auto /usr/share/man/man7/bash-builtins.7.gz
|
||||
c++ auto /usr/bin/g++
|
||||
c89 auto /usr/bin/c89-gcc
|
||||
c99 auto /usr/bin/c99-gcc
|
||||
cc auto /usr/bin/gcc
|
||||
cpp auto /usr/bin/cpp
|
||||
ebtables auto /usr/sbin/ebtables-nft
|
||||
editor auto /bin/nano
|
||||
ex auto /usr/bin/vim.basic
|
||||
fakeroot auto /usr/bin/fakeroot-sysv
|
||||
ftp auto /usr/bin/netkit-ftp
|
||||
infobrowser auto /usr/bin/info
|
||||
ip6tables auto /usr/sbin/ip6tables-nft
|
||||
iptables auto /usr/sbin/iptables-nft
|
||||
jsondiff auto /usr/bin/json-patch-jsondiff
|
||||
lzma auto /usr/bin/xz
|
||||
mt auto /bin/mt-gnu
|
||||
nc auto /bin/nc.openbsd
|
||||
newt-palette auto /etc/newt/palette.ubuntu
|
||||
pager auto /usr/bin/less
|
||||
pico auto /bin/nano
|
||||
pinentry auto /usr/bin/pinentry-curses
|
||||
rcp auto /usr/bin/scp
|
||||
rlogin auto /usr/bin/slogin
|
||||
rmt auto /usr/sbin/rmt-tar
|
||||
rsh auto /usr/bin/ssh
|
||||
rview auto /usr/bin/vim.basic
|
||||
rvim auto /usr/bin/vim.basic
|
||||
sar auto /usr/bin/sar.sysstat
|
||||
telnet auto /usr/bin/telnet.netkit
|
||||
text.plymouth auto /usr/share/plymouth/themes/ubuntu-text/ubuntu-text.plymouth
|
||||
traceroute6 auto /usr/bin/traceroute6.iputils
|
||||
vi auto /usr/bin/vim.basic
|
||||
view auto /usr/bin/vim.basic
|
||||
vim auto /usr/bin/vim.basic
|
||||
vimdiff auto /usr/bin/vim.basic
|
||||
vtrgb auto /etc/console-setup/vtrgb
|
||||
w auto /usr/bin/w.procps
|
||||
write auto /usr/bin/write.ul
|
1
tests/fixtures/generic/update-alternatives-query.json
vendored
Normal file
1
tests/fixtures/generic/update-alternatives-query.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"name":"editor","link":"/usr/bin/editor","slaves":[{"name":"editor.1.gz","path":"/usr/share/man/man1/editor.1.gz"},{"name":"editor.da.1.gz","path":"/usr/share/man/da/man1/editor.1.gz"},{"name":"editor.de.1.gz","path":"/usr/share/man/de/man1/editor.1.gz"},{"name":"editor.fr.1.gz","path":"/usr/share/man/fr/man1/editor.1.gz"},{"name":"editor.it.1.gz","path":"/usr/share/man/it/man1/editor.1.gz"},{"name":"editor.ja.1.gz","path":"/usr/share/man/ja/man1/editor.1.gz"},{"name":"editor.pl.1.gz","path":"/usr/share/man/pl/man1/editor.1.gz"},{"name":"editor.ru.1.gz","path":"/usr/share/man/ru/man1/editor.1.gz"}],"status":"auto","best":"/bin/nano","value":"/bin/nano","alternatives":[{"alternative":"/bin/ed","priority":-100,"slaves":[{"name":"editor.1.gz","path":"/usr/share/man/man1/ed.1.gz"}]},{"alternative":"/bin/nano","priority":40,"slaves":[{"name":"editor.1.gz","path":"/usr/share/man/man1/nano.1.gz"}]},{"alternative":"/usr/bin/vim.basic","priority":30,"slaves":[{"name":"editor.1.gz","path":"/usr/share/man/man1/vim.1.gz"},{"name":"editor.da.1.gz","path":"/usr/share/man/da/man1/vim.1.gz"},{"name":"editor.de.1.gz","path":"/usr/share/man/de/man1/vim.1.gz"},{"name":"editor.fr.1.gz","path":"/usr/share/man/fr/man1/vim.1.gz"},{"name":"editor.it.1.gz","path":"/usr/share/man/it/man1/vim.1.gz"},{"name":"editor.ja.1.gz","path":"/usr/share/man/ja/man1/vim.1.gz"},{"name":"editor.pl.1.gz","path":"/usr/share/man/pl/man1/vim.1.gz"},{"name":"editor.ru.1.gz","path":"/usr/share/man/ru/man1/vim.1.gz"}]},{"alternative":"/usr/bin/vim.tiny","priority":15,"slaves":[{"name":"editor.1.gz","path":"/usr/share/man/man1/vim.1.gz"},{"name":"editor.da.1.gz","path":"/usr/share/man/da/man1/vim.1.gz"},{"name":"editor.de.1.gz","path":"/usr/share/man/de/man1/vim.1.gz"},{"name":"editor.fr.1.gz","path":"/usr/share/man/fr/man1/vim.1.gz"},{"name":"editor.it.1.gz","path":"/usr/share/man/it/man1/vim.1.gz"},{"name":"editor.ja.1.gz","path":"/usr/share/man/ja/man1/vim.1.gz"},{"name":"editor.pl.1.gz","path":"/usr/share/man/pl/man1/vim.1.gz"},{"name":"editor.ru.1.gz","path":"/usr/share/man/ru/man1/vim.1.gz"}]}]}
|
48
tests/fixtures/generic/update-alternatives-query.out
vendored
Normal file
48
tests/fixtures/generic/update-alternatives-query.out
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
Name: editor
|
||||
Link: /usr/bin/editor
|
||||
Slaves:
|
||||
editor.1.gz /usr/share/man/man1/editor.1.gz
|
||||
editor.da.1.gz /usr/share/man/da/man1/editor.1.gz
|
||||
editor.de.1.gz /usr/share/man/de/man1/editor.1.gz
|
||||
editor.fr.1.gz /usr/share/man/fr/man1/editor.1.gz
|
||||
editor.it.1.gz /usr/share/man/it/man1/editor.1.gz
|
||||
editor.ja.1.gz /usr/share/man/ja/man1/editor.1.gz
|
||||
editor.pl.1.gz /usr/share/man/pl/man1/editor.1.gz
|
||||
editor.ru.1.gz /usr/share/man/ru/man1/editor.1.gz
|
||||
Status: auto
|
||||
Best: /bin/nano
|
||||
Value: /bin/nano
|
||||
|
||||
Alternative: /bin/ed
|
||||
Priority: -100
|
||||
Slaves:
|
||||
editor.1.gz /usr/share/man/man1/ed.1.gz
|
||||
|
||||
Alternative: /bin/nano
|
||||
Priority: 40
|
||||
Slaves:
|
||||
editor.1.gz /usr/share/man/man1/nano.1.gz
|
||||
|
||||
Alternative: /usr/bin/vim.basic
|
||||
Priority: 30
|
||||
Slaves:
|
||||
editor.1.gz /usr/share/man/man1/vim.1.gz
|
||||
editor.da.1.gz /usr/share/man/da/man1/vim.1.gz
|
||||
editor.de.1.gz /usr/share/man/de/man1/vim.1.gz
|
||||
editor.fr.1.gz /usr/share/man/fr/man1/vim.1.gz
|
||||
editor.it.1.gz /usr/share/man/it/man1/vim.1.gz
|
||||
editor.ja.1.gz /usr/share/man/ja/man1/vim.1.gz
|
||||
editor.pl.1.gz /usr/share/man/pl/man1/vim.1.gz
|
||||
editor.ru.1.gz /usr/share/man/ru/man1/vim.1.gz
|
||||
|
||||
Alternative: /usr/bin/vim.tiny
|
||||
Priority: 15
|
||||
Slaves:
|
||||
editor.1.gz /usr/share/man/man1/vim.1.gz
|
||||
editor.da.1.gz /usr/share/man/da/man1/vim.1.gz
|
||||
editor.de.1.gz /usr/share/man/de/man1/vim.1.gz
|
||||
editor.fr.1.gz /usr/share/man/fr/man1/vim.1.gz
|
||||
editor.it.1.gz /usr/share/man/it/man1/vim.1.gz
|
||||
editor.ja.1.gz /usr/share/man/ja/man1/vim.1.gz
|
||||
editor.pl.1.gz /usr/share/man/pl/man1/vim.1.gz
|
||||
editor.ru.1.gz /usr/share/man/ru/man1/vim.1.gz
|
1
tests/fixtures/generic/xrandr_simple.json
vendored
1
tests/fixtures/generic/xrandr_simple.json
vendored
@ -43,6 +43,7 @@
|
||||
"is_connected": true,
|
||||
"is_primary": true,
|
||||
"device_name": "eDP1",
|
||||
"rotation": "normal",
|
||||
"resolution_width": 1920,
|
||||
"resolution_height": 1080,
|
||||
"offset_width": 0,
|
||||
|
215
tests/test_git_log.py
Normal file
215
tests/test_git_log.py
Normal file
@ -0,0 +1,215 @@
|
||||
import os
|
||||
import unittest
|
||||
import json
|
||||
import jc.parsers.git_log
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class MyTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# input
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-short.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_short = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-short-stat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_short_stat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-short-shortstat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_short_shortstat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-medium.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_medium = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-medium-stat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_medium_stat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-medium-shortstat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_medium_shortstat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-full.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_full = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-full-stat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_full_stat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-full-shortstat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_full_shortstat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-fuller.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_fuller = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-fuller-stat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_fuller_stat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-fuller-shortstat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_fuller_shortstat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-oneline.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_oneline = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-oneline-stat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_oneline_stat = f.read()
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-oneline-shortstat.out'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_oneline_shortstat = f.read()
|
||||
|
||||
# output
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-short.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_short_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-short-stat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_short_stat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-short-shortstat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_short_shortstat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-medium.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_medium_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-medium-stat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_medium_stat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-medium-shortstat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_medium_shortstat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-full.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_full_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-full-stat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_full_stat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-full-shortstat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_full_shortstat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-fuller.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_fuller_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-fuller-stat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_fuller_stat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-fuller-shortstat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_fuller_shortstat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-oneline.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_oneline_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-oneline-stat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_oneline_stat_json = json.loads(f.read())
|
||||
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/git-log-oneline-shortstat.json'), 'r', encoding='utf-8') as f:
|
||||
self.git_log_oneline_shortstat_json = json.loads(f.read())
|
||||
|
||||
|
||||
def test_git_log_nodata(self):
|
||||
"""
|
||||
Test 'git_log' with no data
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse('', quiet=True), [])
|
||||
|
||||
def test_git_log(self):
|
||||
"""
|
||||
Test 'git_log'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log, quiet=True), self.git_log_json)
|
||||
|
||||
def test_git_log_short(self):
|
||||
"""
|
||||
Test 'git_log --format=short'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_short, quiet=True), self.git_log_short_json)
|
||||
|
||||
def test_git_log_short_stat(self):
|
||||
"""
|
||||
Test 'git_log --format=short --stat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_short_stat, quiet=True), self.git_log_short_stat_json)
|
||||
|
||||
def test_git_log_short_shortstat(self):
|
||||
"""
|
||||
Test 'git_log --format=short --shortstat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_short_shortstat, quiet=True), self.git_log_short_shortstat_json)
|
||||
|
||||
def test_git_log_medium(self):
|
||||
"""
|
||||
Test 'git_log --format=medium'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_medium, quiet=True), self.git_log_medium_json)
|
||||
|
||||
def test_git_log_medium_stat(self):
|
||||
"""
|
||||
Test 'git_log --format=medium --stat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_medium_stat, quiet=True), self.git_log_medium_stat_json)
|
||||
|
||||
def test_git_log_medium_shortstat(self):
|
||||
"""
|
||||
Test 'git_log --format=medium --shortstat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_medium_shortstat, quiet=True), self.git_log_medium_shortstat_json)
|
||||
|
||||
def test_git_log_full(self):
|
||||
"""
|
||||
Test 'git_log --format=full'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_full, quiet=True), self.git_log_full_json)
|
||||
|
||||
def test_git_log_full_stat(self):
|
||||
"""
|
||||
Test 'git_log --format=full --stat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_full_stat, quiet=True), self.git_log_full_stat_json)
|
||||
|
||||
def test_git_log_full_shortstat(self):
|
||||
"""
|
||||
Test 'git_log --format=full --shortstat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_full_shortstat, quiet=True), self.git_log_full_shortstat_json)
|
||||
|
||||
def test_git_log_fuller(self):
|
||||
"""
|
||||
Test 'git_log --format=fuller'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_fuller, quiet=True), self.git_log_fuller_json)
|
||||
|
||||
def test_git_log_fuller_stat(self):
|
||||
"""
|
||||
Test 'git_log --format=fuller --stat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_fuller_stat, quiet=True), self.git_log_fuller_stat_json)
|
||||
|
||||
def test_git_log_fuller_shortstat(self):
|
||||
"""
|
||||
Test 'git_log --format=fuller --shortstat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_fuller_shortstat, quiet=True), self.git_log_fuller_shortstat_json)
|
||||
|
||||
def test_git_log_oneline(self):
|
||||
"""
|
||||
Test 'git_log --format=oneline'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_oneline, quiet=True), self.git_log_oneline_json)
|
||||
|
||||
def test_git_log_oneline_stat(self):
|
||||
"""
|
||||
Test 'git_log --format=oneline --stat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_oneline_stat, quiet=True), self.git_log_oneline_stat_json)
|
||||
|
||||
def test_git_log_oneline_shortstat(self):
|
||||
"""
|
||||
Test 'git_log --format=oneline --shortstat'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.git_log.parse(self.git_log_oneline_shortstat, quiet=True), self.git_log_oneline_shortstat_json)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -41,6 +41,18 @@ class MyTests(unittest.TestCase):
|
||||
"""
|
||||
self.assertEqual(jc.parsers.ini.parse(self.generic_ini_iptelserver, quiet=True), self.generic_ini_iptelserver_json)
|
||||
|
||||
def test_ini_duplicate_keys(self):
|
||||
"""
|
||||
Test input that contains duplicate keys. Only the last value should be used.
|
||||
"""
|
||||
data = '''
|
||||
duplicate_key: value1
|
||||
another_key = foo
|
||||
duplicate_key = value2
|
||||
'''
|
||||
expected = {'duplicate_key': 'value2', 'another_key': 'foo'}
|
||||
self.assertEqual(jc.parsers.ini.parse(data, quiet=True), expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -41,6 +41,18 @@ class MyTests(unittest.TestCase):
|
||||
"""
|
||||
self.assertEqual(jc.parsers.kv.parse(self.generic_ini_keyvalue_ifcfg, quiet=True), self.generic_ini_keyvalue_ifcfg_json)
|
||||
|
||||
def test_kv_duplicate_keys(self):
|
||||
"""
|
||||
Test input that contains duplicate keys. Only the last value should be used.
|
||||
"""
|
||||
data = '''
|
||||
duplicate_key: value1
|
||||
another_key = foo
|
||||
duplicate_key = value2
|
||||
'''
|
||||
expected = {'duplicate_key': 'value2', 'another_key': 'foo'}
|
||||
self.assertEqual(jc.parsers.kv.parse(data, quiet=True), expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
35
tests/test_update_alt_gs.py
Normal file
35
tests/test_update_alt_gs.py
Normal file
@ -0,0 +1,35 @@
|
||||
import os
|
||||
import unittest
|
||||
import json
|
||||
import jc.parsers.update_alt_gs
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class MyTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# input
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/update-alternatives-get-selections.out'), 'r', encoding='utf-8') as f:
|
||||
self.update_alternatives_get_selections = f.read()
|
||||
|
||||
# output
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/update-alternatives-get-selections.json'), 'r', encoding='utf-8') as f:
|
||||
self.update_alternatives_get_selections_json = json.loads(f.read())
|
||||
|
||||
|
||||
def test_update_alt_gs_nodata(self):
|
||||
"""
|
||||
Test 'update-alternatives --get-selections' with no data
|
||||
"""
|
||||
self.assertEqual(jc.parsers.update_alt_gs.parse('', quiet=True), [])
|
||||
|
||||
def test_update_alt_gs(self):
|
||||
"""
|
||||
Test 'update-alternatives --get-selections'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.update_alt_gs.parse(self.update_alternatives_get_selections, quiet=True), self.update_alternatives_get_selections_json)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
35
tests/test_update_alt_q.py
Normal file
35
tests/test_update_alt_q.py
Normal file
@ -0,0 +1,35 @@
|
||||
import os
|
||||
import unittest
|
||||
import json
|
||||
import jc.parsers.update_alt_q
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
class MyTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# input
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/update-alternatives-query.out'), 'r', encoding='utf-8') as f:
|
||||
self.update_alternatives_query = f.read()
|
||||
|
||||
# output
|
||||
with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/update-alternatives-query.json'), 'r', encoding='utf-8') as f:
|
||||
self.update_alternatives_query_json = json.loads(f.read())
|
||||
|
||||
|
||||
def test_update_alt_q_nodata(self):
|
||||
"""
|
||||
Test 'update-alternatives --query' with no data
|
||||
"""
|
||||
self.assertEqual(jc.parsers.update_alt_q.parse('', quiet=True), {})
|
||||
|
||||
def test_update_alt_q(self):
|
||||
"""
|
||||
Test 'update-alternatives --query'
|
||||
"""
|
||||
self.assertEqual(jc.parsers.update_alt_q.parse(self.update_alternatives_query, quiet=True), self.update_alternatives_query_json)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -30,7 +30,8 @@ class XrandrTests(unittest.TestCase):
|
||||
"HDMI1 connected (normal left inverted right x axis y axis)",
|
||||
"VIRTUAL1 disconnected (normal left inverted right x axis y axis)",
|
||||
"eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm",
|
||||
"eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 309mm x 174mm"
|
||||
"eDP-1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 309mm x 174mm",
|
||||
"HDMI-0 connected 2160x3840+3840+0 right (normal left inverted right x axis y axis) 609mm x 349mm",
|
||||
]
|
||||
for device in devices:
|
||||
self.assertIsNotNone(re.match(_device_pattern, device))
|
||||
@ -85,7 +86,7 @@ class XrandrTests(unittest.TestCase):
|
||||
|
||||
def test_device(self):
|
||||
# regex101 sample link for tests/edits https://regex101.com/r/3cHMv3/1
|
||||
sample = "eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 310mm x 170mm"
|
||||
sample = "eDP1 connected primary 1920x1080+0+0 left (normal left inverted right x axis y axis) 310mm x 170mm"
|
||||
actual: Optional[Device] = _parse_device([sample])
|
||||
|
||||
expected = {
|
||||
@ -98,6 +99,7 @@ class XrandrTests(unittest.TestCase):
|
||||
"offset_height": 0,
|
||||
"dimension_width": 310,
|
||||
"dimension_height": 170,
|
||||
"rotation": "left",
|
||||
}
|
||||
|
||||
self.assertIsNotNone(actual)
|
||||
|
@ -41,6 +41,14 @@ class MyTests(unittest.TestCase):
|
||||
"""
|
||||
self.assertEqual(jc.parsers.yaml.parse(self.generic_yaml_istio_sidecar, quiet=True), self.generic_yaml_istio_sidecar_json)
|
||||
|
||||
def test_yaml_datetime(self):
|
||||
"""
|
||||
Test yaml file with datetime object (should convert to a string)
|
||||
"""
|
||||
data = 'deploymentTime: 2022-04-18T11:12:47'
|
||||
expected = [{"deploymentTime":"2022-04-18T11:12:47"}]
|
||||
self.assertEqual(jc.parsers.yaml.parse(data, quiet=True), expected)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -1,11 +1,21 @@
|
||||
#!/bin/bash
|
||||
# Update all documentation (README.md, Man page, Doc files)
|
||||
|
||||
echo === Building README.md
|
||||
./readmegen.py && echo "+++ README.md build successful" || echo "--- README.md build failed"
|
||||
(
|
||||
echo === Building README.md
|
||||
./readmegen.py && echo "++++ README.md build successful" || echo "---- README.md build failed"
|
||||
) &
|
||||
|
||||
echo === Building man page
|
||||
./mangen.py && echo "+++ man page build successful" || echo "--- man page build failed"
|
||||
(
|
||||
echo === Building man page
|
||||
./mangen.py && echo "++++ man page build successful" || echo "---- man page build failed"
|
||||
) &
|
||||
|
||||
echo === Building documentation
|
||||
./docgen.sh && echo "+++ documentation build successful" || echo "--- documentation build failed"
|
||||
(
|
||||
echo === Building documentation
|
||||
./docgen.sh && echo "++++ documentation build successful" || echo "---- documentation build failed"
|
||||
) &
|
||||
|
||||
wait
|
||||
echo
|
||||
echo "All documentation updated"
|
||||
|
Reference in New Issue
Block a user