Coverage for frappe_manager / main.py: 0%
54 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
1import atexit
2import signal
4from frappe_manager import CLI_LOG_DIRECTORY
5from frappe_manager.commands import app
6from frappe_manager.exceptions import FrappeManagerException
7from frappe_manager.logger import log
8from frappe_manager.output_manager.globals import get_global_output_handler, set_global_output_handler
9from frappe_manager.output_manager.rich_output import RichOutputHandler
10from frappe_manager.utils.docker import process_opened
11from frappe_manager.utils.helpers import capture_and_format_exception, remove_zombie_subprocess_process
14def cli_entrypoint():
15 """
16 Main CLI entry point.
18 Initializes a basic RichOutputHandler early, which will be upgraded
19 to LoggingOutputHandler in app_callback (commands/__init__.py) after
20 CLI arguments are parsed. Exception handling uses bare richprint for
21 backward compatibility.
22 """
23 if hasattr(signal, "SIGPIPE"):
24 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
26 # Initialize basic output handler early (before app() runs)
27 # This will be upgraded to LoggingOutputHandler in app_callback after CLI args are parsed
28 basic_handler = RichOutputHandler()
29 set_global_output_handler(basic_handler)
31 try:
32 app()
33 except FrappeManagerException as e:
34 try:
35 from frappe_manager.metadata_manager import FMConfigManager
37 fm_config = FMConfigManager.import_from_toml()
38 file_level = fm_config.logs.file_level
39 except Exception:
40 file_level = "DEBUG"
42 logger = log.get_logger(file_level=file_level)
43 output = get_global_output_handler()
45 output.display_error(f"[red]Error Occurred[/red] {str(e).strip()}")
47 # Show details if available
48 if e.details:
49 output.display_error(f"Details: {e.details}")
51 output.print(f"More info about error is logged in {CLI_LOG_DIRECTORY / 'fm.log'}", emoji_code=":mag:")
52 output.stop()
54 exception_traceback: str = capture_and_format_exception()
55 logger.error(f"FM Exception: {e.__class__.__name__}: {e!s}\n{exception_traceback}")
56 exit(1)
58 except Exception as e:
59 try:
60 from frappe_manager.metadata_manager import FMConfigManager
62 fm_config = FMConfigManager.import_from_toml()
63 file_level = fm_config.logs.file_level
64 except Exception:
65 file_level = "DEBUG"
67 logger = log.get_logger(file_level=file_level)
68 output = get_global_output_handler()
70 output.display_error(f"[red]Unexpected Error[/red] {str(e).strip()}")
71 output.print(f"More info about error is logged in {CLI_LOG_DIRECTORY / 'fm.log'}", emoji_code=":mag:")
72 output.stop()
74 exception_traceback: str = capture_and_format_exception()
75 logger.error(f"Unexpected Exception:\n{exception_traceback}")
76 exit(1)
78 finally:
79 atexit.register(exit_cleanup)
82def exit_cleanup():
83 """
84 This function is used to perform cleanup at the exit.
85 """
86 remove_zombie_subprocess_process(process_opened)
87 output = get_global_output_handler()
88 output.stop()