8dd94ab1842d9c88040f3332176c54f16ce87954
[idea/community.git] / python / helpers / pydev / pydev_monkey.py
1 import os
2 import shlex
3 import sys
4 import pydev_log
5 import traceback
6
7 helpers = os.path.dirname(__file__)
8
9 def is_python(path):
10     if path.endswith("'") or path.endswith('"'):
11         path = path[1:len(path)-1]
12     filename = os.path.basename(path).lower()
13     for name in ['python', 'jython', 'pypy']:
14         if filename.find(name) != -1:
15             return True
16
17     return False
18
19 def patch_args(args):
20     try:
21         pydev_log.debug("Patching args: %s"% str(args))
22
23         import sys
24         new_args = []
25         i = 0
26         if len(args) == 0:
27             return args
28
29         if is_python(args[0]):
30             try:
31                 indC = args.index('-c')
32             except ValueError:
33                 indC = -1
34
35             if indC != -1:
36                 import pydevd
37                 host, port = pydevd.dispatch()
38
39                 if port is not None:
40                     new_args.extend(args)
41                     new_args[indC + 1] = "import sys; sys.path.append('%s'); import pydevd; pydevd.settrace(host='%s', port=%s, suspend=False); %s"%(helpers, host, port, args[indC + 1])
42                     return new_args
43             else:
44                 new_args.append(args[0])
45         else:
46             pydev_log.debug("Process is not python, returning.")
47             return args
48
49         i = 1
50         while i < len(args):
51             if args[i].startswith('-'):
52                 new_args.append(args[i])
53             else:
54                 break
55             i+=1
56
57         if args[i].endswith('pydevd.py'): #no need to add pydevd twice
58             return args
59
60         for x in sys.original_argv:
61             if sys.platform == "win32" and not x.endswith('"'):
62                 arg = '"%s"'%x
63             else:
64                 arg = x
65             new_args.append(arg)
66             if x == '--file':
67                 break
68
69         while i < len(args):
70             new_args.append(args[i])
71             i+=1
72
73         return new_args
74     except:
75         traceback.print_exc()
76         return args
77
78
79 def args_to_str(args):
80     quoted_args = []
81     for x in args:
82         if x.startswith('"') and x.endswith('"'):
83             quoted_args.append(x)
84         else:
85             quoted_args.append('"%s"' % x)
86
87     return ' '.join(quoted_args)
88
89 def remove_quotes(str):
90     if str.startswith('"') and str.endswith('"'):
91         return str[1:-1]
92     else:
93         return str
94
95 def str_to_args(str):
96     return [remove_quotes(x) for x in shlex.split(str)]
97
98 def patch_arg_str_win(arg_str):
99     new_arg_str = arg_str.replace('\\', '/')
100     args = str_to_args(new_arg_str)
101     if not is_python(args[0]):
102         return arg_str
103     arg_str = args_to_str(patch_args(args))
104     pydev_log.debug("New args: %s"% arg_str)
105     return arg_str
106
107 def monkey_patch_module(module, funcname, create_func):
108     if hasattr(module, funcname):
109         original_name = 'original_' + funcname
110         if not hasattr(module, original_name):
111             setattr(module, original_name, getattr(module, funcname))
112             setattr(module, funcname, create_func(original_name))
113
114
115 def monkey_patch_os(funcname, create_func):
116     monkey_patch_module(os, funcname, create_func)
117
118
119 def warn_multiproc():
120     import pydev_log
121
122     pydev_log.error_once(
123         "New process is launching. Breakpoints won't work.\n To debug that process please enable 'Attach to subprocess automatically while debugging' option in the debugger settings.\n")
124
125
126 def create_warn_multiproc(original_name):
127
128     def new_warn_multiproc(*args):
129         import os
130
131         warn_multiproc()
132
133         return getattr(os, original_name)(*args)
134     return new_warn_multiproc
135
136 def create_execl(original_name):
137     def new_execl(path, *args):
138         '''
139 os.execl(path, arg0, arg1, ...)
140 os.execle(path, arg0, arg1, ..., env)
141 os.execlp(file, arg0, arg1, ...)
142 os.execlpe(file, arg0, arg1, ..., env)
143         '''
144         import os
145         args = patch_args(args)
146         return getattr(os, original_name)(path, *args)
147     return new_execl
148
149 def create_execv(original_name):
150     def new_execv(path, args):
151         '''
152 os.execv(path, args)
153 os.execvp(file, args)
154         '''
155         import os
156         return getattr(os, original_name)(path, patch_args(args))
157     return new_execv
158
159 def create_execve(original_name):
160     """
161 os.execve(path, args, env)
162 os.execvpe(file, args, env)
163     """
164     def new_execve(path, args, env):
165         import os
166         return getattr(os, original_name)(path, patch_args(args), env)
167     return new_execve
168
169
170 def create_spawnl(original_name):
171     def new_spawnl(mode, path, *args):
172         '''
173 os.spawnl(mode, path, arg0, arg1, ...)
174 os.spawnlp(mode, file, arg0, arg1, ...)
175         '''
176         import os
177         args = patch_args(args)
178         return getattr(os, original_name)(mode, path, *args)
179     return new_spawnl
180
181 def create_spawnv(original_name):
182     def new_spawnv(mode, path, args):
183         '''
184 os.spawnv(mode, path, args)
185 os.spawnvp(mode, file, args)
186         '''
187         import os
188         return getattr(os, original_name)(mode, path, patch_args(args))
189     return new_spawnv
190
191 def create_spawnve(original_name):
192     """
193 os.spawnve(mode, path, args, env)
194 os.spawnvpe(mode, file, args, env)
195     """
196     def new_spawnve(mode, path, args, env):
197         import os
198         return getattr(os, original_name)(mode, path, patch_args(args), env)
199     return new_spawnve
200
201 def create_CreateProcess(original_name):
202     """
203 CreateProcess(*args, **kwargs)
204     """
205     def new_CreateProcess(appName, commandLine, *args):
206         try:
207             import _subprocess
208         except ImportError:
209             import _winapi as _subprocess
210         return getattr(_subprocess, original_name)(appName, patch_arg_str_win(commandLine), *args)
211     return new_CreateProcess
212
213 def create_CreateProcessWarnMultiproc(original_name):
214     """
215 CreateProcess(*args, **kwargs)
216     """
217     def new_CreateProcess(*args):
218         try:
219             import _subprocess
220         except ImportError:
221             import _winapi as _subprocess
222         warn_multiproc()
223         return getattr(_subprocess, original_name)(*args)
224     return new_CreateProcess
225
226 def create_fork(original_name):
227     def new_fork():
228         import os
229         child_process = getattr(os, original_name)() # fork
230         if not child_process:
231             import pydevd
232
233             pydevd.settrace_forked()
234         return child_process
235     return new_fork
236
237 def patch_new_process_functions():
238 #os.execl(path, arg0, arg1, ...)
239 #os.execle(path, arg0, arg1, ..., env)
240 #os.execlp(file, arg0, arg1, ...)
241 #os.execlpe(file, arg0, arg1, ..., env)
242 #os.execv(path, args)
243 #os.execve(path, args, env)
244 #os.execvp(file, args)
245 #os.execvpe(file, args, env)
246     monkey_patch_os('execl', create_execl)
247     monkey_patch_os('execle', create_execl)
248     monkey_patch_os('execlp', create_execl)
249     monkey_patch_os('execlpe', create_execl)
250     monkey_patch_os('execv', create_execv)
251     monkey_patch_os('execve', create_execve)
252     monkey_patch_os('execvp', create_execv)
253     monkey_patch_os('execvpe', create_execve)
254
255 #os.spawnl(mode, path, ...)
256 #os.spawnle(mode, path, ..., env)
257 #os.spawnlp(mode, file, ...)
258 #os.spawnlpe(mode, file, ..., env)
259 #os.spawnv(mode, path, args)
260 #os.spawnve(mode, path, args, env)
261 #os.spawnvp(mode, file, args)
262 #os.spawnvpe(mode, file, args, env)
263
264     monkey_patch_os('spawnl', create_spawnl)
265     monkey_patch_os('spawnle', create_spawnl)
266     monkey_patch_os('spawnlp', create_spawnl)
267     monkey_patch_os('spawnlpe', create_spawnl)
268     monkey_patch_os('spawnv', create_spawnv)
269     monkey_patch_os('spawnve', create_spawnve)
270     monkey_patch_os('spawnvp', create_spawnv)
271     monkey_patch_os('spawnvpe', create_spawnve)
272
273     if sys.platform != 'win32':
274         monkey_patch_os('fork', create_fork)
275     else:
276         #Windows
277         try:
278             import _subprocess
279         except ImportError:
280             import _winapi as _subprocess
281         monkey_patch_module(_subprocess, 'CreateProcess', create_CreateProcess)
282
283
284 def patch_new_process_functions_with_warning():
285     monkey_patch_os('execl', create_warn_multiproc)
286     monkey_patch_os('execle', create_warn_multiproc)
287     monkey_patch_os('execlp', create_warn_multiproc)
288     monkey_patch_os('execlpe', create_warn_multiproc)
289     monkey_patch_os('execv', create_warn_multiproc)
290     monkey_patch_os('execve', create_warn_multiproc)
291     monkey_patch_os('execvp', create_warn_multiproc)
292     monkey_patch_os('execvpe', create_warn_multiproc)
293     monkey_patch_os('spawnl', create_warn_multiproc)
294     monkey_patch_os('spawnle', create_warn_multiproc)
295     monkey_patch_os('spawnlp', create_warn_multiproc)
296     monkey_patch_os('spawnlpe', create_warn_multiproc)
297     monkey_patch_os('spawnv', create_warn_multiproc)
298     monkey_patch_os('spawnve', create_warn_multiproc)
299     monkey_patch_os('spawnvp', create_warn_multiproc)
300     monkey_patch_os('spawnvpe', create_warn_multiproc)
301
302     if sys.platform != 'win32':
303         monkey_patch_os('fork', create_warn_multiproc)
304     else:
305         #Windows
306         try:
307             import _subprocess
308         except ImportError:
309             import _winapi as _subprocess
310         monkey_patch_module(_subprocess, 'CreateProcess', create_CreateProcessWarnMultiproc)