|
1 | 1 | # -*- coding: iso-8859-1 -*- |
2 | | -# Copyright (C) 2013-2015, 2023-2025 Rocky Bernstein <[email protected]> |
| 2 | +# Copyright (C) 2013-2015, 2023-2026 Rocky Bernstein <[email protected]> |
3 | 3 | # |
4 | 4 | # This program is free software: you can redistribute it and/or modify |
5 | 5 | # it under the terms of the GNU General Public License as published by |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | 16 |
|
17 | 17 | import codecs |
| 18 | +import importlib |
18 | 19 | import os |
19 | 20 | import sys |
20 | 21 | from optparse import OptionParser |
@@ -208,6 +209,14 @@ def process_options(pkg_version: str, sys_argv: list, option_list=None): |
208 | 209 | help="Don't register this as a global debugger.", |
209 | 210 | ) |
210 | 211 |
|
| 212 | + optparser.add_option( |
| 213 | + "-m", |
| 214 | + dest="module", |
| 215 | + action="store", |
| 216 | + type="string", |
| 217 | + metavar="module", |
| 218 | + help="Run library module as a script.", |
| 219 | + ) |
211 | 220 | optparser.add_option( |
212 | 221 | "--main", |
213 | 222 | dest="main", |
@@ -353,8 +362,17 @@ def process_options(pkg_version: str, sys_argv: list, option_list=None): |
353 | 362 |
|
354 | 363 | sys.argv = sys_argv |
355 | 364 |
|
356 | | - # Here is where we *parse* arguments |
357 | | - (opts, sys.argv) = optparser.parse_args(sys_argv[1:]) |
| 365 | + # If the -m option is present, only parse options before it and |
| 366 | + # leave -m and the following module/args alone. |
| 367 | + if "-m" in sys_argv[1:]: |
| 368 | + m_index_end = sys_argv.index("-m") + 2 |
| 369 | + # Parse only the arguments before '-m mod' |
| 370 | + (opts, _) = optparser.parse_args(sys_argv[1:m_index_end]) |
| 371 | + # Preserve the -m and everything after as the script/module args |
| 372 | + sys.argv = sys_argv[m_index_end :] |
| 373 | + else: |
| 374 | + # Here is where we *parse* arguments |
| 375 | + (opts, sys.argv) = optparser.parse_args(sys_argv[1:]) |
358 | 376 |
|
359 | 377 | if opts.edit_mode not in ("vi", "emacs"): |
360 | 378 | sys.stderr.write( |
@@ -410,6 +428,21 @@ def process_options(pkg_version: str, sys_argv: list, option_list=None): |
410 | 428 | sys.exit(2) |
411 | 429 | pass |
412 | 430 |
|
| 431 | + if opts.module: |
| 432 | + try: |
| 433 | + module = importlib.import_module(opts.module) |
| 434 | + if module.__file__.endswith("__init__.py"): |
| 435 | + main_module = f"{opts.module}.__main__" |
| 436 | + importlib.import_module(main_module) |
| 437 | + opts.module = main_module |
| 438 | + except ImportError: |
| 439 | + print(f"No module named {opts.module}") |
| 440 | + sys.exit(3) |
| 441 | + except Exception as e: |
| 442 | + print(f"Unexpected exception importing {opts.module}:\n\t{e}") |
| 443 | + sys.exit(4) |
| 444 | + pass |
| 445 | + |
413 | 446 | return opts, dbg_opts, sys.argv |
414 | 447 |
|
415 | 448 |
|
@@ -483,19 +516,39 @@ def postprocess_options(dbg, opts): |
483 | 516 | import pprint |
484 | 517 |
|
485 | 518 | def doit(version, arg_str): |
486 | | - print(f"options '{arg_str}'") |
| 519 | + print(f"Test {version}") |
| 520 | + print(f"options: '{arg_str}':") |
487 | 521 | args = arg_str.split() |
488 | 522 | opts, _, _ = process_options(version, args) |
489 | 523 | pp.pprint(vars(opts)) |
| 524 | + print(f"sys.argv: {sys.argv})") |
490 | 525 | print("") |
491 | 526 | return |
492 | 527 |
|
493 | 528 | pp = pprint.PrettyPrinter(indent=4) |
494 | | - doit("1.1", "__file__") |
495 | | - doit("1.2", f"{__file__} foo bar") |
496 | | - doit("1.3", f"{__file__} --server") |
497 | | - doit("1.3", f"{__file__} --command {__file__} bar baz") |
498 | | - doit("1.4", f"{__file__} --server --client") |
499 | | - doit("1.5", f"{__file__} --style=emacs") |
500 | | - doit("1.6", f"{__file__} --help") # exits, so must be last |
| 529 | + |
| 530 | + doit("1: no options.", |
| 531 | + "trepan3k") |
| 532 | + doit("2; program and argument", |
| 533 | + "trepan3k foo bar") |
| 534 | + doit("3: one trepan3k option", |
| 535 | + "trepan3k --server") |
| 536 | + |
| 537 | + doit("4: --command option", |
| 538 | + f"trepan3k --command {__file__} bar baz") |
| 539 | + |
| 540 | + doit("5", "trepan3k --server --client") |
| 541 | + doit("6", "trepan3k --style=emacs") |
| 542 | + |
| 543 | + # -F bytes foo.pyc should be passed to pydisasm |
| 544 | + doit("7: trepan3k option with program having its own options", |
| 545 | + "trepan3k --trace pydisasm -F bytes foo.pyc") |
| 546 | + |
| 547 | + # Options after -m pydebug should be passed to pydebug |
| 548 | + doit("8: -m option with arguments to module", |
| 549 | + "trepan3k --trace -m dis --host 0.0.0.0") |
| 550 | + |
| 551 | + # --help exits, so must be last |
| 552 | + doit("9: show help", |
| 553 | + "trepan3k --help") |
501 | 554 | pass |
0 commit comments