📄 debuggerservice.py
字号:
for openDoc in openDocs:
# This ugliness to prevent comparison failing because the drive letter
# gets lowercased occasionally. Don't know why that happens or why it
# only happens occasionally.
if DebuggerService.ComparePaths(openDoc.GetFilename(),filename):
foundView = openDoc.GetFirstView()
break
if not foundView:
if _VERBOSE:
print "filename=", filename
doc = wx.GetApp().GetDocumentManager().CreateDocument(DebuggerService.ExpandPath(filename), wx.lib.docview.DOC_SILENT)
foundView = doc.GetFirstView()
if foundView:
foundView.GetFrame().SetFocus()
foundView.Activate()
foundView.GotoLine(lineNum)
startPos = foundView.PositionFromLine(lineNum)
if not noArrow:
foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM)
def DeleteCurrentLineMarkers(self):
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
for openDoc in openDocs:
if(isinstance(openDoc, CodeEditor.CodeDocument)):
openDoc.GetFirstView().GetCtrl().ClearCurrentLineMarkers()
def StopAndRemoveUI(self, event):
self.StopExecution(None)
if self in BaseDebuggerUI.debuggers:
BaseDebuggerUI.debuggers.remove(self)
index = self._parentNoteBook.GetSelection()
self._parentNoteBook.GetPage(index).Show(False)
self._parentNoteBook.RemovePage(index)
def OnAddWatch(self, event):
if self.framesTab:
self.framesTab.OnWatch(event)
def MakeFramesUI(self, parent, id, debugger):
assert False, "MakeFramesUI not overridden"
def AppendText(self, event):
self.framesTab.AppendText(event.value)
def AppendErrorText(self, event):
self.framesTab.AppendErrorText(event.value)
def OnClearOutput(self, event):
self.framesTab.ClearOutput(None)
def SwitchToOutputTab(self):
self.framesTab.SwitchToOutputTab()
class PHPDebuggerUI(BaseDebuggerUI):
DEFAULT_LISTENER_HOST = "127.0.0.1"
DEFAULT_LISTENER_PORT = 10001
DEFAULT_DBG_MOD_TIMEOUT = 300
DEFAULT_DBG_MAX_EXEC_TIME = 240
dbgSessSeqId = 1
def __init__(self, parent, id, command, service):
BaseDebuggerUI.__init__(self, parent, id)
#Note host and port need to come out of options or a pool.
self._dbgHost = PHPDebuggerUI.DEFAULT_LISTENER_HOST
self._dbgPort = PHPDebuggerUI.DEFAULT_LISTENER_PORT
self._dbgTimeout = PHPDebuggerUI.DEFAULT_DBG_MOD_TIMEOUT
self._dbgMaxExecTime = PHPDebuggerUI.DEFAULT_DBG_MAX_EXEC_TIME
self._dbgSessId = None
self._dbgSessParam = None
self._dbgPhpIniFile = None
self._callback = PHPDebugger.PHPDebuggerCallback(self, service, self._dbgHost, self._dbgPort)
self._executor = Executor(command, self)
self._service = service
self._stopped = False
self._allStopped = False
self._createPhpDbgSess()
def showErrorDialog(self, message, title):
wx.MessageBox(_(message), _(title))
return
def _createPhpDbgSess(self):
currTimeStr = str(time.time())
(secStr, usecStr) = currTimeStr.split('.')
secLongInt = long(secStr)
usecLongInt = long(usecStr)
self._dbgSessId = "%06ld%06ld%04d" % (secLongInt, usecLongInt, PHPDebuggerUI.dbgSessSeqId)
PHPDebuggerUI.dbgSessSeqId = PHPDebuggerUI.dbgSessSeqId + 1
self._dbgSessParam = "DBGSESSID=%s@clienthost:%d" % (self._dbgSessId, self._dbgPort)
if _VERBOSE:
print "phpDbgParam=%s" % self._dbgSessParam
self._service.SetPhpDbgParam(self._dbgSessParam)
def _preparePhpIniFile(self):
success = False
phpCgiExec = Executor.GetPHPExecutablePath()
phpExec = phpCgiExec.replace("php-cgi", "php")
iniPath = self._getPhpIniFromRunningPhp(phpExec)
try:
iniDbgPath = os.path.normpath(iniPath + ".ag_debug_enabled")
dbgFile = open(iniDbgPath, "w")
oriFile = open(iniPath, "r")
while True:
oneOriLine = oriFile.readline()
if oneOriLine == '':
break
if not oneOriLine.startswith("debugger.") and not oneOriLine.startswith("max_execution_time="):
dbgFile.write(oneOriLine)
oriFile.close()
if _WINDOWS:
dbgExtFile = "php_dbg.dll"
else:
dbgExtFile = "dbg.so"
#
# TODO: we should make all of these options configurable.
#
configStr = "\n; ===============================================================\n; The followings are added by ActiveGrid IDE PHP Debugger Runtime\n; ===============================================================\n\n; As we are running with the dbg module, it takes a much longer time for each script to run.\nmax_execution_time=%d\n\n[debugger]\nextension=%s\ndebugger.enabled=On\ndebugger.JIT_enabled=On\ndebugger.JIT_host=%s\ndebugger.JIT_port=%d\ndebugger.fail_silently=Off\ndebugger.timeout_seconds=%d\ndebugger.ignore_nops=Off\ndebugger.enable_session_cookie=On\ndebugger.session_nocache=On\ndebugger.profiler_enabled=Off\n" % (self._dbgMaxExecTime, dbgExtFile, self._dbgHost, self._dbgPort, self._dbgTimeout)
dbgFile.write(configStr)
dbgFile.close()
success = True
except:
#TODO: print stack trace.
print "Caught exceptions while minipulating php.ini files"
if success:
self._dbgPhpIniFile = iniDbgPath
else:
self._dbgPhpIniFile = None
def _getPhpIniFromRunningPhp(self, phpExec):
phpIniPath = None
cmdEnv = os.environ
if cmdEnv.has_key('PYTHONPATH'):
del cmdEnv['PYTHONPATH']
cmdLine = [phpExec, "-r", "phpinfo();"]
phpProc = subprocess.Popen(args=cmdLine, bufsize=0, executable=None, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=os.environ, universal_newlines=False, startupinfo=None, creationflags=0)
phpOutput = phpProc.stdout
phpIniPattern = "Configuration File (php.ini) Path => "
while True:
oneLine = phpOutput.readline()
if oneLine == '':
break
if oneLine.startswith(phpIniPattern):
if oneLine.endswith("\n"):
endIndex = oneLine.index("\n")
phpIniPath = oneLine[len(phpIniPattern):endIndex]
else:
phpIniPath = oneLine[len(phpIniPattern):]
if phpIniPath and len(phpIniPath) > 0:
phpIniPath = os.path.normpath(phpIniPath)
break
phpOutput.close()
if _VERBOSE:
print "php.ini path is: %s" % repr(phpIniPath)
return phpIniPath
def Execute(self, initialArgs, startIn, environment, onWebServer = False):
self._preparePhpIniFile()
self._callback.Start()
if not onWebServer:
if self._dbgPhpIniFile:
args = '-c "' + self._dbgPhpIniFile + '" ' + initialArgs
else:
args = initialArgs
self._executor.Execute(args, startIn, environment)
def StopExecution(self, event):
# This is a general comment on shutdown for the running and debugged processes. Basically, the
# current state of this is the result of trial and error coding. The common problems were memory
# access violations and threads that would not exit. Making the OutputReaderThreads daemons seems
# to have side-stepped the hung thread issue. Being very careful not to touch things after calling
# process.py:ProcessOpen.kill() also seems to have fixed the memory access violations, but if there
# were more ugliness discovered I would not be surprised. If anyone has any help/advice, please send
# it on to mfryer@activegrid.com.
if not self._allStopped:
self._stopped = True
try:
self.DisableAfterStop()
except wx._core.PyDeadObjectError:
pass
try:
#
# If this is called by clicking the "Stop" button, we only stop
# the current running php script, and keep the listener
# running.
#
if event:
self._callback.ShutdownServer(stopLsnr = False)
else:
self._callback.ShutdownServer(stopLsnr = True)
self._allStopped = True
except:
tp,val,tb = sys.exc_info()
traceback.print_exception(tp, val, tb)
try:
self.DeleteCurrentLineMarkers()
except:
pass
try:
if self._executor:
self._executor.DoStopExecution()
self._executor = None
except:
tp,val,tb = sys.exc_info()
traceback.print_exception(tp, val, tb)
def MakeFramesUI(self, parent, id, debugger):
return PHPFramesUI(parent, id, self)
def LoadPHPFramesList(self, stackList):
self.framesTab.LoadFramesList(stackList)
#
# TODO: this is a hack to overwrite BaseDebuggerUI's function. The purpose
# is to always push breakpoints no matter if a php is running or not. If
# no php is running, an exception will be thrown and handled like nothing
# happened.
#
def BreakPointChange(self):
self._callback.PushBreakpoints()
self.framesTab.PopulateBPList()
class PythonDebuggerUI(BaseDebuggerUI):
debuggerPortList = None
def GetAvailablePort():
for index in range( 0, len(PythonDebuggerUI.debuggerPortList)):
port = PythonDebuggerUI.debuggerPortList[index]
if PythonDebuggerUI.PortAvailable(port):
PythonDebuggerUI.debuggerPortList.pop(index)
return port
wx.MessageBox(_("Out of ports for debugging! Please restart the application builder.\nIf that does not work, check for and remove running instances of python."), _("Out of Ports"))
assert False, "Out of ports for debugger."
GetAvailablePort = staticmethod(GetAvailablePort)
def ReturnPortToPool(port):
config = wx.ConfigBase_Get()
startingPort = config.ReadInt("DebuggerStartingPort", DEFAULT_PORT)
val = int(startingPort) + int(PORT_COUNT)
if int(port) >= startingPort and (int(port) <= val):
PythonDebuggerUI.debuggerPortList.append(int(port))
ReturnPortToPool = staticmethod(ReturnPortToPool)
def PortAvailable(port):
config = wx.ConfigBase_Get()
hostname = config.Read("DebuggerHostName", DEFAULT_HOST)
try:
server = AGXMLRPCServer((hostname, port))
server.server_close()
if _VERBOSE: print "Port ", str(port), " available."
return True
except:
tp,val,tb = sys.exc_info()
if _VERBOSE: traceback.print_exception(tp, val, tb)
if _VERBOSE: print "Port ", str(port), " unavailable."
return False
PortAvailable = staticmethod(PortAvailable)
def NewPortRange():
config = wx.ConfigBase_Get()
startingPort = config.ReadInt("DebuggerStartingPort", DEFAULT_PORT)
PythonDebuggerUI.debuggerPortList = range(startingPort, startingPort + PORT_COUNT)
NewPortRange = staticmethod(NewPortRange)
def __init__(self, parent, id, command, service, autoContinue=True):
# Check for ports before creating the panel.
if not PythonDebuggerUI.debuggerPortList:
PythonDebuggerUI.NewPortRange()
self._debuggerPort = str(PythonDebuggerUI.GetAvailablePort())
self._guiPort = str(PythonDebuggerUI.GetAvailablePort())
self._debuggerBreakPort = str(PythonDebuggerUI.GetAvailablePort())
BaseDebuggerUI.__init__(self, parent, id)
self._command = command
self._service = service
config = wx.ConfigBase_Get()
self._debuggerHost = self._guiHost = config.Read("DebuggerHostName", DEFAULT_HOST)
url = 'http://' + self._debuggerHost + ':' + self._debuggerPort + '/'
self._breakURL = 'http://' + self._debuggerHost + ':' + self._debuggerBreakPort + '/'
self._callback = PythonDebuggerCallback(self._guiHost, self._guiPort, url, self._breakURL, self, autoContinue)
if DebuggerHarness.__file__.find('library.zip') > 0:
try:
fname = DebuggerHarness.__file__
parts = fname.split('library.zip')
path = os.path.join(parts[0],'activegrid', 'tool', 'DebuggerHarness.py')
except:
tp, val, tb = sys.exc_info()
traceback.print_exception(tp, val, tb)
else:
print "Starting debugger on these ports: %s, %s, %s" % (str(self._debuggerPort) , str(self._guiPort) , str(self._debuggerBreakPort))
path = DebuggerService.ExpandPath(DebuggerHarness.__file__)
self._executor = Executor(path, self, self._debuggerHost, \
self._debuggerPort, self._debuggerBreakPort, self._guiHost, self._guiPort, self._command, callbackOnExit=self.ExecutorFinished)
self._stopped = False
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -