1 | import os |
---|
2 | import sys |
---|
3 | import gluon.dal |
---|
4 | import gluon.html |
---|
5 | import gluon.validators |
---|
6 | import code |
---|
7 | from gluon.debug import communicate, web_debugger, dbg_debugger |
---|
8 | from gluon._compat import thread |
---|
9 | from gluon.fileutils import open_file |
---|
10 | import pydoc |
---|
11 | |
---|
12 | |
---|
13 | if DEMO_MODE or MULTI_USER_MODE: |
---|
14 | session.flash = T('disabled in demo mode') |
---|
15 | redirect(URL('default', 'site')) |
---|
16 | |
---|
17 | FE = 10 ** 9 |
---|
18 | |
---|
19 | |
---|
20 | def index(): |
---|
21 | app = request.args(0) or 'admin' |
---|
22 | reset() |
---|
23 | # read buffer |
---|
24 | data = communicate() |
---|
25 | return dict(app=app, data=data) |
---|
26 | |
---|
27 | |
---|
28 | def callback(): |
---|
29 | app = request.args[0] |
---|
30 | command = request.vars.statement |
---|
31 | session['debug_commands:' + app].append(command) |
---|
32 | output = communicate(command) |
---|
33 | k = len(session['debug_commands:' + app]) - 1 |
---|
34 | return '[%i] %s%s\n' % (k + 1, command, output) |
---|
35 | |
---|
36 | |
---|
37 | def reset(): |
---|
38 | app = request.args(0) or 'admin' |
---|
39 | session['debug_commands:' + app] = [] |
---|
40 | return 'done' |
---|
41 | |
---|
42 | |
---|
43 | # new implementation using dbg |
---|
44 | |
---|
45 | def interact(): |
---|
46 | app = request.args(0) or 'admin' |
---|
47 | reset() |
---|
48 | |
---|
49 | # process all pending messages in the frontend |
---|
50 | web_debugger.run() |
---|
51 | |
---|
52 | # if debugging, filename and lineno should have valid values |
---|
53 | filename = web_debugger.filename |
---|
54 | lineno = web_debugger.lineno |
---|
55 | if filename: |
---|
56 | # prevent IOError 2 on some circuntances (EAFP instead of os.access) |
---|
57 | try: |
---|
58 | lines = open_file(filename, 'r').readlines() |
---|
59 | except: |
---|
60 | lines = "" |
---|
61 | lines = dict([(i + 1, l) for (i, l) in enumerate( |
---|
62 | [l.strip("\n").strip("\r") for l in lines])]) |
---|
63 | filename = os.path.basename(filename) |
---|
64 | else: |
---|
65 | lines = {} |
---|
66 | |
---|
67 | if filename: |
---|
68 | web_debugger.set_burst(2) |
---|
69 | env = web_debugger.do_environment() |
---|
70 | f_locals = env['locals'] |
---|
71 | f_globals = {} |
---|
72 | for name, value in env['globals'].items(): |
---|
73 | if name not in gluon.html.__all__ and \ |
---|
74 | name not in gluon.validators.__all__: |
---|
75 | f_globals[name] = pydoc.text.repr(value) |
---|
76 | else: |
---|
77 | f_locals = {} |
---|
78 | f_globals = {} |
---|
79 | response.headers['refresh'] = "3" |
---|
80 | |
---|
81 | if web_debugger.exception_info: |
---|
82 | response.flash = T('"User Exception" debug mode. ' |
---|
83 | 'An error ticket could be issued!') |
---|
84 | |
---|
85 | return dict(app=app, data="", |
---|
86 | filename=web_debugger.filename, lines=lines, lineno=lineno, |
---|
87 | f_globals=f_globals, f_locals=f_locals, |
---|
88 | exception=web_debugger.exception_info) |
---|
89 | |
---|
90 | |
---|
91 | def step(): |
---|
92 | web_debugger.do_step() |
---|
93 | redirect(URL("interact")) |
---|
94 | |
---|
95 | |
---|
96 | def next(): |
---|
97 | web_debugger.do_next() |
---|
98 | redirect(URL("interact")) |
---|
99 | |
---|
100 | |
---|
101 | def cont(): |
---|
102 | web_debugger.do_continue() |
---|
103 | redirect(URL("interact")) |
---|
104 | |
---|
105 | |
---|
106 | def ret(): |
---|
107 | web_debugger.do_return() |
---|
108 | redirect(URL("interact")) |
---|
109 | |
---|
110 | |
---|
111 | def stop(): |
---|
112 | web_debugger.do_quit() |
---|
113 | redirect(URL("interact")) |
---|
114 | |
---|
115 | |
---|
116 | def execute(): |
---|
117 | app = request.args[0] |
---|
118 | command = request.vars.statement |
---|
119 | session['debug_commands:' + app].append(command) |
---|
120 | try: |
---|
121 | output = web_debugger.do_exec(command) |
---|
122 | if output is None: |
---|
123 | output = "" |
---|
124 | except Exception as e: |
---|
125 | output = T("Exception %s") % str(e) |
---|
126 | k = len(session['debug_commands:' + app]) - 1 |
---|
127 | return '[%i] %s%s\n' % (k + 1, command, output) |
---|
128 | |
---|
129 | |
---|
130 | def breakpoints(): |
---|
131 | "Add or remove breakpoints" |
---|
132 | |
---|
133 | # Get all .py files |
---|
134 | files = listdir(apath('', r=request), '.*\.py$') |
---|
135 | files = [filename for filename in files |
---|
136 | if filename and 'languages' not in filename |
---|
137 | and not filename.startswith("admin") |
---|
138 | and not filename.startswith("examples")] |
---|
139 | |
---|
140 | form = SQLFORM.factory( |
---|
141 | Field('filename', requires=IS_IN_SET(files), label=T("Filename")), |
---|
142 | Field('lineno', 'integer', label=T("Line number"), |
---|
143 | requires=IS_NOT_EMPTY()), |
---|
144 | Field('temporary', 'boolean', label=T("Temporary"), |
---|
145 | comment=T("deleted after first hit")), |
---|
146 | Field('condition', 'string', label=T("Condition"), |
---|
147 | comment=T("honored only if the expression evaluates to true")), |
---|
148 | ) |
---|
149 | |
---|
150 | if form.accepts(request.vars, session): |
---|
151 | filename = os.path.join(request.env['applications_parent'], |
---|
152 | 'applications', form.vars.filename) |
---|
153 | err = dbg_debugger.do_set_breakpoint(filename, |
---|
154 | form.vars.lineno, |
---|
155 | form.vars.temporary, |
---|
156 | form.vars.condition) |
---|
157 | response.flash = T("Set Breakpoint on %s at line %s: %s") % ( |
---|
158 | filename, form.vars.lineno, err or T('successful')) |
---|
159 | |
---|
160 | for item in request.vars: |
---|
161 | if item[:7] == 'delete_': |
---|
162 | dbg_debugger.do_clear(item[7:]) |
---|
163 | |
---|
164 | breakpoints = [{'number': bp[0], 'filename': os.path.basename(bp[1]), |
---|
165 | 'path': bp[1], 'lineno': bp[2], |
---|
166 | 'temporary': bp[3], 'enabled': bp[4], 'hits': bp[5], |
---|
167 | 'condition': bp[6]} |
---|
168 | for bp in dbg_debugger.do_list_breakpoint()] |
---|
169 | |
---|
170 | return dict(breakpoints=breakpoints, form=form) |
---|
171 | |
---|
172 | |
---|
173 | def toggle_breakpoint(): |
---|
174 | "Set or clear a breakpoint" |
---|
175 | |
---|
176 | lineno = None |
---|
177 | ok = None |
---|
178 | try: |
---|
179 | filename = os.path.join(request.env['applications_parent'], |
---|
180 | 'applications', request.vars.filename) |
---|
181 | # normalize path name: replace slashes, references, etc... |
---|
182 | filename = os.path.normpath(os.path.normcase(filename)) |
---|
183 | if not request.vars.data: |
---|
184 | # ace send us the line number! |
---|
185 | lineno = int(request.vars.sel_start) + 1 |
---|
186 | else: |
---|
187 | # editarea send us the offset, manually check the cursor pos |
---|
188 | start = 0 |
---|
189 | sel_start = int(request.vars.sel_start) |
---|
190 | for lineno, line in enumerate(request.vars.data.split("\n")): |
---|
191 | if sel_start <= start: |
---|
192 | break |
---|
193 | start += len(line) + 1 |
---|
194 | else: |
---|
195 | lineno = None |
---|
196 | if lineno is not None: |
---|
197 | for bp in dbg_debugger.do_list_breakpoint(): |
---|
198 | no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp |
---|
199 | # normalize path name: replace slashes, references, etc... |
---|
200 | bp_filename = os.path.normpath(os.path.normcase(bp_filename)) |
---|
201 | if filename == bp_filename and lineno == bp_lineno: |
---|
202 | err = dbg_debugger.do_clear_breakpoint(filename, lineno) |
---|
203 | response.flash = T("Removed Breakpoint on %s at line %s", ( |
---|
204 | filename, lineno)) |
---|
205 | ok = False |
---|
206 | break |
---|
207 | else: |
---|
208 | err = dbg_debugger.do_set_breakpoint(filename, lineno) |
---|
209 | response.flash = T("Set Breakpoint on %s at line %s: %s") % ( |
---|
210 | filename, lineno, err or T('successful')) |
---|
211 | ok = True |
---|
212 | else: |
---|
213 | response.flash = T("Unable to determine the line number!") |
---|
214 | except Exception as e: |
---|
215 | session.flash = str(e) |
---|
216 | return response.json({'ok': ok, 'lineno': lineno}) |
---|
217 | |
---|
218 | def list_breakpoints(): |
---|
219 | "Return a list of linenumbers for current breakpoints" |
---|
220 | |
---|
221 | breakpoints = [] |
---|
222 | ok = False |
---|
223 | try: |
---|
224 | filename = os.path.join(request.env['applications_parent'], |
---|
225 | 'applications', request.vars.filename) |
---|
226 | # normalize path name: replace slashes, references, etc... |
---|
227 | filename = os.path.normpath(os.path.normcase(filename)) |
---|
228 | for bp in dbg_debugger.do_list_breakpoint(): |
---|
229 | no, bp_filename, bp_lineno, temporary, enabled, hits, cond = bp |
---|
230 | # normalize path name: replace slashes, references, etc... |
---|
231 | bp_filename = os.path.normpath(os.path.normcase(bp_filename)) |
---|
232 | if filename == bp_filename: |
---|
233 | breakpoints.append(bp_lineno) |
---|
234 | ok = True |
---|
235 | except Exception as e: |
---|
236 | session.flash = str(e) |
---|
237 | return response.json({'ok': ok, 'breakpoints': breakpoints}) |
---|