Generate settings for an archivers executable

This commit is contained in:
Timmy Welch 2023-01-30 21:36:47 -08:00
parent c80627575a
commit 46899255c8
No known key found for this signature in database
6 changed files with 74 additions and 13 deletions

View File

@ -12,6 +12,13 @@ class Archiver(Protocol):
"""The path to the archive"""
path: pathlib.Path
"""
The name of the executable used for this archiver. This should be the base name of the executable.
For example if 'rar.exe' is needed this should be "rar".
If an executable is not used this should be the empty string.
"""
exe: str = ""
"""
Whether or not this archiver is enabled.
If external imports are required and are not available this should be false. See rar.py and sevenzip.py.
@ -114,7 +121,9 @@ class Archiver(Protocol):
def open(cls, path: pathlib.Path) -> Archiver:
"""
Opens the given archive.
Should always return a an Archver. Should never cause an exception, is_valid will always be called before open.
Should always return a an Archver.
Should never cause an exception no file operations should take place in this method,
is_valid will always be called before open.
"""
archiver = cls()
archiver.path = path

View File

@ -29,10 +29,10 @@ class RarArchiver(Archiver):
"""RAR implementation"""
enabled = rar_support
exe = "rar"
def __init__(self, rar_exe_path: str = "rar") -> None:
def __init__(self) -> None:
super().__init__()
self.rar_exe_path = shutil.which(rar_exe_path) or ""
# windows only, keeps the cmd.exe from popping up
if platform.system() == "Windows":
@ -46,7 +46,7 @@ class RarArchiver(Archiver):
return rarc.comment.decode("utf-8") if rarc else ""
def set_comment(self, comment: str) -> bool:
if rar_support and self.rar_exe_path:
if rar_support and self.exe:
try:
# write comment to temp file
with tempfile.TemporaryDirectory() as tmp_dir:
@ -57,7 +57,7 @@ class RarArchiver(Archiver):
# use external program to write comment to Rar archive
proc_args = [
self.rar_exe_path,
self.exe,
"c",
f"-w{working_dir}",
"-c-",
@ -130,10 +130,10 @@ class RarArchiver(Archiver):
raise OSError
def remove_file(self, archive_file: str) -> bool:
if self.rar_exe_path:
if self.exe:
# use external program to remove file from Rar archive
result = subprocess.run(
[self.rar_exe_path, "d", "-c-", self.path, archive_file],
[self.exe, "d", "-c-", self.path, archive_file],
startupinfo=self.startupinfo,
stdout=subprocess.DEVNULL,
stdin=subprocess.DEVNULL,
@ -155,14 +155,14 @@ class RarArchiver(Archiver):
return False
def write_file(self, archive_file: str, data: bytes) -> bool:
if self.rar_exe_path:
if self.exe:
archive_path = pathlib.PurePosixPath(archive_file)
archive_name = archive_path.name
archive_parent = str(archive_path.parent).lstrip("./")
# use external program to write file to Rar archive
result = subprocess.run(
[self.rar_exe_path, "a", f"-si{archive_name}", f"-ap{archive_parent}", "-c-", "-ep", self.path],
[self.exe, "a", f"-si{archive_name}", f"-ap{archive_parent}", "-c-", "-ep", self.path],
input=data,
startupinfo=self.startupinfo,
stdout=subprocess.DEVNULL,
@ -217,7 +217,7 @@ class RarArchiver(Archiver):
with open(rar_cwd / filename, mode="w+b") as tmp_file:
tmp_file.write(data)
result = subprocess.run(
[self.rar_exe_path, "a", "-r", "-c-", str(rar_path.absolute()), "."],
[self.exe, "a", "-r", "-c-", str(rar_path.absolute()), "."],
cwd=rar_cwd.absolute(),
startupinfo=self.startupinfo,
stdout=subprocess.DEVNULL,
@ -237,7 +237,7 @@ class RarArchiver(Archiver):
return True
def is_writable(self) -> bool:
return bool(self.rar_exe_path and os.path.exists(self.rar_exe_path))
return bool(self.exe and (os.path.exists(self.exe) or shutil.which(self.exe)))
def extension(self) -> str:
return ".cbr"

View File

@ -2,13 +2,16 @@ from __future__ import annotations
from comictaggerlib.ctoptions.cmdline import initial_cmd_line_parser, register_commandline, validate_commandline_options
from comictaggerlib.ctoptions.file import register_settings, validate_settings
from comictaggerlib.ctoptions.plugin import register_plugin_settings, validate_plugin_settings
from comictaggerlib.ctoptions.types import ComicTaggerPaths
__all__ = [
"initial_cmd_line_parser",
"register_commandline",
"register_settings",
"register_plugin_settings",
"validate_commandline_options",
"validate_settings",
"validate_plugin_settings",
"ComicTaggerPaths",
]

View File

@ -248,7 +248,7 @@ def autotag(parser: settngs.Manager) -> None:
)
def validate_settings(options: settngs.Config[settngs.Values], parser: settngs.Manager) -> dict[str, dict[str, Any]]:
def validate_settings(options: settngs.Config[settngs.Values]) -> dict[str, dict[str, Any]]:
options[0].identifier_publisher_filter = [x.strip() for x in options[0].identifier_publisher_filter if x.strip()]
options[0].rename_replacements = Replacements(
[Replacement(x[0], x[1], x[2]) for x in options[0].rename_replacements[0]],

View File

@ -0,0 +1,43 @@
from __future__ import annotations
import logging
import os
import settngs
import comicapi.comicarchive
logger = logging.getLogger("comictagger")
def archiver(manager: settngs.Manager) -> None:
exe_registered: set[str] = set()
for archiver in comicapi.comicarchive.archivers:
if archiver.exe and archiver.exe not in exe_registered:
manager.add_setting(
f"--{archiver.exe.replace(' ', '-').replace('_', '-').strip().strip('-')}",
default=archiver.exe,
help="Path to the %(default)s executable\n\n",
)
exe_registered.add(archiver.exe)
def validate_plugin_settings(options: settngs.Config) -> settngs.Config:
cfg = settngs.normalize_config(options, file=True, cmdline=True, defaults=False)
for archiver in comicapi.comicarchive.archivers:
exe_name = archiver.exe.replace(" ", "-").replace("_", "-").strip().strip("-").replace("-", "_")
if (
exe_name in cfg[0]["archiver"]
and cfg[0]["archiver"][exe_name]
and cfg[0]["archiver"][exe_name] != archiver.exe
):
if os.path.basename(cfg[0]["archiver"][exe_name]) == archiver.exe:
comicapi.utils.add_to_path(os.path.dirname(cfg[0]["archiver"][exe_name]))
else:
archiver.exe = cfg[0]["archiver"][exe_name]
return options
def register_plugin_settings(manager: settngs.Manager):
manager.add_group("archiver", archiver, False)

View File

@ -68,12 +68,16 @@ class App:
def run(self) -> None:
opts = self.initialize()
self.load_plugins()
self.register_options()
self.parse_options(opts.config)
self.initialize_dirs()
self.main()
def load_plugins(self) -> None:
comicapi.comicarchive.load_archive_plugins()
def initialize(self) -> argparse.Namespace:
opts, _ = self.initial_arg_parser.parse_known_args()
assert opts is not None
@ -87,6 +91,7 @@ class App:
)
ctoptions.register_commandline(self.manager)
ctoptions.register_settings(self.manager)
ctoptions.register_plugin_settings(self.manager)
def parse_options(self, config_paths: ctoptions.ComicTaggerPaths) -> None:
self.options, self.config_load_success = self.manager.parse_config(
@ -95,7 +100,8 @@ class App:
self.options = self.manager.get_namespace(self.options)
self.options = ctoptions.validate_commandline_options(self.options, self.manager)
self.options = ctoptions.validate_settings(self.options, self.manager)
self.options = ctoptions.validate_settings(self.options)
self.options = ctoptions.validate_plugin_settings(self.options)
self.options = self.options
def initialize_dirs(self) -> None: