118 lines
4.0 KiB
Python
Executable File
118 lines
4.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# This file is part of ISO Scalpel.
|
|
# Copyright (C) 2025 Jeremy Anderson <info@dcos.net>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, see <https://www.gnu.org/licenses/>
|
|
# or write to the Free Software Foundation, Inc., 51 Franklin Street,
|
|
# Fifth Floor, Boston, MA 02110-1301 USA.
|
|
"""ISO Scalpel -- entry point.
|
|
|
|
A PySide6 disc-image editor built on pycdlib, supporting ISO9660, Rock
|
|
Ridge, Joliet, UDF and El Torito boot images.
|
|
|
|
Usage:
|
|
python main.py [file.iso]
|
|
python main.py --check-deps # report missing deps and exit
|
|
python main.py --no-install-deps # never prompt to install
|
|
python main.py --reset-layout # clear saved window/splitter settings and exit
|
|
python main.py --debug-layout # start the GUI with verbose widget-tree logging
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
|
|
# Make the package importable when run directly.
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
# Verify third-party dependencies BEFORE importing the GUI layer, so a
|
|
# missing package produces a friendly, actionable message instead of a raw
|
|
# traceback. In an interactive terminal the user is offered to install
|
|
# the missing packages (with explicit consent for any sudo fallback).
|
|
from iso_scalpel._deps import (
|
|
check_dependencies,
|
|
ensure_dependencies,
|
|
format_missing_report,
|
|
)
|
|
|
|
# Recognised long options and the flag key they set. A flat lookup table
|
|
# replaces the if/elif chain so adding a new switch is a one-line edit.
|
|
_FLAG_TABLE: dict[str, str] = {
|
|
"--check-deps": "check_only",
|
|
"--no-install-deps": "no_install",
|
|
"--reset-layout": "reset_layout",
|
|
"--debug-layout": "debug_layout",
|
|
}
|
|
|
|
|
|
def _parse_flags(argv: list[str]) -> tuple[list[str], dict[str, bool]]:
|
|
"""Separate our own flags from argv; return (positional, flags_dict).
|
|
|
|
Unknown arguments are treated as positional and returned for the GUI
|
|
layer (which honours a single ISO path argument).
|
|
"""
|
|
flags = dict.fromkeys(_FLAG_TABLE.values(), False)
|
|
rest: list[str] = []
|
|
for arg in argv:
|
|
flag_key = _FLAG_TABLE.get(arg)
|
|
if flag_key is not None:
|
|
flags[flag_key] = True
|
|
else:
|
|
rest.append(arg)
|
|
return rest, flags
|
|
|
|
|
|
def _reset_layout() -> int:
|
|
"""Delete the saved settings file so the next launch uses defaults."""
|
|
from iso_scalpel.config import _config_path
|
|
path = _config_path()
|
|
if os.path.exists(path):
|
|
try:
|
|
os.remove(path)
|
|
print(f"Removed saved settings: {path}")
|
|
except OSError as exc:
|
|
sys.stderr.write(f"Could not remove {path}: {exc}\n")
|
|
return 1
|
|
else:
|
|
print(f"No saved settings at {path} -- nothing to reset.")
|
|
print("Re-run `python main.py` to launch with default layout.")
|
|
return 0
|
|
|
|
|
|
def main() -> int:
|
|
argv = list(sys.argv)
|
|
argv, flags = _parse_flags(argv)
|
|
|
|
if flags["check_only"]:
|
|
missing = check_dependencies()
|
|
if missing:
|
|
sys.stderr.write(format_missing_report(missing) + "\n")
|
|
return 1
|
|
print("All dependencies satisfied.")
|
|
return 0
|
|
|
|
if flags["reset_layout"]:
|
|
return _reset_layout()
|
|
|
|
ensure_dependencies(auto_install=not flags["no_install"])
|
|
|
|
from iso_scalpel.app import run
|
|
# If a file was passed on the command line, defer opening it to the
|
|
# main window after it is constructed. Handled in run() via argv.
|
|
return run(argv, debug_layout=flags["debug_layout"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|