def main(): original_argv = list(sys.argv) try: sys.argv[1:] = parse(sys.argv[1:]) except Exception as ex: print(HELP + "\nError: " + str(ex), file=sys.stderr) sys.exit(2) log.to_file(prefix="ptvsd.server") log.describe_environment("ptvsd.server startup environment:") log.info( "sys.argv before parsing: {0!r}\n" " after parsing: {1!r}", original_argv, sys.argv, ) try: run = { "file": run_file, "module": run_module, "code": run_code, "pid": attach_to_pid, }[options.target_kind] run() except SystemExit as ex: log.exception("Debuggee exited via SystemExit: {0!r}", ex.code, level="debug") raise
def debug(address, log_dir=None, multiprocess=True): if log_dir: log.log_dir = log_dir log.to_file(prefix="ptvsd.server") log.describe_environment("ptvsd.server debug start environment:") log.debug("{0}{1!r}", func.__name__, (address, log_dir, multiprocess)) if is_attached(): log.info("{0}() ignored - already attached.", func.__name__) return options.host, options.port # Ensure port is int if address is not options: host, port = address options.host, options.port = (host, int(port)) if multiprocess is not options: options.multiprocess = multiprocess ptvsd_path, _, _ = get_abs_path_real_path_and_base_from_file(ptvsd.__file__) ptvsd_path = os.path.dirname(ptvsd_path) start_patterns = (ptvsd_path,) end_patterns = ("ptvsd_launcher.py",) log.info( "Won't trace filenames starting with: {0!j}\n" "Won't trace filenames ending with: {1!j}", start_patterns, end_patterns, ) try: return func(start_patterns, end_patterns) except Exception: raise log.exception("{0}() failed:", func.__name__, level="info")
def main(): from ptvsd.common import log from ptvsd import launcher from ptvsd.launcher import debuggee log.to_file(prefix="ptvsd.launcher") log.describe_environment("ptvsd.launcher startup environment:") # Disable exceptions on Ctrl+C - we want to allow the debuggee process to handle # these, or not, as it sees fit. If the debuggee exits on Ctrl+C, the launcher # will also exit, so it doesn't need to observe the signal directly. signal.signal(signal.SIGINT, signal.SIG_IGN) def option(name, type, *args): try: return type(os.environ.pop(name, *args)) except Exception: raise log.exception("Error parsing {0!r}:", name) launcher_port = option("PTVSD_LAUNCHER_PORT", int) launcher.connect(launcher_port) launcher.channel.wait() if debuggee.process is not None: sys.exit(debuggee.process.returncode)
def run_code(): log.describe_environment("Pre-launch environment:") log.info("Running code:\n\n{0}", options.target) # Add current directory to path, like Python itself does for -c. sys.path.insert(0, "") code = compile(options.target, "<string>", "exec") setup_debug_server("-c") eval(code, {})
def run_module(): # Add current directory to path, like Python itself does for -m. This must # be in place before trying to use find_spec below to resolve submodules. sys.path.insert(0, "") # We want to do the same thing that run_module() would do here, without # actually invoking it. On Python 3, it's exposed as a public API, but # on Python 2, we have to invoke a private function in runpy for this. # Either way, if it fails to resolve for any reason, just leave argv as is. argv_0 = sys.argv[0] try: if sys.version_info >= (3,): from importlib.util import find_spec spec = find_spec(options.target) if spec is not None: argv_0 = spec.origin else: _, _, _, argv_0 = runpy._get_module_details(options.target) except Exception: log.exception("Error determining module path for sys.argv") setup_debug_server(argv_0) # On Python 2, module name must be a non-Unicode string, because it ends up # a part of module's __package__, and Python will refuse to run the module # if __package__ is Unicode. target = ( compat.filename_bytes(options.target) if sys.version_info < (3,) else options.target ) log.describe_environment("Pre-launch environment:") log.info("Running module {0!r}", target) # Docs say that runpy.run_module is equivalent to -m, but it's not actually # the case for packages - -m sets __name__ to "__main__", but run_module sets # it to "pkg.__main__". This breaks everything that uses the standard pattern # __name__ == "__main__" to detect being run as a CLI app. On the other hand, # runpy._run_module_as_main is a private function that actually implements -m. try: run_module_as_main = runpy._run_module_as_main except AttributeError: log.warning("runpy._run_module_as_main is missing, falling back to run_module.") runpy.run_module(target, alter_sys=True) else: run_module_as_main(target, alter_argv=True)
def run_file(): setup_debug_server(options.target) # run_path has one difference with invoking Python from command-line: # if the target is a file (rather than a directory), it does not add its # parent directory to sys.path. Thus, importing other modules from the # same directory is broken unless sys.path is patched here. if os.path.isfile(options.target): dir = os.path.dirname(options.target) sys.path.insert(0, dir) else: log.debug("Not a file: {0!j}", options.target) log.describe_environment("Pre-launch environment:") log.info("Running file {0!j}", options.target) runpy.run_path(options.target, run_name="__main__")
def main(args): from ptvsd.common import log, options as common_options from ptvsd.adapter import ide, servers, sessions, options as adapter_options if args.log_stderr: log.stderr.levels |= set(log.LEVELS) adapter_options.log_stderr = True if args.log_dir is not None: common_options.log_dir = args.log_dir log.to_file(prefix="ptvsd.adapter") log.describe_environment("ptvsd.adapter startup environment:") if args.for_enable_attach and args.port is None: log.error("--for-enable-attach requires --port") sys.exit(64) server_host, server_port = servers.listen() ide_host, ide_port = ide.listen(port=args.port) if args.for_enable_attach: endpoints = { "ide": { "host": ide_host, "port": ide_port }, "server": { "host": server_host, "port": server_port }, } log.info("Sending endpoints to stdout: {0!r}", endpoints) print(json.dumps(endpoints)) sys.stdout.flush() if args.port is None: ide.IDE("stdio") servers.wait_until_disconnected() log.info( "All debug servers disconnected; waiting for remaining sessions...") sessions.wait_until_ended() log.info("All debug sessions have ended; exiting.")
def main(): from ptvsd.common import log from ptvsd.launcher import adapter, debuggee log.to_file(prefix="ptvsd.launcher") log.describe_environment("ptvsd.launcher startup environment:") def option(name, type, *args): try: return type(os.environ.pop(name, *args)) except Exception: raise log.exception("Error parsing {0!r}:", name) session_id = option("PTVSD_SESSION_ID", int) launcher_port = option("PTVSD_LAUNCHER_PORT", int) adapter.connect(session_id, launcher_port) adapter.channel.wait() if debuggee.process is not None: sys.exit(debuggee.process.returncode)
def main(args): from ptvsd.common import log, options as common_options from ptvsd.adapter import session, options as adapter_options if args.log_stderr: log.stderr_levels |= set(log.LEVELS) adapter_options.log_stderr = True if args.log_dir is not None: common_options.log_dir = args.log_dir log.to_file(prefix="ptvsd.adapter") log.describe_environment("ptvsd.adapter startup environment:") session = session.Session() if args.port is None: session.connect_to_ide() else: if args.for_server_on_port is not None: session.connect_to_server(("127.0.0.1", args.for_server_on_port)) with session.accept_connection_from_ide((args.host, args.port)) as (_, port): if session.server: session.server.set_debugger_property({"adapterPort": port}) session.wait_for_completion()
def pytest_report_header(config): log.describe_environment(fmt("Test environment for tests-{0}", os.getpid()))
def main(args): from ptvsd import adapter from ptvsd.common import compat, log, sockets from ptvsd.adapter import ide, servers, sessions if args.for_server is not None: if os.name == "posix": # On POSIX, we need to leave the process group and its session, and then # daemonize properly by double-forking (first fork already happened when # this process was spawned). os.setsid() if os.fork() != 0: sys.exit(0) for stdio in sys.stdin, sys.stdout, sys.stderr: if stdio is not None: stdio.close() if args.log_stderr: log.stderr.levels |= set(log.LEVELS) if args.log_dir is not None: log.log_dir = args.log_dir log.to_file(prefix="ptvsd.adapter") log.describe_environment("ptvsd.adapter startup environment:") servers.access_token = args.server_access_token if args.for_server is None: adapter.access_token = compat.force_str( codecs.encode(os.urandom(32), "hex")) try: server_host, server_port = servers.listen() except Exception as exc: if args.for_server is None: raise endpoints = { "error": "Can't listen for server connections: " + str(exc) } else: endpoints = {"server": {"host": server_host, "port": server_port}} try: ide_host, ide_port = ide.listen(port=args.port) except Exception as exc: if args.for_server is None: raise endpoints = { "error": "Can't listen for IDE connections: " + str(exc) } else: endpoints["ide"] = {"host": ide_host, "port": ide_port} if args.for_server is not None: log.info( "Sending endpoints info to debug server at localhost:{0}:\n{1!j}", args.for_server, endpoints, ) try: sock = sockets.create_client() try: sock.settimeout(None) sock.connect(("127.0.0.1", args.for_server)) sock_io = sock.makefile("wb", 0) try: sock_io.write(json.dumps(endpoints).encode("utf-8")) finally: sock_io.close() finally: sockets.close_socket(sock) except Exception: raise log.exception( "Error sending endpoints info to debug server:") if "error" in endpoints: log.error("Couldn't set up endpoints; exiting.") sys.exit(1) listener_file = os.getenv("PTVSD_ADAPTER_ENDPOINTS") if listener_file is not None: log.info("Writing endpoints info to {0!r}:\n{1!j}", listener_file, endpoints) def delete_listener_file(): log.info("Listener ports closed; deleting {0!r}", listener_file) try: os.remove(listener_file) except Exception: log.exception("Failed to delete {0!r}", listener_file, level="warning") try: with open(listener_file, "w") as f: atexit.register(delete_listener_file) print(json.dumps(endpoints), file=f) except Exception: raise log.exception("Error writing endpoints info to file:") if args.port is None: ide.IDE("stdio") # These must be registered after the one above, to ensure that the listener sockets # are closed before the endpoint info file is deleted - this way, another process # can wait for the file to go away as a signal that the ports are no longer in use. atexit.register(servers.stop_listening) atexit.register(ide.stop_listening) servers.wait_until_disconnected() log.info( "All debug servers disconnected; waiting for remaining sessions...") sessions.wait_until_ended() log.info("All debug sessions have ended; exiting.")
def main(args): from ptvsd import adapter from ptvsd.common import compat, log from ptvsd.adapter import ide, servers, sessions if args.log_stderr: log.stderr.levels |= set(log.LEVELS) if args.log_dir is not None: log.log_dir = args.log_dir log.to_file(prefix="ptvsd.adapter") log.describe_environment("ptvsd.adapter startup environment:") if args.for_server and args.port is None: log.error("--for-server requires --port") sys.exit(64) servers.access_token = args.server_access_token if not args.for_server: adapter.access_token = compat.force_str( codecs.encode(os.urandom(32), "hex")) server_host, server_port = servers.listen() ide_host, ide_port = ide.listen(port=args.port) endpoints_info = { "ide": { "host": ide_host, "port": ide_port }, "server": { "host": server_host, "port": server_port }, } if args.for_server: log.info("Writing endpoints info to stdout:\n{0!r}", endpoints_info) print(json.dumps(endpoints_info)) sys.stdout.flush() if args.port is None: ide.IDE("stdio") listener_file = os.getenv("PTVSD_ADAPTER_ENDPOINTS") if listener_file is not None: log.info("Writing endpoints info to {0!r}:\n{1!r}", listener_file, endpoints_info) def delete_listener_file(): log.info("Listener ports closed; deleting {0!r}", listener_file) try: os.remove(listener_file) except Exception: log.exception("Failed to delete {0!r}", listener_file, level="warning") with open(listener_file, "w") as f: atexit.register(delete_listener_file) print(json.dumps(endpoints_info), file=f) # These must be registered after the one above, to ensure that the listener sockets # are closed before the endpoint info file is deleted - this way, another process # can wait for the file to go away as a signal that the ports are no longer in use. atexit.register(servers.stop_listening) atexit.register(ide.stop_listening) servers.wait_until_disconnected() log.info( "All debug servers disconnected; waiting for remaining sessions...") sessions.wait_until_ended() log.info("All debug sessions have ended; exiting.")