|
1 | 1 | #!/usr/bin/env python3 |
2 | | -import argparse |
3 | | -import logging |
4 | | -import os |
5 | | -import sys |
6 | | -import traceback |
7 | | -from logging.handlers import RotatingFileHandler |
8 | | -from pathlib import Path |
9 | | -import gi |
10 | | -gi.require_version("Gtk", "3.0") |
11 | | -gi.require_version("Gdk", "3.0") |
12 | | -gi.require_version("Pango", "1.0") |
13 | | -gi.require_version("GdkPixbuf", "2.0") |
14 | | -gi.require_version("GLib", "2.0") |
15 | | - |
16 | | -from clipse_gui import __version__, constants # noqa: E402 |
17 | | - |
18 | | -PACKAGE_PARENT = ".." |
19 | | -SCRIPT_DIR = os.path.dirname( |
20 | | - os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))) |
21 | | -) |
22 | | -sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT))) |
23 | | - |
24 | | -log = None |
25 | | - |
26 | | - |
27 | | -class ColorFormatter(logging.Formatter): |
28 | | - COLORS = { |
29 | | - "DEBUG": "\033[1;36m", |
30 | | - "INFO": "\033[1;32m", |
31 | | - "WARNING": "\033[1;33m", |
32 | | - "ERROR": "\033[1;31m", |
33 | | - "CRITICAL": "\033[1;41m", |
34 | | - "RESET": "\033[0m", |
35 | | - } |
36 | | - |
37 | | - def format(self, record): |
38 | | - level_color = self.COLORS.get(record.levelname, "") |
39 | | - reset = self.COLORS["RESET"] |
40 | | - record.levelname = f"{level_color}{record.levelname}{reset}" |
41 | | - record.name = f"\033[1;34m{record.name}\033[0m" |
42 | | - record.asctime = f"\033[1;37m{self.formatTime(record, self.datefmt)}\033[0m" |
43 | | - return super().format(record) |
44 | | - |
45 | | - |
46 | | -def parse_args_from_sys_argv(): |
47 | | - parser = argparse.ArgumentParser( |
48 | | - description="Start the Clipse GUI application.", |
49 | | - formatter_class=argparse.ArgumentDefaultsHelpFormatter, |
50 | | - ) |
51 | | - parser.add_argument( |
52 | | - "-d", "--debug", action="store_true", help="Enable debug logging" |
53 | | - ) |
54 | | - parser.add_argument( |
55 | | - "-v", "--version", action="version", version=f"Clipse GUI v{__version__}" |
56 | | - ) |
57 | | - return parser.parse_known_args() |
58 | | - |
| 2 | +"""Dev entry shim for in-tree runs. |
59 | 3 |
|
60 | | -def setup_logging(debug=False): |
61 | | - global log |
62 | | - try: |
63 | | - log_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" |
64 | | - date_format = "%Y-%m-%d %H:%M:%S" |
| 4 | +The canonical entry point is `clipse_gui.cli:main`, exposed as `clipse-gui` |
| 5 | +via `[project.scripts]` once installed from the wheel. This file just lets |
| 6 | +`python clipse-gui.py` work from a fresh checkout. |
| 7 | +""" |
65 | 8 |
|
66 | | - stream_handler = logging.StreamHandler(sys.stdout) |
67 | | - stream_handler.setLevel(logging.DEBUG if debug else logging.INFO) |
68 | | - stream_handler.setFormatter(ColorFormatter(log_format, datefmt=date_format)) |
69 | | - |
70 | | - handlers = [stream_handler] |
71 | | - |
72 | | - # File logging only in debug mode — RotatingFileHandler adds ~100ms I/O on every start |
73 | | - if debug: |
74 | | - log_file_path = os.path.join(constants.CONFIG_DIR, "clipse-gui.log") |
75 | | - file_handler = RotatingFileHandler( |
76 | | - filename=log_file_path, |
77 | | - maxBytes=5 * 1024 * 1024, |
78 | | - backupCount=3, |
79 | | - ) |
80 | | - file_handler.setLevel(logging.DEBUG) |
81 | | - file_handler.setFormatter(logging.Formatter(log_format, datefmt=date_format)) |
82 | | - handlers.append(file_handler) |
83 | | - |
84 | | - logging.basicConfig(level=logging.DEBUG, handlers=handlers) |
85 | | - log = logging.getLogger(__name__) |
86 | | - log.info(f"Logging initialized ({'DEBUG + file' if debug else 'INFO'})") |
87 | | - except Exception as e: |
88 | | - print(f"CRITICAL: Failed to set up logging: {e}", file=sys.stderr) |
89 | | - traceback.print_exc() |
90 | | - sys.exit(1) |
91 | | - |
92 | | - |
93 | | -def main(): |
94 | | - args, gtk_args = parse_args_from_sys_argv() |
95 | | - setup_logging(debug=args.debug) |
96 | | - |
97 | | - if log is None: |
98 | | - print("CRITICAL: Logging setup failed. Exiting.", file=sys.stderr) |
99 | | - sys.exit(1) |
100 | | - |
101 | | - try: |
102 | | - Path(constants.CONFIG_DIR).mkdir(parents=True, exist_ok=True) |
103 | | - except Exception as e: |
104 | | - log.critical(f"Failed to create config directory: {e}", exc_info=True) |
105 | | - sys.exit(1) |
106 | | - |
107 | | - try: |
108 | | - from clipse_gui.app import ClipseGuiApplication |
| 9 | +import os |
| 10 | +import sys |
109 | 11 |
|
110 | | - app = ClipseGuiApplication() |
111 | | - exit_status = app.run(gtk_args) |
112 | | - log.info(f"Application exited with status {exit_status}.") |
113 | | - sys.exit(exit_status) |
114 | | - except Exception as e: |
115 | | - log.critical(f"Unhandled exception in main: {e}", exc_info=True) |
116 | | - sys.exit(1) |
| 12 | +# Make the package importable when running from source without installing. |
| 13 | +sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) |
117 | 14 |
|
| 15 | +from clipse_gui.cli import main # noqa: E402 |
118 | 16 |
|
119 | 17 | if __name__ == "__main__": |
120 | 18 | main() |
0 commit comments