forked from platformio/platformio-core
		
	
		
			
				
	
	
		
			138 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright (c) 2014-present PlatformIO <contact@platformio.org>
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
# you may not use this file except in compliance with the License.
 | 
						|
# You may obtain a copy of the License at
 | 
						|
#
 | 
						|
#    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
# See the License for the specific language governing permissions and
 | 
						|
# limitations under the License.
 | 
						|
 | 
						|
import os
 | 
						|
from os.path import isdir, isfile, join
 | 
						|
 | 
						|
from twisted.internet import reactor  # pylint: disable=import-error
 | 
						|
 | 
						|
from platformio import exception, fs, util
 | 
						|
from platformio.commands.debug.helpers import escape_gdbmi_stream, is_gdbmi_mode
 | 
						|
from platformio.commands.debug.process import BaseProcess
 | 
						|
from platformio.proc import where_is_program
 | 
						|
 | 
						|
 | 
						|
class DebugServer(BaseProcess):
 | 
						|
    def __init__(self, debug_options, env_options):
 | 
						|
        self.debug_options = debug_options
 | 
						|
        self.env_options = env_options
 | 
						|
 | 
						|
        self._debug_port = None
 | 
						|
        self._transport = None
 | 
						|
        self._process_ended = False
 | 
						|
 | 
						|
    def spawn(self, patterns):  # pylint: disable=too-many-branches
 | 
						|
        systype = util.get_systype()
 | 
						|
        server = self.debug_options.get("server")
 | 
						|
        if not server:
 | 
						|
            return None
 | 
						|
        server = self.apply_patterns(server, patterns)
 | 
						|
        server_executable = server["executable"]
 | 
						|
        if not server_executable:
 | 
						|
            return None
 | 
						|
        if server["cwd"]:
 | 
						|
            server_executable = join(server["cwd"], server_executable)
 | 
						|
        if (
 | 
						|
            "windows" in systype
 | 
						|
            and not server_executable.endswith(".exe")
 | 
						|
            and isfile(server_executable + ".exe")
 | 
						|
        ):
 | 
						|
            server_executable = server_executable + ".exe"
 | 
						|
 | 
						|
        if not isfile(server_executable):
 | 
						|
            server_executable = where_is_program(server_executable)
 | 
						|
        if not isfile(server_executable):
 | 
						|
            raise exception.DebugInvalidOptions(
 | 
						|
                "\nCould not launch Debug Server '%s'. Please check that it "
 | 
						|
                "is installed and is included in a system PATH\n\n"
 | 
						|
                "See documentation or contact contact@platformio.org:\n"
 | 
						|
                "http://docs.platformio.org/page/plus/debugging.html\n"
 | 
						|
                % server_executable
 | 
						|
            )
 | 
						|
 | 
						|
        self._debug_port = ":3333"
 | 
						|
        openocd_pipe_allowed = all(
 | 
						|
            [not self.debug_options["port"], "openocd" in server_executable]
 | 
						|
        )
 | 
						|
        if openocd_pipe_allowed:
 | 
						|
            args = []
 | 
						|
            if server["cwd"]:
 | 
						|
                args.extend(["-s", server["cwd"]])
 | 
						|
            args.extend(
 | 
						|
                ["-c", "gdb_port pipe; tcl_port disabled; telnet_port disabled"]
 | 
						|
            )
 | 
						|
            args.extend(server["arguments"])
 | 
						|
            str_args = " ".join(
 | 
						|
                [arg if arg.startswith("-") else '"%s"' % arg for arg in args]
 | 
						|
            )
 | 
						|
            self._debug_port = '| "%s" %s' % (server_executable, str_args)
 | 
						|
            self._debug_port = fs.to_unix_path(self._debug_port)
 | 
						|
        else:
 | 
						|
            env = os.environ.copy()
 | 
						|
            # prepend server "lib" folder to LD path
 | 
						|
            if (
 | 
						|
                "windows" not in systype
 | 
						|
                and server["cwd"]
 | 
						|
                and isdir(join(server["cwd"], "lib"))
 | 
						|
            ):
 | 
						|
                ld_key = (
 | 
						|
                    "DYLD_LIBRARY_PATH" if "darwin" in systype else "LD_LIBRARY_PATH"
 | 
						|
                )
 | 
						|
                env[ld_key] = join(server["cwd"], "lib")
 | 
						|
                if os.environ.get(ld_key):
 | 
						|
                    env[ld_key] = "%s:%s" % (env[ld_key], os.environ.get(ld_key))
 | 
						|
            # prepend BIN to PATH
 | 
						|
            if server["cwd"] and isdir(join(server["cwd"], "bin")):
 | 
						|
                env["PATH"] = "%s%s%s" % (
 | 
						|
                    join(server["cwd"], "bin"),
 | 
						|
                    os.pathsep,
 | 
						|
                    os.environ.get("PATH", os.environ.get("Path", "")),
 | 
						|
                )
 | 
						|
 | 
						|
            self._transport = reactor.spawnProcess(
 | 
						|
                self,
 | 
						|
                server_executable,
 | 
						|
                [server_executable] + server["arguments"],
 | 
						|
                path=server["cwd"],
 | 
						|
                env=env,
 | 
						|
            )
 | 
						|
            if "mspdebug" in server_executable.lower():
 | 
						|
                self._debug_port = ":2000"
 | 
						|
            elif "jlink" in server_executable.lower():
 | 
						|
                self._debug_port = ":2331"
 | 
						|
            elif "qemu" in server_executable.lower():
 | 
						|
                self._debug_port = ":1234"
 | 
						|
 | 
						|
        return self._transport
 | 
						|
 | 
						|
    def get_debug_port(self):
 | 
						|
        return self._debug_port
 | 
						|
 | 
						|
    def outReceived(self, data):
 | 
						|
        super(DebugServer, self).outReceived(
 | 
						|
            escape_gdbmi_stream("@", data) if is_gdbmi_mode() else data
 | 
						|
        )
 | 
						|
 | 
						|
    def processEnded(self, reason):
 | 
						|
        self._process_ended = True
 | 
						|
        super(DebugServer, self).processEnded(reason)
 | 
						|
 | 
						|
    def terminate(self):
 | 
						|
        if self._process_ended or not self._transport:
 | 
						|
            return
 | 
						|
        try:
 | 
						|
            self._transport.signalProcess("KILL")
 | 
						|
        except:  # pylint: disable=bare-except
 | 
						|
            pass
 |