Skip to content

Commit

Permalink
Add nicer default output for info command
Browse files Browse the repository at this point in the history
  • Loading branch information
AT0myks committed Jul 15, 2023
1 parent fa72185 commit 34bce78
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 10 deletions.
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,39 @@ provided on PyPI.
#### Info

```
$ reolinkfw info file_or_url
usage: reolinkfw info [-h] [--no-cache] [-j [indent]] file_or_url
positional arguments:
file_or_url URL or on-disk file
optional arguments:
-h, --help show this help message and exit
--no-cache don't use cache for remote files (URLs)
-j [indent], --json [indent] JSON output with optional indentation level for pretty print
```

Example:

```
$ reolinkfw info RLC-410-5MP_20_20052300.zip -i 2
$ reolinkfw info RLC-410-5MP_20_20052300.zip
IPC_51516M5M.20_20052300.RLC-410-5MP.OV05A10.5MP.REOLINK.pak
Model: RLC-410-5MP
Hardware info: IPC_51516M5M
Device type: IPC
Firmware version: v3.0.0.20_20052300
Build date: 2020-05-23
Architecture: MIPS
OS: Linux
Kernel image name: Linux-4.1.0
U-Boot version: U-Boot 2014.07 (Feb 26 2019 - 18:20:07)
File system: squashfs
File system sections: fs
```

Or with JSON output:

```
$ reolinkfw info RLC-410-5MP_20_20052300.zip -j 2
[
{
"firmware_version_prefix": "v3.0.0",
Expand Down
44 changes: 36 additions & 8 deletions reolinkfw/__main__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,50 @@
#!/usr/bin/env python3

import argparse
import asyncio
import json
import sys
from argparse import ArgumentParser, Namespace
from datetime import datetime
from pathlib import Path, PurePath

from reolinkfw import __version__, get_info, get_paks
from reolinkfw.extract import extract_pak
from reolinkfw.util import sha256_pak

HW_FIELDS = ("board_type", "detail_machine_type", "board_name")

async def info(args: argparse.Namespace) -> None:
info = await get_info(args.file_or_url, not args.no_cache)
print(json.dumps(info, indent=args.indent, default=str))

async def info(args: Namespace) -> None:
pak_infos = await get_info(args.file_or_url, not args.no_cache)
if args.json is None:
width = 21
for idx, info in enumerate(pak_infos):
info = Namespace(**info)
fs_types = set(fs["type"] for fs in info.filesystems)
fs_names = [fs["name"] for fs in info.filesystems]
version = f"{info.firmware_version_prefix}.{info.version_file}"
hw_names = set(getattr(info, key) for key in HW_FIELDS)
build_date = datetime.strptime(info.build_date, "%y%m%d").date()
print(info.pak)
print(f"{'Model:':{width}}", info.display_type_info)
print(f"{'Hardware info:':{width}}", ', '.join(sorted(hw_names)))
print(f"{'Device type:':{width}}", info.type)
print(f"{'Firmware version:':{width}}", version)
print(f"{'Build date:':{width}}", build_date)
print(f"{'Architecture:':{width}}", info.architecture)
print(f"{'OS:':{width}}", info.os)
print(f"{'Kernel image name:':{width}}", info.kernel_image_name)
print(f"{'U-Boot version:':{width}}", info.uboot_version or "Unknown")
print(f"{'File system:':{width}}", ', '.join(sorted(fs_types)))
print(f"{'File system sections:':{width}}", ', '.join(fs_names))
if idx != len(pak_infos) - 1:
print()
else:
indent = None if args.json < 0 else args.json
print(json.dumps(pak_infos, indent=indent, default=str))

async def extract(args: argparse.Namespace) -> None:

async def extract(args: Namespace) -> None:
paks = await get_paks(args.file_or_url, not args.no_cache)
if not paks:
raise Exception("No PAKs found in ZIP file")
Expand All @@ -28,16 +56,16 @@ async def extract(args: argparse.Namespace) -> None:


def main():
parser = argparse.ArgumentParser(description="Extract information and files from Reolink firmwares")
parser = ArgumentParser(description="Extract information and files from Reolink firmwares")
parser.add_argument("-V", "--version", action="version", version=f"%(prog)s {__version__}")
subparsers = parser.add_subparsers(required=True)

pcache = argparse.ArgumentParser(add_help=False)
pcache = ArgumentParser(add_help=False)
pcache.add_argument("--no-cache", action="store_true", help="don't use cache for remote files (URLs)")

parser_i = subparsers.add_parser("info", parents=[pcache])
parser_i.add_argument("file_or_url", help="URL or on-disk file")
parser_i.add_argument("-i", "--indent", type=int, help="indent level for pretty print")
parser_i.add_argument("-j", "--json", nargs='?', type=int, const=-1, metavar="indent", help="JSON output with optional indentation level for pretty print")
parser_i.set_defaults(func=info)

descex = "Extract the file system from a Reolink firmware"
Expand Down

0 comments on commit 34bce78

Please sign in to comment.