Ejemplo n.º 1
0
def listen(address, settrace_kwargs):
    # Errors below are logged with level="info", because the caller might be catching
    # and handling exceptions, and we don't want to spam their stderr unnecessarily.

    import subprocess

    server_access_token = compat.force_str(codecs.encode(os.urandom(32), "hex"))

    try:
        endpoints_listener = sockets.create_server("127.0.0.1", 0, timeout=10)
    except Exception as exc:
        log.swallow_exception("Can't listen for adapter endpoints:")
        raise RuntimeError("can't listen for adapter endpoints: " + str(exc))
    endpoints_host, endpoints_port = endpoints_listener.getsockname()
    log.info(
        "Waiting for adapter endpoints on {0}:{1}...", endpoints_host, endpoints_port
    )

    host, port = address
    adapter_args = [
        sys.executable,
        os.path.dirname(adapter.__file__),
        "--for-server",
        str(endpoints_port),
        "--host",
        host,
        "--port",
        str(port),
        "--server-access-token",
        server_access_token,
    ]
    if log.log_dir is not None:
        adapter_args += ["--log-dir", log.log_dir]
    log.info("debugpy.listen() spawning adapter: {0!j}", adapter_args)

    # On Windows, detach the adapter from our console, if any, so that it doesn't
    # receive Ctrl+C from it, and doesn't keep it open once we exit.
    creationflags = 0
    if sys.platform == "win32":
        creationflags |= 0x08000000  # CREATE_NO_WINDOW
        creationflags |= 0x00000200  # CREATE_NEW_PROCESS_GROUP

    # Adapter will outlive this process, so we shouldn't wait for it. However, we
    # need to ensure that the Popen instance for it doesn't get garbage-collected
    # by holding a reference to it in a non-local variable, to avoid triggering
    # https://bugs.python.org/issue37380.
    try:
        global _adapter_process
        _adapter_process = subprocess.Popen(
            adapter_args, close_fds=True, creationflags=creationflags
        )
        if os.name == "posix":
            # It's going to fork again to daemonize, so we need to wait on it to
            # clean it up properly.
            _adapter_process.wait()
        else:
            # Suppress misleading warning about child process still being alive when
            # this process exits (https://bugs.python.org/issue38890).
            _adapter_process.returncode = 0
            pydevd.add_dont_terminate_child_pid(_adapter_process.pid)
    except Exception as exc:
        log.swallow_exception("Error spawning debug adapter:", level="info")
        raise RuntimeError("error spawning debug adapter: " + str(exc))

    try:
        sock, _ = endpoints_listener.accept()
        try:
            sock.settimeout(None)
            sock_io = sock.makefile("rb", 0)
            try:
                endpoints = json.loads(sock_io.read().decode("utf-8"))
            finally:
                sock_io.close()
        finally:
            sockets.close_socket(sock)
    except socket.timeout:
        log.swallow_exception("Timed out waiting for adapter to connect:", level="info")
        raise RuntimeError("timed out waiting for adapter to connect")
    except Exception as exc:
        log.swallow_exception("Error retrieving adapter endpoints:", level="info")
        raise RuntimeError("error retrieving adapter endpoints: " + str(exc))

    log.info("Endpoints received from adapter: {0!j}", endpoints)

    if "error" in endpoints:
        raise RuntimeError(str(endpoints["error"]))

    try:
        server_host = str(endpoints["server"]["host"])
        server_port = int(endpoints["server"]["port"])
        client_host = str(endpoints["client"]["host"])
        client_port = int(endpoints["client"]["port"])
    except Exception as exc:
        log.swallow_exception(
            "Error parsing adapter endpoints:\n{0!j}\n", endpoints, level="info"
        )
        raise RuntimeError("error parsing adapter endpoints: " + str(exc))
    log.info(
        "Adapter is accepting incoming client connections on {0}:{1}",
        client_host,
        client_port,
    )

    _settrace(
        host=server_host,
        port=server_port,
        wait_for_ready_to_run=False,
        block_until_connected=True,
        access_token=server_access_token,
        **settrace_kwargs
    )
    log.info("pydevd is connected to adapter at {0}:{1}", server_host, server_port)
    return client_host, client_port
        if hasattr(os, 'getppid'):
            print('%screated %s (child of %s)' %
                  ('\t' * (4 - n), os.getpid(), os.getppid()))
        else:
            print('%screated %s' % ('\t' * (4 - n), os.getpid()))

    elif 'check-subprocesses' in sys.argv or 'check-subprocesses-ignore-pid' in sys.argv:
        # Recursively create a process tree such as:
        # - parent (this process)
        #    - p3
        #      - p2
        #        - p1
        #          - p0
        #    - p3
        #      - p2
        #        - p1
        #          - p0
        p0 = subprocess.Popen(
            [sys.executable, __file__, 'launch-subprocesses', '3'])
        p1 = subprocess.Popen(
            [sys.executable, __file__, 'launch-subprocesses', '3'])

        if 'check-subprocesses-ignore-pid' in sys.argv:
            import pydevd
            pydevd.add_dont_terminate_child_pid(p0.pid)

        print('created', os.getpid())

    while True:
        time.sleep(.1)
