From d3d10f870dcc164da1116d40a8b055dfdab96b71 Mon Sep 17 00:00:00 2001 From: Shararamosh Date: Thu, 22 Aug 2024 20:37:12 +0300 Subject: [PATCH] Added batch folder deserialization and support for argparse arguments to both executables. --- .github/workflows/build_executable.yml | 5 +- flatc_deserializer.py | 18 ++- flatc_deserializer_batch.py | 27 ++++ images/flatbuffers-batch-logo-clean.png | Bin 0 -> 51015 bytes localization/en_US/flatc_download_funcs.yml | 2 +- localization/en_US/main.yml | 17 ++- localization/ru_RU/flatc_download_funcs.yml | 2 +- localization/ru_RU/main.yml | 13 +- main.py | 131 +++++++++++++++++--- 9 files changed, 189 insertions(+), 26 deletions(-) create mode 100644 flatc_deserializer_batch.py create mode 100644 images/flatbuffers-batch-logo-clean.png diff --git a/.github/workflows/build_executable.yml b/.github/workflows/build_executable.yml index feacc47..dfbc702 100644 --- a/.github/workflows/build_executable.yml +++ b/.github/workflows/build_executable.yml @@ -20,10 +20,12 @@ jobs: run: | pyinstaller --onefile --name="flatc_deserializer" --console --icon=images\flatbuffers-logo-clean.png --add-data="images:images" --add-data="localization:localization" flatc_deserializer.py pyinstaller --onefile --name="flatc_downloader" --console --icon=images\flatbuffers-downloader-logo-clean.png --add-data="images:images" --add-data="localization:localization" flatc_downloader.py + pyinstaller --onefile --name="flatc_deserializer_batch" --console --icon=images\flatbuffers-batch-logo-clean.png --add-data="images:images" --add-data="localization:localization" flatc_deserializer_batch.py - name: Move Deserializer and Downloader Executables from dist to root directory and delete dist directory run: | move dist\flatc_deserializer.exe . move dist\flatc_downloader.exe . + move dist\flatc_deserializer_batch.exe . rd /s /q dist shell: cmd - name: Create Automatic Windows Release @@ -35,4 +37,5 @@ jobs: title: Latest Build files: | flatc_deserializer.exe - flatc_downloader.exe \ No newline at end of file + flatc_downloader.exe + flatc_deserializer_batch.exe \ No newline at end of file diff --git a/flatc_deserializer.py b/flatc_deserializer.py index ebbb123..f74a25d 100644 --- a/flatc_deserializer.py +++ b/flatc_deserializer.py @@ -1,12 +1,24 @@ """ - Десериализация бинарных файлов Flatbuffers по заданной схеме c открытием диалогового окна для - поиска компилятора схемы при его отсутствии в рабочей директории. + Десериализация выбранных бинарных файлов Flatbuffers по выбранной схеме. """ import os import sys +import argparse +from i18n import t from main import prepare_app, get_flatc_path, execute_deserialize # pylint: disable=import-error if __name__ == "__main__": prepare_app("images/flatbuffers-logo-clean.png") - sys.exit(execute_deserialize(get_flatc_path(True, os.getcwd(), True))) + parser = argparse.ArgumentParser(prog=t("main.flatc_deserializer_name"), + description=t("main.flatc_deserializer_desc")) + parser.add_argument("-s", "--schema_path", type=str, default="", help=t("main.schema_file_arg")) + parser.add_argument("-b", "--binary_paths", nargs="+", default=[], + help=t("main.binary_files_arg")) + parser.add_argument("-o", "--output_path", type=str, default="", + help=t("main.output_directory_arg")) + parser.add_argument("-f", "--flatc_path", type=str, default="", help=t("main.flatc_path_arg")) + args = parser.parse_args() + sys.exit(execute_deserialize( + get_flatc_path(os.getcwd(), True) if args.flatc_path == "" else args.flatc_path, + args.schema_path, args.binary_paths, args.output_path)) diff --git a/flatc_deserializer_batch.py b/flatc_deserializer_batch.py new file mode 100644 index 0000000..4696155 --- /dev/null +++ b/flatc_deserializer_batch.py @@ -0,0 +1,27 @@ +""" + Десериализация бинарных файлов Flatbuffers в выбранной директории по всем схемам в другой + выбранной директории. +""" +import os +import sys +import argparse +from i18n import t + +from main import prepare_app, get_flatc_path, \ + execute_deserialize_batch # pylint: disable=import-error + +if __name__ == "__main__": + prepare_app("images/flatbuffers-batch-logo-clean.png") + parser = argparse.ArgumentParser(prog=t("main.flatc_deserializer_name"), + description=t("main.flatc_derializer_desc")) + parser.add_argument("-s", "--schemas_path", type=str, default="", + help=t("main.schemas_directory_arg")) + parser.add_argument("-b", "--binaries_path", type=str, default="", + help=t("main.binaries_directory_arg")) + parser.add_argument("-o", "--output_path", type=str, default="", + help=t("main.output_directory_arg")) + parser.add_argument("-f", "--flatc_path", type=str, default="", help=t("main.flatc_path_arg")) + args = parser.parse_args() + sys.exit(execute_deserialize_batch( + get_flatc_path(os.getcwd(), True) if args.flatc_path == "" else args.flatc_path, + args.schemas_path, args.binaries_path, args.output_path)) diff --git a/images/flatbuffers-batch-logo-clean.png b/images/flatbuffers-batch-logo-clean.png new file mode 100644 index 0000000000000000000000000000000000000000..43a3096c889fa953c80ec6bb983b9206b66560f4 GIT binary patch literal 51015 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 e@)+?^jrC7% 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 B4F~`L literal 0 HcmV?d00001 diff --git a/localization/en_US/flatc_download_funcs.yml b/localization/en_US/flatc_download_funcs.yml index 6e0275e..344235f 100644 --- a/localization/en_US/flatc_download_funcs.yml +++ b/localization/en_US/flatc_download_funcs.yml @@ -1,5 +1,5 @@ download_start: Retrieving Flatbuffers latest release data... download_failed: Can't find valid latest Flatbuffers release. -download_finish: "Downloaded latest Flatbuffers release to %s." +download_finish: Downloaded latest Flatbuffers release to %s. unpack_path: Unpacked %s archive to %s. archive_removed: Flatbuffers archive is removed. \ No newline at end of file diff --git a/localization/en_US/main.yml b/localization/en_US/main.yml index 4e04575..c59cdc6 100644 --- a/localization/en_US/main.yml +++ b/localization/en_US/main.yml @@ -1,6 +1,6 @@ -tkinter_flatc_select: Select scheme compiler +tkinter_flatc_select: Select schema compiler exe_filetype: Windows Executable -tkinter_fbs_select: Select scheme file +tkinter_fbs_select: Select schema file fbs_filetype: Flatbuffers scheme tkinter_binaries_select: Select binary files flatc_binary_filetype: Binary Flatbuffers file @@ -12,4 +12,15 @@ file_not_found: File %s not found. directory_not_found: Directory %s not found. file_removed: File %s is removed. flatc_already_exists: "Flabuffers schema compiler already exists in working directory: %s." -file_not_executable: File %s is not executable. \ No newline at end of file +file_not_executable: File %s is not executable. +tkinter_fbs_directory_select: Select directory with schema files +tkinter_binary_directory_select: Select directory with binary files +no_schema_files_found: No schema files found in directory %s. +schemas_directory_arg: Directory with schema files +binaries_directory_arg: Directory with binary files +output_directory_arg: Output directory for deserialized files +schema_file_arg: Schema file +binary_files_arg: Binary files +flatc_path_arg: Path to schema compiler (flatc) +flatc_deserializer_name: Flatbuffers Batch Deserializer +flatc_deserializer_desc: Program for batch deserialization of Flatbuffers binary files. \ No newline at end of file diff --git a/localization/ru_RU/flatc_download_funcs.yml b/localization/ru_RU/flatc_download_funcs.yml index d01f6e3..a324788 100644 --- a/localization/ru_RU/flatc_download_funcs.yml +++ b/localization/ru_RU/flatc_download_funcs.yml @@ -1,5 +1,5 @@ download_start: Получение данных о последней версии Flatbuffers... download_failed: Не удалось найти валидную последнюю версию Flatbuffers. -download_finish: "Последняя версия Flatbuffers была загружена в %s." +download_finish: Последняя версия Flatbuffers была загружена в %s. unpack_path: Архив %s распакован в %s. archive_removed: Архив Flatbuffers был удалён. \ No newline at end of file diff --git a/localization/ru_RU/main.yml b/localization/ru_RU/main.yml index 07ec1be..bb778a7 100644 --- a/localization/ru_RU/main.yml +++ b/localization/ru_RU/main.yml @@ -12,4 +12,15 @@ file_not_found: Файл %s не найден. directory_not_found: Директория %s не найдена. file_removed: Файл %s был удалён. flatc_already_exists: "Компилятор схемы Flatbuffers уже существует в рабочей директории: %s" -file_not_executable: Файл %s не является исполняемым. \ No newline at end of file +file_not_executable: Файл %s не является исполняемым. +tkinter_fbs_directory_select: Выбор директории с файлами схем +tkinter_binary_directory_select: Выбор директории с бинарными файлами +no_schema_files_found: Файлы схем не были найдены в директории %s. +schemas_directory_arg: Директория с файлами схем +binaries_directory_arg: Директория с бинарными файлами +output_directory_arg: Директория вывода для десериализованных файлов +schema_file_arg: Файл схемы +binary_files_arg: Бинарные файлы +flatc_path_arg: Путь к компилятору схемы (flatc) +flatc_deserializer_name: Flatbuffers Batch Deserializer +flatc_deserializer_desc: Программа для пакетной десериализации бинарных файлов Flatbuffers. \ No newline at end of file diff --git a/main.py b/main.py index 6273eda..b8c09eb 100644 --- a/main.py +++ b/main.py @@ -37,6 +37,7 @@ def prepare_app(icon_path: str): """ logging.basicConfig(stream=sys.stdout, format="%(message)s", level=logging.INFO) filterwarnings("ignore", category=DeprecationWarning) + # noinspection PyDeprecation i18n.set("locale", getdefaultlocale()[0]) # pylint: disable=deprecated-method i18n.set("fallback", "en_US") i18n.load_path.append(get_resource_path("localization")) @@ -49,20 +50,14 @@ def prepare_app(icon_path: str): root.iconphoto(True, PhotoImage(file=get_resource_path(icon_path))) -def get_flatc_path(allow_system_path: bool, root_path: str, allow_ask: bool, - suppress_ask_error: bool = True) -> str: +def get_flatc_path(root_path: str, allow_ask: bool, suppress_ask_error: bool = True) -> str: """ Получение пути к файлу компилятора Flatbuffers. - :param allow_system_path: Позволить искать файл в системных директориях Python. :param root_path: Путь к текущей рабочей директории. :param allow_ask: Позволить открыть файл через диалоговое окно, если файла нет в рабочей директории. :param suppress_ask_error: Игнорировать ошибку FileNotFoundError, если не выводится диалоговое окно для файла. :return: Путь к файлу. """ - if allow_system_path: - flatc_path = which("flatc") - if flatc_path is not None: - return os.path.abspath(flatc_path) flatc_path = which("flatc", path=root_path + os.sep) if flatc_path is not None: return os.path.abspath(flatc_path) @@ -89,7 +84,7 @@ def execute_download(root_path: str) -> int | str: :param root_path: Путь к текущей рабочей директории. :return: Код ошибки или строка об ошибке. """ - flatc_path = get_flatc_path(False, root_path, False, True) + flatc_path = get_flatc_path(root_path, False, True) if flatc_path != "": logging.info(i18n.t("main.flatc_already_exists"), flatc_path) else: @@ -97,25 +92,39 @@ def execute_download(root_path: str) -> int | str: return os.EX_OK -def execute_deserialize(flatc_path: str) -> int | str: +def execute_deserialize(flatc_path: str, schema_path: str, binary_paths: list[str], output_path: +str) -> (int | str): """ Десериализация бинарных файлов Flatbuffers по заданной схеме. :param flatc_path: Путь к файлу компилятора схемы. + :param schema_path: Путь к файлу схемы. + :param binary_paths: Список путей к бинарным файлам. + :param output_path: Путь к директории вывода для десериализованных файлов. :return: Код ошибки или строка об ошибке. """ if not os.path.isfile(flatc_path): raise FileNotFoundError(i18n.t("main.file_not_found") % flatc_path) if which(os.path.split(flatc_path)[1], path=os.path.split(flatc_path)[0]) is None: raise FileNotFoundError(i18n.t("main.file_not_executable") % flatc_path) - schema_path = askopenfilename(title=i18n.t("main.tkinter_fbs_select"), - filetypes=[(i18n.t("main.fbs_filetype"), "*.fbs")]) if schema_path == "": - return os.EX_OK + schema_path = askopenfilename(title=i18n.t("main.tkinter_fbs_select"), + filetypes=[(i18n.t("main.fbs_filetype"), "*.fbs")]) + if schema_path == "": + return os.EX_OK + elif not os.path.isfile(schema_path): + raise FileNotFoundError(i18n.t("main.file_not_found") % schema_path) schema_name = os.path.splitext(os.path.basename(schema_path))[0] - binary_paths = askopenfilenames(title=i18n.t("main.tkinter_binaries_select"), - filetypes=[ - (i18n.t("main.flatc_binary_filetype"), "*." + schema_name)]) - output_path = askdirectory(title=i18n.t("main.tkinter_output_select")) + if len(binary_paths) < 1: + binary_paths = askopenfilenames(title=i18n.t("main.tkinter_binaries_select"), filetypes=[ + (i18n.t("main.flatc_binary_filetype"), "*." + schema_name)]) + if len(binary_paths) < 1: + return os.EX_OK + else: + binary_paths = [binary_path for binary_path in binary_paths if os.path.isfile(binary_path)] + if output_path == "": + output_path = askdirectory(title=i18n.t("main.tkinter_output_select")) + elif not os.path.isdir(output_path): + raise FileNotFoundError(i18n.t("main.directory_not_found") % output_path) full_size = sum(os.stat(binary_path).st_size for binary_path in binary_paths) with logging_redirect_tqdm(): pbar = tqdm(total=full_size, position=0, unit="B", unit_scale=True, @@ -128,3 +137,93 @@ def execute_deserialize(flatc_path: str) -> int | str: pbar.set_postfix_str("") pbar.close() return os.EX_OK + + +def get_schema_paths(root_path: str) -> list[str]: + """ + Получение списка путей к файлам схем Flatbuffers внутри заданной корневой директории. + :param root_path: Путь к корневой директории. + :return: Список путей к файлам схем. + """ + schema_paths = [] + if not os.path.isdir(root_path): + return schema_paths + for subdir, _, files in os.walk(root_path): + for file in files: + file_path = os.path.abspath(os.path.join(subdir, file)) + if os.path.splitext(file_path)[1].lower() == ".fbs": + schema_paths.append(file_path) + return schema_paths + + +def get_binary_tuples(binaries_path: str, schema_paths: list[str]) -> tuple[ + list[tuple[str, str]], int]: + """ + Получение списка кортежей из двух элементов: (путь к бинарному файлу, путь к соответствующему ему файлу схемы) + :param binaries_path: Список путей к бинарным файлам. + :param schema_paths: Список путей к файлам схем. + :return: Кортеж из двух строковых элементов. + """ + binary_tuples = [] + full_size = 0 + for subdir, _, files in os.walk(binaries_path): + for file in files: + file_path = os.path.abspath(os.path.join(subdir, file)) + for schema_path in schema_paths: + if os.path.splitext(os.path.basename(schema_path))[0].casefold() == \ + os.path.splitext(file)[1][1:].casefold(): + binary_tuples.append((file_path, schema_path)) + full_size += os.stat(file_path).st_size + break + return binary_tuples, full_size + + +def execute_deserialize_batch(flatc_path: str, schemas_path: str, binaries_path: str, + output_path: str) -> (int | str): + """ + Десериализация всех файлов Flatbuffers в директории по всем схемам из другой директории. + :param flatc_path: Путь к файлу компилятора схемы. + :param schemas_path: Путь к директории с файлами схем. + :param binaries_path: Путь к директории с бинарными файлами. + :param output_path: Путь к директории вывода. + :return: Код ошибки или строка об ошибке. + """ + if not os.path.isfile(flatc_path): + raise FileNotFoundError(i18n.t("main.file_not_found") % flatc_path) + if which(os.path.split(flatc_path)[1], path=os.path.split(flatc_path)[0]) is None: + raise FileNotFoundError(i18n.t("main.file_not_executable") % flatc_path) + if schemas_path == "": + schemas_path = askdirectory(title=i18n.t("main.tkinter_fbs_directory_select")) + if schemas_path == "": + return os.EX_OK + elif not os.path.isdir(schemas_path): + raise FileNotFoundError(i18n.t("main.directory_not_found") % schemas_path) + if binaries_path == "": + binaries_path = askdirectory(title=i18n.t("main.tkinter_binary_directory_select")) + if binaries_path == "": + return os.EX_OK + elif not os.path.isdir(binaries_path): + raise FileNotFoundError(i18n.t("main.directory_not_found") % binaries_path) + if output_path == "": + output_path = askdirectory(title=i18n.t("main.tkinter_output_select")) + if output_path == "": + output_path = os.path.split(flatc_path)[0] + elif not os.path.isdir(output_path): + raise FileNotFoundError(i18n.t("main.directory_not_found") % output_path) + schema_paths = get_schema_paths(schemas_path) + if len(schema_paths) < 1: + logging.info(i18n.t("main.no_schema_files_found"), binaries_path) + return os.EX_OK + binary_tuples, full_size = get_binary_tuples(binaries_path, schema_paths) + with logging_redirect_tqdm(): + pbar = tqdm(total=full_size, position=0, unit="B", unit_scale=True, + desc=i18n.t("main.files")) + for binary_path, schema_path in binary_tuples: + pbar.set_postfix_str(binary_path) + pbar.clear() + deserialize(flatc_path, schema_path, binary_path, output_path + os.sep + + os.path.split(os.path.relpath(binary_path, binaries_path))[0]) + pbar.update(os.stat(binary_path).st_size) + pbar.set_postfix_str("") + pbar.close() + return os.EX_OK