#!/usr/bin/env python3 # This file is part of ISO Scalpel. # Copyright (C) 2025 Jeremy Anderson # # 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 # 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())