Ejemplo n.º 3
0
Archivo: api.py Proyecto: yazici/ptvsd
def enable_attach(dont_trace_start_patterns, dont_trace_end_patterns):
    if hasattr(enable_attach, "called"):
        raise RuntimeError(
            "enable_attach() can only be called once per process.")

    server_access_token = compat.force_str(codecs.encode(
        os.urandom(32), "hex"))

    import subprocess

    adapter_args = [
        sys.executable,
        _ADAPTER_PATH,
        "--for-server",
        "--host",
        options.host,
        "--port",
        str(options.port),
        "--server-access-token",
        server_access_token,
    ]

    if log.log_dir is not None:
        adapter_args += ["--log-dir", log.log_dir]

    log.info("enable_attach() spawning adapter: {0!r}", adapter_args)

    # Adapter will outlive this process, so we shouldn't wait for it. However, we do
    # need to ensure that the Popen instance for it doesn't get garbage-collected, to
    # avoid triggering https://bugs.python.org/issue37380.
    enable_attach.process = process = subprocess.Popen(adapter_args,
                                                       bufsize=0,
                                                       stdout=subprocess.PIPE)

    line = process.stdout.readline()
    if isinstance(line, bytes):
        line = line.decode("utf-8")
    connection_details = json.JSONDecoder().decode(line)
    log.info("Connection details received from adapter: {0!r}",
             connection_details)

    host = "127.0.0.1"  # This should always be loopback address.
    port = connection_details["server"]["port"]

    pydevd.settrace(
        host=host,
        port=port,
        suspend=False,
        patch_multiprocessing=options.multiprocess,
        wait_for_ready_to_run=False,
        block_until_connected=True,
        dont_trace_start_patterns=dont_trace_start_patterns,
        dont_trace_end_patterns=dont_trace_end_patterns,
        access_token=server_access_token,
        client_access_token=options.client_access_token,
    )

    log.info("pydevd debug client connected to: {0}:{1}", host, port)

    # Ensure that we ignore the adapter process when terminating the debugger.
    pydevd.add_dont_terminate_child_pid(process.pid)
    options.port = connection_details["ide"]["port"]

    enable_attach.called = True
    log.info("ptvsd debug server running at: {0}:{1}", options.host,
             options.port)
    return options.host, options.port
