238 lines
7.7 KiB
Python
238 lines
7.7 KiB
Python
|
import os
|
||
|
import sys
|
||
|
import gluon.dal
|
||
|
import gluon.html
|
||
|
import gluon.validators
|
||
|
import code
|
||
|
from gluon.debug import communicate, web_debugger, dbg_debugger
|
||
|
from gluon._compat import thread
|
||
|
from gluon.fileutils import open_file
|
||
|
import pydoc
|
||
|
|
||
|
|
||
|
if DEMO_MODE or MULTI_USER_MODE:
|
||
|
session.flash = T('disabled in demo mode')
|
||
|
redirect(URL('default', 'site'))
|
||
|
|
||
|
FE = 10 ** 9
|
||
|
|
||
|
|
||
|
def index():
|
||
|
app = request.args(0) or 'admin'
|
||
|
reset()
|
||
|
# read buffer
|
||
|
data = communicate()
|
||
|
return dict(app=app, data=data)
|
||
|
|
||
|
|
||
|
def callback():
|
||
|
app = request.args[0]
|
||
|
command = request.vars.statement
|
||
|
session['debug_commands:' + app].append(command)
|
||
|
output = communicate(command)
|
||
|
k = len(session['debug_commands:' + app]) - 1
|
||
|
return '[%i] %s%s\n' % (k + 1, command, output)
|
||
|
|
||
|
|
||
|
def reset():
|
||
|
app = request.args(0) or 'admin'
|
||
|
session['debug_commands:' + app] = []
|
||
|
return 'done'
|
||
|
|
||
|
|
||
|
# new implementation using dbg
|
||
|
|
||
|
def interact():
|
||
|
app = request.args(0) or 'admin'
|
||
|
reset()
|
||
|
|
||
|
# process all pending messages in the frontend
|
||
|
web_debugger.run()
|
||
|
|
||
|
# if debugging, filename and lineno should have valid values
|
||
|
filename = web_debugger.filename
|
||
|
lineno = web_debugger.lineno
|
||
|
if filename:
|
||
|
# prevent IOError 2 on some circuntances (EAFP instead of os.access)
|
||
|
try:
|
||
|
lines = open_file(filename, 'r').readlines()
|
||
|
except:
|
||
|
lines = ""
|
||
|
lines = dict([(i + 1, l) for (i, l) in enumerate(
|
||
|
[l.strip("\n").strip("\r") for l in lines])])
|
||
|
filename = os.path.basename(filename)
|
||
|
else:
|
||
|
lines = {}
|
||
|
|
||
|
if filename:
|
||
|
web_debugger.set_burst(2)
|
||
|
env = web_debugger.do_environment()
|
||
|
f_locals = env['locals']
|
||
|
f_globals = {}
|
||
|
for name, value in env['globals'].items():
|
||
|
if name not in gluon.html.__all__ and \
|
||
|
name not in gluon.validators.__all__:
|
||
|
f_globals[name] = pydoc.text.repr(value)
|
||
|
else:
|
||
|
f_locals = {}
|
||
|
f_globals = {}
|
||
|
response.headers['refresh'] = "3"
|
||
|
|
||
|
if web_debugger.exception_info:
|
||
|
response.flash = T('"User Exception" debug mode. '
|
||
|
'An error ticket could be issued!')
|
||
|
|
||
|
return dict(app=app, data="",
|
||
|
filename=web_debugger.filename, lines=lines, lineno=lineno,
|
||
|
f_globals=f_globals, f_locals=f_locals,
|
||
|
exception=web_debugger.exception_info)
|
||
|
|
||
|
|
||
|
def step():
|
||
|
web_debugger.do_step()
|
||
|
redirect(URL("interact"))
|
||
|
|
||
|
|
||
|
def next():
|
||
|
web_debugger.do_next()
|
||
|
redirect(URL("interact"))
|
||
|
|
||
|
|
||
|
def cont():
|
||
|
web_debugger.do_continue()
|
||
|
redirect(URL("interact"))
|
||
|
|
||
|
|
||
|
def ret():
|
||
|
web_debugger.do_return()
|
||
|
redirect(URL("interact"))
|
||
|
|
||
|
|
||
|
def stop():
|
||
|
web_debugger.do_quit()
|
||
|
redirect(URL("interact"))
|
||
|
|
||
|
|
||
|
def execute():
|
||
|
app = request.args[0]
|
||
|
command = request.vars.statement
|
||
|
session['debug_commands:' + app].append(command)
|
||
|
try:
|
||
|
output = web_debugger.do_exec(command)
|
||
|
if output is None:
|
||
|
output = ""
|
||
|
except Exception as e:
|
||
|
output = T("Exception %s") % str(e)
|
||
|
k = len(session['debug_commands:' + app]) - 1
|
||
|
return '[%i] %s%s\n' % (k + 1, command, output)
|
||
|
|
||
|
|
||
|
def breakpoints():
|
||
|
"Add or remove breakpoints"
|
||
|
|
||
|
# Get all .py files
|
||
|
files = listdir(apath('', r=request), '.*\.py$')
|
||
|
files = [filename for filename in files
|
||
|
if filename and 'languages' not in filename
|
||
|
and not filename.startswith("admin")
|
||
|
and not filename.startswith("examples")]
|
||
|
|
||
|
form = SQLFORM.factory(
|
||
|
Field('filename', requires=IS_IN_SET(files), label=T("Filename")),
|
||
|
Field('lineno', 'integer', label=T("Line number"),
|
||
|
requires=IS_NOT_EMPTY()),
|
||
|
Field('temporary', 'boolean', label=T("Temporary"),
|
||
|
comment=T("deleted after first hit")),
|
||
|
Field('condition', 'string', label=T("Condition"),
|
||
|
comment=T("honored only if the expression evaluates to true")),
|
||
|
)
|
||
|
|
||
|
if form.accepts(request.vars, session):
|
||
|
filename = os.path.join(request.env['applications_parent'],
|
||
|
'applications', form.vars.filename)
|
||
|
err = dbg_debugger.do_set_breakpoint(filename,
|
||
|
form.vars.lineno,
|
||
|
form.vars.temporary,
|
||
|
form.vars.condition)
|
||
|
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
||
|
filename, form.vars.lineno, err or T('successful'))
|
||
|
|
||
|
for item in request.vars:
|
||
|
if item[:7] == 'delete_':
|
||
|
dbg_debugger.do_clear(item[7:])
|
||
|
|
||
|
breakpoints = [{'number': bp[0], 'filename': os.path.basename(bp[1]),
|
||
|
'path': bp[1], 'lineno': bp[2],
|
||
|
'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5],
|
||
|
'condition': bp[6]}
|
||
|
for bp in dbg_debugger.do_list_breakpoint()]
|
||
|
|
||
|
return dict(breakpoints=breakpoints, form=form)
|
||
|
|
||
|
|
||
|
def toggle_breakpoint():
|
||
|
"Set or clear a breakpoint"
|
||
|
|
||
|
lineno = None
|
||
|
ok = None
|
||
|
try:
|
||
|
filename = os.path.join(request.env['applications_parent'],
|
||
|
'applications', request.vars.filename)
|
||
|
# normalize path name: replace slashes, references, etc...
|
||
|
filename = os.path.normpath(os.path.normcase(filename))
|
||
|
if not request.vars.data:
|
||
|
# ace send us the line number!
|
||
|
lineno = int(request.vars.sel_start) + 1
|
||
|
else:
|
||
|
# editarea send us the offset, manually check the cursor pos
|
||
|
start = 0
|
||
|
sel_start = int(request.vars.sel_start)
|
||
|
for lineno, line in enumerate(request.vars.data.split("\n")):
|
||
|
if sel_start <= start:
|
||
|
break
|
||
|
start += len(line) + 1
|
||
|
else:
|
||
|
lineno = None
|
||
|
if lineno is not None:
|
||
|
for bp in dbg_debugger.do_list_breakpoint():
|
||
|
no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp
|
||
|
# normalize path name: replace slashes, references, etc...
|
||
|
bp_filename = os.path.normpath(os.path.normcase(bp_filename))
|
||
|
if filename == bp_filename and lineno == bp_lineno:
|
||
|
err = dbg_debugger.do_clear_breakpoint(filename, lineno)
|
||
|
response.flash = T("Removed Breakpoint on %s at line %s", (
|
||
|
filename, lineno))
|
||
|
ok = False
|
||
|
break
|
||
|
else:
|
||
|
err = dbg_debugger.do_set_breakpoint(filename, lineno)
|
||
|
response.flash = T("Set Breakpoint on %s at line %s: %s") % (
|
||
|
filename, lineno, err or T('successful'))
|
||
|
ok = True
|
||
|
else:
|
||
|
response.flash = T("Unable to determine the line number!")
|
||
|
except Exception as e:
|
||
|
session.flash = str(e)
|
||
|
return response.json({'ok': ok, 'lineno': lineno})
|
||
|
|
||
|
def list_breakpoints():
|
||
|
"Return a list of linenumbers for current breakpoints"
|
||
|
|
||
|
breakpoints = []
|
||
|
ok = False
|
||
|
try:
|
||
|
filename = os.path.join(request.env['applications_parent'],
|
||
|
'applications', request.vars.filename)
|
||
|
# normalize path name: replace slashes, references, etc...
|
||
|
filename = os.path.normpath(os.path.normcase(filename))
|
||
|
for bp in dbg_debugger.do_list_breakpoint():
|
||
|
no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp
|
||
|
# normalize path name: replace slashes, references, etc...
|
||
|
bp_filename = os.path.normpath(os.path.normcase(bp_filename))
|
||
|
if filename == bp_filename:
|
||
|
breakpoints.append(bp_lineno)
|
||
|
ok = True
|
||
|
except Exception as e:
|
||
|
session.flash = str(e)
|
||
|
return response.json({'ok': ok, 'breakpoints': breakpoints})
|