123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- #########################################################################
- """ wingdbstub.py -- Debug stub for debuggifying Python programs
-
- Copyright (c) 1999-2001, Archaeopteryx Software, Inc. All rights reserved.
-
- Written by Stephan R.A. Deibel and John P. Ehresman
-
- Usage:
- -----
-
- This is the file that Wing DB users copy into their python project
- directory if they want to be able to debug programs that are launched
- outside of the IDE (e.g., CGI scripts, in response to a browser page
- load).
-
- To use this, edit the configuration values below to match your
- Wing installation and requirements of your project.
-
- Then, add the following line to your code:
-
- import wingdbstub
-
- Debugging will start immediately after this import statements.
-
- Next make sure that your IDE is running and that it's configured to accept
- connections from the host the debug program will be running on.
-
- Now, invoking your python file should run the code within the debugger.
- Note, however, that Wing will not stop in the code unless a breakpoint
- is set.
-
- If the debug process is started before the IDE, or is not listening
- at the time this module is imported then the program will run with
- debugging until an attach request is seen. Attaching only works
- if the .wingdebugpw file is present; see the manual for details.
-
- On win32, you either need to edit WINGHOME in this script or
- pass in an environment variable called WINGHOME that points to
- the Wing installation directory.
-
- """
- #########################################################################
-
- import sys
- import os
- import imp
-
-
- #------------------------------------------------------------------------
- # Default configuration values: Note that the named environment
- # variables, if set, will override these settings.
-
- # Set this to 1 to disable all debugging; 0 to enable debugging
- # (WINGDB_DISABLED environment variable)
- kWingDebugDisabled = 0
-
- # Host:port of the IDE within which to debug: As configured in the IDE
- # with the Server Port preference
- # (WINGDB_HOSTPORT environment variable)
- kWingHostPort = 'localhost:50005'
-
- # Port on which to listen for connection requests, so that the
- # IDE can (re)attach to the debug process after it has started.
- # Set this to '-1' to disable listening for connection requests.
- # This is only used when the debug process is not attached to
- # an IDE or the IDE has dropped its connection. The configured
- # port can optionally be added to the IDE's Common Attach Hosts
- # preference. Note that a random port is used instead if this
- # port is already in use!
- # (WINGDB_ATTACHPORT environment variable)
- kAttachPort = '50015'
-
- # Set this to a filename to log verbose information about the debugger
- # internals to a file. If the file does not exist, it will be created
- # as long as its enclosing directory exists and is writeable. Use
- # "<stderr>" or "<stdout>". Note that "<stderr>" may cause problems
- # on win32 if the debug process is not running in a console.
- # (WINGDB_LOGFILE environment variable)
- kLogFile = None
-
- # Set to get a tremendous amount of logging from the debugger internals
- # (WINGDB_LOGVERYVERBOSE)
- kLogVeryVerbose = 0
-
- # Set this to 1 when debugging embedded scripts in an environment that
- # creates and reuses a Python instance across multiple script invocations:
- # It turns off automatic detection of program quit so that the debug session
- # can span multiple script invocations. When this is turned on, you may
- # need to call ProgramQuit() on the debugger object to shut down the
- # debugger cleanly when your application exits or discards the Python
- # instance. If multiple Python instances are created in the same run,
- # only the first one will be able to debug unless it terminates debug
- # and the environment variable WINGDB_ACTIVE is unset before importing
- # this module in the second or later Python instance. See the Wing
- # IDE manual for details.
- kEmbedded = 0
-
- # Path to search for the debug password file and the name of the file
- # to use. The password file contains the encryption type and connect
- # password for all connections to the IDE and must match the wingdebugpw
- # file in the profile dir used by the IDE. Any entry of '$<winguserprofile>'
- # is replaced by the wing user profile directory for the user that the
- # current process is running as
- # (WINGDB_PWFILEPATH environment variable)
- kPWFilePath = [os.path.dirname(__file__), '$<winguserprofile>']
- kPWFileName = 'wingdebugpw'
-
- # Whether to exit if the debugger fails to run or to connect with an IDE
- # for whatever reason
- kExitOnFailure = 0
-
- #------------------------------------------------------------------------
- # Find Wing debugger installation location
-
- # Edit this to point to your Wing installation or set to None to use env WINGHOME
- # On OS X this must be set to name of the Wing application bundle
- # (for example, /Applications/WingIDE.app)
- WINGHOME = None
-
- if sys.hexversion >= 0x03000000:
- def has_key(o, key):
- return key in o
- else:
- def has_key(o, key):
- return o.has_key(key)
-
- # Check environment: Must have WINGHOME defined if still == None
- if WINGHOME == None:
- if has_key(os.environ, 'WINGHOME'):
- WINGHOME=os.environ['WINGHOME']
- else:
- sys.stdout.write("*******************************************************************\n")
- sys.stdout.write("Error: Could not find Wing installation! You must set WINGHOME or edit\n")
- sys.stdout.write("wingdbstub.py where indicated to point it to the location where\n")
- sys.stdout.write("Wing is installed.\n")
- sys.exit(1)
-
- kPWFilePath.append(WINGHOME)
-
- # The user settings dir where per-user settings & patches are located. Will be
- # set from environment if left as None
- kUserSettingsDir = None
- if kUserSettingsDir is None:
- kUserSettingsDir = os.environ.get('WINGDB_USERSETTINGS')
-
- def _FindActualWingHome(winghome):
- """ Find the actual directory to use for winghome. Needed on OS X
- where the .app directory is the preferred dir to use for WINGHOME and
- .app/Contents/MacOS is accepted for backward compatibility. """
-
- if sys.platform != 'darwin':
- return winghome
-
- app_dir = None
- if os.path.isdir(winghome):
- if winghome.endswith('/'):
- wo_slash = winghome[:-1]
- else:
- wo_slash = winghome
-
- if wo_slash.endswith('.app'):
- app_dir = wo_slash
- elif wo_slash.endswith('.app/Contents/MacOS'):
- app_dir = wo_slash[:-len('/Contents/MacOS')]
-
- if app_dir and os.path.isdir(os.path.join(app_dir, 'Contents', 'Resources')):
- return os.path.join(app_dir, 'Contents', 'Resources')
-
- return winghome
-
- def _ImportWingdb(winghome, user_settings=None):
- """ Find & import wingdb module. """
-
- try:
- exec_dict = {}
- execfile(os.path.join(winghome, 'bin', '_patchsupport.py'), exec_dict)
- find_matching = exec_dict['FindMatching']
- dir_list = find_matching('bin', winghome, user_settings)
- except Exception:
- dir_list = []
- dir_list.extend([os.path.join(winghome, 'bin'), os.path.join(winghome, 'src')])
- for path in dir_list:
- try:
- f, p, d = imp.find_module('wingdb', [path])
- try:
- return imp.load_module('wingdb', f, p, d)
- finally:
- if f is not None:
- f.close()
- break
- except ImportError:
- pass
-
- #------------------------------------------------------------------------
- # Set debugger if it hasn't been set -- this is to handle module reloading
- # In the reload case, the debugger variable will be set to something
- try:
- debugger
- except NameError:
- debugger = None
-
- # Unset WINGDB_ACTIVE env if it was inherited from another process
- # XXX Would be better to be able to call getpid() on dbgtracer but can't access it yet
- if 'WINGDB_ACTIVE' in os.environ and os.environ['WINGDB_ACTIVE'] != str(os.getpid()):
- del os.environ['WINGDB_ACTIVE']
-
- # Start debugging if not disabled and this module has never been imported
- # before
- if (not kWingDebugDisabled and debugger is None
- and not has_key(os.environ, 'WINGDB_DISABLED') and
- not has_key(os.environ, 'WINGDB_ACTIVE')):
-
- exit_on_fail = 0
-
- try:
- # Obtain exit if fails value
- exit_on_fail = os.environ.get('WINGDB_EXITONFAILURE', kExitOnFailure)
-
- # Obtain configuration for log file to use, if any
- logfile = os.environ.get('WINGDB_LOGFILE', kLogFile)
- if logfile == '-' or logfile == None or len(logfile.strip()) == 0:
- logfile = None
-
- very_verbose_log = os.environ.get('WINGDB_LOGVERYVERBOSE', kLogVeryVerbose)
- if type(very_verbose_log) == type('') and very_verbose_log.strip() == '':
- very_verbose_log = 0
-
- # Determine remote host/port where the IDE is running
- hostport = os.environ.get('WINGDB_HOSTPORT', kWingHostPort)
- colonpos = hostport.find(':')
- host = hostport[:colonpos]
- port = int(hostport[colonpos+1:])
-
- # Determine port to listen on locally for attach requests
- attachport = int(os.environ.get('WINGDB_ATTACHPORT', kAttachPort))
-
- # Check if running embedded script
- embedded = int(os.environ.get('WINGDB_EMBEDDED', kEmbedded))
-
- # Obtain debug password file search path
- if has_key(os.environ, 'WINGDB_PWFILEPATH'):
- pwfile_path = os.environ['WINGDB_PWFILEPATH'].split(os.pathsep)
- else:
- pwfile_path = kPWFilePath
-
- # Obtain debug password file name
- if has_key(os.environ, 'WINGDB_PWFILENAME'):
- pwfile_name = os.environ['WINGDB_PWFILENAME']
- else:
- pwfile_name = kPWFileName
-
- # Load wingdb.py
- actual_winghome = _FindActualWingHome(WINGHOME)
- wingdb = _ImportWingdb(actual_winghome, kUserSettingsDir)
- if wingdb == None:
- sys.stdout.write("*******************************************************************\n")
- sys.stdout.write("Error: Cannot find wingdb.py in $(WINGHOME)/bin or $(WINGHOME)/src\n")
- sys.stdout.write("Error: Please check the WINGHOME definition in wingdbstub.py\n")
- sys.exit(2)
-
- # Find the netserver module and create an error stream
- netserver = wingdb.FindNetServerModule(actual_winghome, kUserSettingsDir)
- err = wingdb.CreateErrStream(netserver, logfile, very_verbose_log)
-
- # Start debugging
- debugger = netserver.CNetworkServer(host, port, attachport, err,
- pwfile_path=pwfile_path,
- pwfile_name=pwfile_name,
- autoquit=not embedded)
- debugger.StartDebug(stophere=0)
- os.environ['WINGDB_ACTIVE'] = str(os.getpid())
- if debugger.ChannelClosed():
- raise ValueError('Not connected')
-
- except:
- if exit_on_fail:
- raise
- else:
- pass
-
- def Ensure(require_connection=1, require_debugger=1):
- """ Ensure the debugger is started and attempt to connect to the IDE if
- not already connected. Will raise a ValueError if:
-
- * the require_connection arg is true and the debugger is unable to connect
- * the require_debugger arg is true and the debugger cannot be loaded
-
- If SuspendDebug() has been called through the low-level API, calling
- Ensure() resets the suspend count to zero and additional calls to
- ResumeDebug() will be ignored until SuspendDebug() is called again.
-
- Note that a change to the host & port to connect to will only
- be use if a new connection is made.
-
- """
-
- if debugger is None:
- if require_debugger:
- raise ValueError("No debugger")
- return
-
- hostport = os.environ.get('WINGDB_HOSTPORT', kWingHostPort)
- colonpos = hostport.find(':')
- host = hostport[:colonpos]
- port = int(hostport[colonpos+1:])
-
- resumed = debugger.ResumeDebug()
- while resumed > 0:
- resumed = debugger.ResumeDebug()
-
- debugger.SetClientAddress((host, port))
-
- if not debugger.DebugActive():
- debugger.StartDebug()
- elif debugger.ChannelClosed():
- debugger.ConnectToClient()
-
- if require_connection and debugger.ChannelClosed():
- raise ValueError('Not connected')
-
|