Ejemplo n.º 4
0
def enable_attach(dont_trace_start_patterns, dont_trace_end_patterns):
    if hasattr(enable_attach, "called"):
        raise RuntimeError("enable_attach() can only be called once per process.")

    import subprocess

    adapter_args = [
        sys.executable,
        _ADAPTER_PATH,
        "--host",
        server_opts.host,
        "--port",
        str(server_opts.port),
        "--for-enable-attach",
    ]

    if common_opts.log_dir is not None:
        adapter_args += ["--log-dir", common_opts.log_dir]

    log.info("enable_attach() spawning adapter: {0!r}", adapter_args)

    # Adapter life time is expected to be longer than this process,
    # so never wait on the adapter process
    process = subprocess.Popen(adapter_args, bufsize=0, stdout=subprocess.PIPE)

    line = process.stdout.readline()
    if isinstance(line, bytes):
        line = line.decode("utf-8")
    connection_details = json.JSONDecoder().decode(line)
    log.info("Connection details received from adapter: {0!r}", connection_details)

    host = "127.0.0.1"  # This should always be loopback address.
    port = connection_details["server"]["port"]

    pydevd.settrace(
        host=host,
        port=port,
        suspend=False,
        patch_multiprocessing=server_opts.multiprocess,
        wait_for_ready_to_run=False,
        block_until_connected=True,
        dont_trace_start_patterns=dont_trace_start_patterns,
        dont_trace_end_patterns=dont_trace_end_patterns,
    )

    log.info("pydevd debug client connected to: {0}:{1}", host, port)

    # Ensure that we ignore the adapter process when terminating the debugger.
    pydevd.add_dont_terminate_child_pid(process.pid)
    server_opts.port = connection_details["ide"]["port"]

    listener_file = os.getenv("PTVSD_LISTENER_FILE")
    if listener_file is not None:
        with open(listener_file, "w") as f:
            json.dump({"host": server_opts.host, "port": server_opts.port}, f)

    enable_attach.called = True
    log.info(
        "ptvsd debug server running at: {0}:{1}", server_opts.host, server_opts.port
    )
    return server_opts.host, server_opts.port
Ejemplo n.º 5
0
def enable_attach(dont_trace_start_patterns, dont_trace_end_patterns):
    if hasattr(enable_attach, "called"):
        raise RuntimeError("enable_attach() can only be called once per process.")

    host, port = pydevd._enable_attach(
        ("127.0.0.1", 0),
        dont_trace_start_patterns=dont_trace_start_patterns,
        dont_trace_end_paterns=dont_trace_end_patterns,
        patch_multiprocessing=server_opts.multiprocess,
    )

    log.info("pydevd debug server running at: {0}:{1}", host, port)

    class _DAPMessagesListener(pydevd.IDAPMessagesListener):
        def before_send(self, msg):
            pass

        def after_receive(self, msg):
            try:
                if msg["command"] == "setDebuggerProperty":
                    port_queue.put(msg["arguments"]["adapterPort"])
            except KeyError:
                pass

    port_queue = queue.Queue()
    pydevd.add_dap_messages_listener(_DAPMessagesListener())

    with pydevd.skip_subprocess_arg_patch():
        import subprocess

        adapter_args = [
            sys.executable,
            os.path.join(os.path.dirname(ptvsd.__file__), "adapter"),
            "--host",
            server_opts.host,
            "--port",
            str(server_opts.port),
            "--for-server-on-port",
            str(port),
        ]

        if common_opts.log_dir is not None:
            adapter_args += ["--log-dir", common_opts.log_dir]

        log.info("enable_attach() spawning adapter: {0!r}", adapter_args)

        # Adapter life time is expected to be longer than this process,
        # so never wait on the adapter process
        process = subprocess.Popen(adapter_args, bufsize=0)
        # Ensure that we ignore the adapter process when terminating the
        # debugger. 
        pydevd.add_dont_terminate_child_pid(process.pid)

    server_opts.port = port_queue.get(True, _QUEUE_TIMEOUT)

    listener_file = os.getenv("PTVSD_LISTENER_FILE")
    if listener_file is not None:
        with open(listener_file, "w") as f:
            json.dump({"host": server_opts.host, "port": server_opts.port}, f)

    enable_attach.called = True
    log.info(
        "ptvsd debug server running at: {0}:{1}", server_opts.host, server_opts.port
    )
    return server_opts.host, server_opts.port