searchcode logo
Dogecoin is an open source peer-to-peer cryptocurrency

monodevelop /monodevelop-2.8.8.4/src/addins/MonoDevelop.Debugger.Soft/MonoDevelop.Debugger.Soft/CustomSoftDebuggerEngine.cs

git clone git://pkgs.fedoraproject.org/monodevelop

Language

C#

MD5 Hash

e328cfc01bb707d5b87548a3242bb116

Lines in File 366
Blank Lines 55 (15.03%)
Comment Lines 37 (10%)
Code Lines 274 (75%)
Estimated Development Effort (Months)0.62
Estimated Development Effort (Years)0
Estimated Developers0.3
Estimated Cost$6939.00
Generated using David A. Wheeler's 'SLOCCount'.
  1. //
  2. // CustomSoftDebuggerEngine.cs
  3. //
  4. // Author:
  5. // Michael Hutchinson <mhutchinson@novell.com>
  6. //
  7. // Copyright (c) 2010 Novell, Inc.
  8. //
  9. // Permission is hereby granted, free of charge, to any person obtaining a copy
  10. // of this software and associated documentation files (the "Software"), to deal
  11. // in the Software without restriction, including without limitation the rights
  12. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. // copies of the Software, and to permit persons to whom the Software is
  14. // furnished to do so, subject to the following conditions:
  15. //
  16. // The above copyright notice and this permission notice shall be included in
  17. // all copies or substantial portions of the Software.
  18. //
  19. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25. // THE SOFTWARE.
  26.  
  27. using System;
  28. using System.Diagnostics;
  29. using Mono.Debugging.Client;
  30. using MonoDevelop.Core;
  31. using MonoDevelop.Core.Execution;
  32. using System.Net;
  33. using System.Collections.Generic;
  34. using Mono.Debugging.Soft;
  35.  
  36. namespace MonoDevelop.Debugger.Soft
  37. {
  38. class CustomSoftDebuggerEngine: IDebuggerEngine
  39. {
  40. bool? available;
  41.  
  42. public bool CanDebugCommand (ExecutionCommand cmd)
  43. {
  44. // This isn't polished enough to show it by default. GUI needs work, and it should be exposed
  45. // via "run with->custom parameters", not a toplevel command and dialog.
  46. // That would also make it possible to save settings.
  47. if (!available.HasValue) {
  48. available = !string.IsNullOrEmpty (Environment.GetEnvironmentVariable ("MONODEVELOP_SDB_TEST"));
  49. }
  50. return available.Value;
  51. }
  52.  
  53. public DebuggerSession CreateSession ()
  54. {
  55. return new CustomSoftDebuggerSession ();
  56. }
  57.  
  58. public ProcessInfo[] GetAttachableProcesses ()
  59. {
  60. return new ProcessInfo[0];
  61. }
  62.  
  63. public DebuggerStartInfo CreateDebuggerStartInfo (ExecutionCommand c)
  64. {
  65. //WORKAROUND: explicit generic type argument works around a gmcs 2.6.x type inference bug
  66. return InvokeSynch<SoftDebuggerStartInfo> (GetDebuggerInfo) ??
  67. //HACK: flag object so we can cancel the session
  68. new DebuggerStartInfo ();
  69. }
  70.  
  71. static SoftDebuggerStartInfo GetDebuggerInfo ()
  72. {
  73. var dlg = new DebuggerOptionsDialog ();
  74. try {
  75. return dlg.Run ();
  76. } finally {
  77. dlg.Destroy ();
  78. }
  79. }
  80.  
  81. static T InvokeSynch<T> (Func<T> func)
  82. {
  83. if (MonoDevelop.Ide.DispatchService.IsGuiThread)
  84. return func ();
  85.  
  86. var ev = new System.Threading.ManualResetEvent (false);
  87. T val = default (T);
  88. Exception caught = null;
  89. Gtk.Application.Invoke (delegate {
  90. try {
  91. val = func ();
  92. } catch (Exception ex) {
  93. caught = ex;
  94. } finally {
  95. ev.Set ();
  96. }
  97. });
  98. ev.WaitOne ();
  99. if (caught != null)
  100. throw caught;
  101. return val;
  102. }
  103.  
  104. class CustomSoftDebuggerSession : SoftDebuggerSession
  105. {
  106. IProcessAsyncOperation process;
  107. bool usingExternalConsole;
  108.  
  109. protected override void OnRun (DebuggerStartInfo startInfo)
  110. {
  111. var info = startInfo as SoftDebuggerStartInfo;
  112. if (info == null) {
  113. EndSession ();
  114. return;
  115. }
  116.  
  117. StartProcess (info);
  118.  
  119. if (info.StartArgs is SoftDebuggerConnectArgs) {
  120. //connecting to the process, so give it a moment to start listening
  121. System.Threading.Thread.Sleep (200);
  122. }
  123.  
  124. base.OnRun (startInfo);
  125. }
  126.  
  127. void StartProcess (SoftDebuggerStartInfo info)
  128. {
  129. if (string.IsNullOrEmpty (info.Command))
  130. return;
  131.  
  132. if (info.UseExternalConsole) {
  133. usingExternalConsole = true;
  134. var console = ExternalConsoleFactory.Instance.CreateConsole (info.CloseExternalConsoleOnExit);
  135. process = Runtime.ProcessService.StartConsoleProcess (
  136. info.Command, info.Arguments, info.WorkingDirectory, info.EnvironmentVariables,
  137. console, null);
  138. } else {
  139. var psi = new ProcessStartInfo (info.Command, info.Arguments) {
  140. WorkingDirectory = info.WorkingDirectory,
  141. };
  142. foreach (KeyValuePair<string,string> kvp in info.EnvironmentVariables)
  143. psi.EnvironmentVariables [kvp.Key] = kvp.Value;
  144.  
  145. process = Runtime.ProcessService.StartProcess (psi, ProcessOutput, ProcessError, null);
  146. }
  147. }
  148.  
  149. void ProcessOutput (object sender, string message)
  150. {
  151. OnTargetOutput (true, message);
  152. }
  153.  
  154. void ProcessError (object sender, string message)
  155. {
  156. OnTargetOutput (false, message);
  157. }
  158.  
  159. protected override void EndSession ()
  160. {
  161. base.EndSession ();
  162. EndProcess ();
  163. }
  164.  
  165. void EndProcess ()
  166. {
  167. if (process == null)
  168. return;
  169.  
  170. var p = process;
  171. process = null;
  172.  
  173. if (usingExternalConsole || p.IsCompleted)
  174. return;
  175.  
  176. try {
  177. p.Cancel ();
  178. } catch {}
  179. }
  180.  
  181. protected override void EnsureExited ()
  182. {
  183. EndProcess ();
  184. }
  185. }
  186.  
  187. class DebuggerOptionsDialog : Gtk.Dialog
  188. {
  189. MonoDevelop.Components.FileEntry commandEntry = new MonoDevelop.Components.FileEntry ();
  190. Gtk.Entry argsEntry = new Gtk.Entry ();
  191. Gtk.Entry ipEntry = new Gtk.Entry ();
  192. Gtk.Entry portEntry = new Gtk.Entry ();
  193. Gtk.Entry consolePortEntry = new Gtk.Entry ();
  194. Gtk.Button listenButton = new Gtk.Button ("Listen");
  195. Gtk.Button connectButton = new Gtk.Button ("Connect");
  196.  
  197. const Gtk.ResponseType listenResponse = Gtk.ResponseType.Yes;
  198. const Gtk.ResponseType connectResponse = Gtk.ResponseType.Ok;
  199.  
  200. IPAddress ip;
  201. string command, args;
  202. int? port, consolePort;
  203.  
  204. Properties properties;
  205.  
  206. //TODO: dropdown menus for picking string substitutions. also substitutions for port, ip
  207. public DebuggerOptionsDialog () : base (
  208. "Launch Soft Debugger", MonoDevelop.Ide.MessageService.RootWindow,
  209. Gtk.DialogFlags.DestroyWithParent | Gtk.DialogFlags.Modal)
  210. {
  211. properties = PropertyService.Get ("MonoDevelop.Debugger.Soft.CustomSoftDebugger", new Properties());
  212.  
  213. AddActionWidget (new Gtk.Button (Gtk.Stock.Cancel), Gtk.ResponseType.Cancel);
  214. AddActionWidget (listenButton, listenResponse);
  215. AddActionWidget (connectButton, connectResponse);
  216.  
  217. var table = new Gtk.Table (5, 2, false);
  218. table.BorderWidth = 6;
  219. VBox.PackStart (table, true, true, 0);
  220.  
  221. table.Attach (new Gtk.Label ("Command:") { Xalign = 0 }, 0, 1, 0, 1);
  222. table.Attach (new Gtk.Label ("Arguments:") { Xalign = 0 }, 0, 1, 1, 2);
  223. table.Attach (new Gtk.Label ("IP:") { Xalign = 0 }, 0, 1, 2, 3);
  224. table.Attach (new Gtk.Label ("Port:") { Xalign = 0 }, 0, 1, 3, 4);
  225. table.Attach (new Gtk.Label ("Output:") { Xalign = 0 }, 0, 1, 4, 5);
  226.  
  227. table.Attach (commandEntry, 1, 2, 0, 1);
  228. table.Attach (argsEntry, 1, 2, 1, 2);
  229. table.Attach (ipEntry, 1, 2, 2, 3);
  230. table.Attach (portEntry, 1, 2, 3, 4);
  231. table.Attach (consolePortEntry, 1, 2, 4, 5);
  232.  
  233. argsEntry.WidthRequest = 500;
  234.  
  235. commandEntry.PathChanged += delegate {
  236. try {
  237. //check it parses
  238. MonoDevelop.Core.StringParserService.Parse (commandEntry.Path);
  239. command = commandEntry.Path;
  240. } catch {
  241. command = null;
  242. }
  243. CheckValid ();
  244. };
  245.  
  246. argsEntry.Changed += delegate {
  247. try {
  248. //check it parses
  249. MonoDevelop.Core.StringParserService.Parse (argsEntry.Text);
  250. args = argsEntry.Text;
  251. } catch {
  252. args = null;
  253. }
  254. CheckValid ();
  255. };
  256.  
  257. ipEntry.Changed += delegate {
  258. if (string.IsNullOrEmpty (ipEntry.Text)) {
  259. ip = IPAddress.Loopback;
  260. } else if (!IPAddress.TryParse (ipEntry.Text, out ip)) {
  261. ip = null;
  262. }
  263. CheckValid ();
  264. };
  265.  
  266. portEntry.Changed += delegate {
  267. port = ParsePort (portEntry.Text);
  268. CheckValid ();
  269. };
  270.  
  271. consolePortEntry.Changed += delegate {
  272. consolePort = ParsePort (consolePortEntry.Text);
  273. CheckValid ();
  274. };
  275.  
  276. command = properties.Get ("Command", "");
  277. args = properties.Get ("Arguments", "");
  278. if (!IPAddress.TryParse (properties.Get ("IpAddress", "127.0.0.1"), out ip) || ip == null)
  279. ip = IPAddress.Loopback;
  280. string portStr = properties.Get<string> ("Port");
  281. port = ParsePort (portStr) ?? 10000;
  282. string consolePortStr = properties.Get<string> ("ConsolePort");
  283. consolePort = ParsePort (consolePortStr);
  284.  
  285. commandEntry.Path = command;
  286. argsEntry.Text = args;
  287. ipEntry.Text = ip.ToString ();
  288. portEntry.Text = PortToString (port) ?? "";
  289. consolePortEntry.Text = PortToString (consolePort) ?? "";
  290.  
  291. CheckValid ();
  292.  
  293. VBox.ShowAll ();
  294. }
  295.  
  296. int? ParsePort (string port)
  297. {
  298. if (string.IsNullOrEmpty (port))
  299. return null;
  300. int value;
  301. if (!int.TryParse (port, out value))
  302. return -1;
  303. return value;
  304. }
  305.  
  306. string PortToString (int? port)
  307. {
  308. return port.HasValue? port.Value.ToString () : null;
  309. }
  310.  
  311. public new SoftDebuggerStartInfo Run ()
  312. {
  313. var response = (Gtk.ResponseType) MonoDevelop.Ide.MessageService.RunCustomDialog (this);
  314. if (response != listenResponse && response != connectResponse)
  315. return null;
  316.  
  317. properties.Set ("Command", command);
  318. properties.Set ("Arguments", args);
  319. properties.Set ("IpAddress", ip.ToString ());
  320. properties.Set ("Port", PortToString (port));
  321. properties.Set ("ConsolePort", PortToString (consolePort));
  322.  
  323. var name = string.IsNullOrEmpty (command)? "" : command;
  324. bool listen = response == listenResponse;
  325. var agentArgs = string.Format ("transport=dt_socket,address={0}:{1}{2}", ip, port, listen?"":",server=y");
  326.  
  327. var customArgsTags = new string[,] {
  328. { "AgentArgs", agentArgs },
  329. { "IP", ip.ToString () },
  330. { "Port", PortToString (port) },
  331. { "Console", PortToString (consolePort) },
  332. };
  333.  
  334. SoftDebuggerRemoteArgs startArgs;
  335. if (listen) {
  336. startArgs = (SoftDebuggerRemoteArgs) new SoftDebuggerListenArgs (name, ip, port.Value, consolePort ?? -1);
  337. } else {
  338. startArgs = new SoftDebuggerConnectArgs (name, ip, port.Value, consolePort ?? -1) {
  339. //infinite connection retries (user can cancel), 800ms between them
  340. TimeBetweenConnectionAttempts = 800,
  341. MaxConnectionAttempts = -1,
  342. };
  343. };
  344.  
  345. var dsi = new SoftDebuggerStartInfo (startArgs) {
  346. Command = StringParserService.Parse (command),
  347. Arguments = StringParserService.Parse (args, customArgsTags),
  348. };
  349.  
  350. //FIXME: GUI for env vars
  351. //dsi.EnvironmentVariables [kvp.Key] = kvp.Value;
  352.  
  353. return dsi;
  354. }
  355.  
  356. void CheckValid ()
  357. {
  358. bool valid = ip != null
  359. && (port.HasValue && port.Value >= 0)
  360. && (!consolePort.HasValue || consolePort >= 0);
  361. listenButton.Sensitive = valid;
  362. connectButton.Sensitive = valid && port > 0 && (!consolePort.HasValue || consolePort > 0);
  363. }
  364. }
  365. }
  366. }