PageRenderTime 124ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/GitUI/Script/ScriptRunner.cs

https://github.com/vbjay/gitextensions
C# | 462 lines | 431 code | 27 blank | 4 comment | 104 complexity | 17f37cc03f6dff9770bc2d226f75cbe4 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Security.Policy;
  7. using System.Windows.Forms;
  8. using GitCommands;
  9. using GitCommands.Config;
  10. using GitUI.HelperDialogs;
  11. namespace GitUI.Script
  12. {
  13. /// <summary>Runs scripts.</summary>
  14. public static class ScriptRunner
  15. {
  16. /// <summary>Tries to run scripts identified by a <paramref name="command"/>
  17. /// and returns true if any executed.</summary>
  18. public static bool ExecuteScriptCommand(IWin32Window owner, GitModule aModule, int command, RevisionGrid revisionGrid = null)
  19. {
  20. var curScripts = ScriptManager.GetScripts();
  21. bool anyScriptExecuted = false;
  22. foreach (ScriptInfo s in curScripts)
  23. {
  24. if (s.HotkeyCommandIdentifier == command)
  25. {
  26. RunScript(owner, aModule, s.Name, revisionGrid);
  27. anyScriptExecuted = true;
  28. }
  29. }
  30. return anyScriptExecuted;
  31. }
  32. public static bool RunScript(IWin32Window owner, GitModule aModule, string script, RevisionGrid revisionGrid)
  33. {
  34. if (string.IsNullOrEmpty(script))
  35. return false;
  36. ScriptInfo scriptInfo = ScriptManager.GetScript(script);
  37. if (scriptInfo == null)
  38. {
  39. MessageBox.Show(owner, "Cannot find script: " + script, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  40. return false;
  41. }
  42. if (string.IsNullOrEmpty(scriptInfo.Command))
  43. return false;
  44. string argument = scriptInfo.Arguments;
  45. foreach (string option in Options)
  46. {
  47. if (string.IsNullOrEmpty(argument) || !argument.Contains(option))
  48. continue;
  49. if (!option.StartsWith("{s"))
  50. continue;
  51. if (revisionGrid != null)
  52. continue;
  53. MessageBox.Show(owner,
  54. string.Format("Option {0} is only supported when started from revision grid.", option),
  55. "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  56. return false;
  57. }
  58. return RunScript(owner, aModule, scriptInfo, revisionGrid);
  59. }
  60. private static string GetRemotePath(string url)
  61. {
  62. Uri uri;
  63. string path = "";
  64. if (Uri.TryCreate(url, UriKind.Absolute, out uri))
  65. path = uri.LocalPath;
  66. else if (Uri.TryCreate("ssh://" + url.Replace(":", "/"), UriKind.Absolute, out uri))
  67. path = uri.LocalPath;
  68. int pos = path.LastIndexOf(".");
  69. if (pos >= 0)
  70. path = path.Substring(0, pos);
  71. return path;
  72. }
  73. internal static bool RunScript(IWin32Window owner, GitModule aModule, ScriptInfo scriptInfo, RevisionGrid revisionGrid)
  74. {
  75. string originalCommand = scriptInfo.Command;
  76. string argument = scriptInfo.Arguments;
  77. string command = OverrideCommandWhenNecessary(originalCommand);
  78. GitRevision selectedRevision = null;
  79. GitRevision currentRevision = null;
  80. var selectedLocalBranches = new List<GitRef>();
  81. var selectedRemoteBranches = new List<GitRef>();
  82. var selectedRemotes = new List<string>();
  83. var selectedBranches = new List<GitRef>();
  84. var selectedTags = new List<GitRef>();
  85. var currentLocalBranches = new List<GitRef>();
  86. var currentRemoteBranches = new List<GitRef>();
  87. var currentRemote = "";
  88. var currentBranches = new List<GitRef>();
  89. var currentTags = new List<GitRef>();
  90. foreach (string option in Options)
  91. {
  92. if (string.IsNullOrEmpty(argument) || !argument.Contains(option))
  93. continue;
  94. if (option.StartsWith("{c") || selectedRevision != null)
  95. {
  96. currentRevision = GetCurrentRevision(aModule, revisionGrid, currentTags, currentLocalBranches, currentRemoteBranches, currentBranches, currentRevision, option);
  97. if (currentLocalBranches.Count == 1)
  98. currentRemote = aModule.GetSetting(string.Format("branch.{0}.remote", currentLocalBranches[0].Name));
  99. else
  100. {
  101. currentRemote = aModule.GetCurrentRemote();
  102. if (string.IsNullOrEmpty(currentRemote))
  103. currentRemote = aModule.GetSetting(string.Format("branch.{0}.remote",
  104. askToSpecify(currentLocalBranches, "Current Revision Branch")));
  105. }
  106. }
  107. else if (revisionGrid != null)
  108. {
  109. selectedRevision = CalculateSelectedRevision(revisionGrid, selectedRemoteBranches, selectedRemotes, selectedLocalBranches, selectedBranches, selectedTags);
  110. }
  111. string remote;
  112. string url;
  113. switch (option)
  114. {
  115. case "{sTag}":
  116. if (selectedTags.Count == 1)
  117. argument = argument.Replace(option, selectedTags[0].Name);
  118. else if (selectedTags.Count != 0)
  119. argument = argument.Replace(option, askToSpecify(selectedTags, "Selected Revision Tag"));
  120. else
  121. argument = argument.Replace(option, "");
  122. break;
  123. case "{sBranch}":
  124. if (selectedBranches.Count == 1)
  125. argument = argument.Replace(option, selectedBranches[0].Name);
  126. else if (selectedBranches.Count != 0)
  127. argument = argument.Replace(option,
  128. askToSpecify(selectedBranches, "Selected Revision Branch"));
  129. else
  130. argument = argument.Replace(option, "");
  131. break;
  132. case "{sLocalBranch}":
  133. if (selectedLocalBranches.Count == 1)
  134. argument = argument.Replace(option, selectedLocalBranches[0].Name);
  135. else if (selectedLocalBranches.Count != 0)
  136. argument = argument.Replace(option,
  137. askToSpecify(selectedLocalBranches,
  138. "Selected Revision Local Branch"));
  139. else
  140. argument = argument.Replace(option, "");
  141. break;
  142. case "{sRemoteBranch}":
  143. if (selectedRemoteBranches.Count == 1)
  144. argument = argument.Replace(option, selectedRemoteBranches[0].Name);
  145. else if (selectedRemoteBranches.Count != 0)
  146. argument = argument.Replace(option,
  147. askToSpecify(selectedRemoteBranches,
  148. "Selected Revision Remote Branch"));
  149. else
  150. argument = argument.Replace(option, "");
  151. break;
  152. case "{sRemote}":
  153. if (selectedRemotes.Count == 0)
  154. {
  155. argument = argument.Replace(option, "");
  156. break;
  157. }
  158. if (selectedRemotes.Count == 1)
  159. remote = selectedRemotes[0];
  160. else
  161. remote = askToSpecify(selectedRemotes, "Selected Revision Remote");
  162. argument = argument.Replace(option, remote);
  163. break;
  164. case "{sRemoteUrl}":
  165. if (selectedRemotes.Count == 0)
  166. {
  167. argument = argument.Replace(option, "");
  168. break;
  169. }
  170. if (selectedRemotes.Count == 1)
  171. remote = selectedRemotes[0];
  172. else
  173. remote = askToSpecify(selectedRemotes, "Selected Revision Remote");
  174. url = aModule.GetPathSetting(string.Format(SettingKeyString.RemoteUrl, remote));
  175. argument = argument.Replace(option, url);
  176. break;
  177. case "{sRemotePathFromUrl}":
  178. if (selectedRemotes.Count == 0)
  179. {
  180. argument = argument.Replace(option, "");
  181. break;
  182. }
  183. if (selectedRemotes.Count == 1)
  184. remote = selectedRemotes[0];
  185. else
  186. remote = askToSpecify(selectedRemotes, "Selected Revision Remote");
  187. url = aModule.GetPathSetting(string.Format(SettingKeyString.RemoteUrl, remote));
  188. argument = argument.Replace(option, GetRemotePath(url));
  189. break;
  190. case "{sHash}":
  191. argument = argument.Replace(option, selectedRevision.Guid);
  192. break;
  193. case "{sMessage}":
  194. argument = argument.Replace(option, selectedRevision.Message);
  195. break;
  196. case "{sAuthor}":
  197. argument = argument.Replace(option, selectedRevision.Author);
  198. break;
  199. case "{sCommitter}":
  200. argument = argument.Replace(option, selectedRevision.Committer);
  201. break;
  202. case "{sAuthorDate}":
  203. argument = argument.Replace(option, selectedRevision.AuthorDate.ToString());
  204. break;
  205. case "{sCommitDate}":
  206. argument = argument.Replace(option, selectedRevision.CommitDate.ToString());
  207. break;
  208. case "{cTag}":
  209. if (currentTags.Count == 1)
  210. argument = argument.Replace(option, currentTags[0].Name);
  211. else if (currentTags.Count != 0)
  212. argument = argument.Replace(option, askToSpecify(currentTags, "Current Revision Tag"));
  213. else
  214. argument = argument.Replace(option, "");
  215. break;
  216. case "{cBranch}":
  217. if (currentBranches.Count == 1)
  218. argument = argument.Replace(option, currentBranches[0].Name);
  219. else if (currentBranches.Count != 0)
  220. argument = argument.Replace(option,
  221. askToSpecify(currentBranches, "Current Revision Branch"));
  222. else
  223. argument = argument.Replace(option, "");
  224. break;
  225. case "{cLocalBranch}":
  226. if (currentLocalBranches.Count == 1)
  227. argument = argument.Replace(option, currentLocalBranches[0].Name);
  228. else if (currentLocalBranches.Count != 0)
  229. argument = argument.Replace(option,
  230. askToSpecify(currentLocalBranches,
  231. "Current Revision Local Branch"));
  232. else
  233. argument = argument.Replace(option, "");
  234. break;
  235. case "{cRemoteBranch}":
  236. if (currentRemoteBranches.Count == 1)
  237. argument = argument.Replace(option, currentRemoteBranches[0].Name);
  238. else if (currentRemoteBranches.Count != 0)
  239. argument = argument.Replace(option,
  240. askToSpecify(currentRemoteBranches,
  241. "Current Revision Remote Branch"));
  242. else
  243. argument = argument.Replace(option, "");
  244. break;
  245. case "{cHash}":
  246. argument = argument.Replace(option, currentRevision.Guid);
  247. break;
  248. case "{cMessage}":
  249. argument = argument.Replace(option, currentRevision.Message);
  250. break;
  251. case "{cAuthor}":
  252. argument = argument.Replace(option, currentRevision.Author);
  253. break;
  254. case "{cCommitter}":
  255. argument = argument.Replace(option, currentRevision.Committer);
  256. break;
  257. case "{cAuthorDate}":
  258. argument = argument.Replace(option, currentRevision.AuthorDate.ToString());
  259. break;
  260. case "{cCommitDate}":
  261. argument = argument.Replace(option, currentRevision.CommitDate.ToString());
  262. break;
  263. case "{cDefaultRemote}":
  264. if (string.IsNullOrEmpty(currentRemote))
  265. {
  266. argument = argument.Replace(option, "");
  267. break;
  268. }
  269. argument = argument.Replace(option, currentRemote);
  270. break;
  271. case "{cDefaultRemoteUrl}":
  272. if (string.IsNullOrEmpty(currentRemote))
  273. {
  274. argument = argument.Replace(option, "");
  275. break;
  276. }
  277. url = aModule.GetPathSetting(string.Format(SettingKeyString.RemoteUrl, currentRemote));
  278. argument = argument.Replace(option, url);
  279. break;
  280. case "{cDefaultRemotePathFromUrl}":
  281. if (string.IsNullOrEmpty(currentRemote))
  282. {
  283. argument = argument.Replace(option, "");
  284. break;
  285. }
  286. url = aModule.GetPathSetting(string.Format(SettingKeyString.RemoteUrl, currentRemote));
  287. argument = argument.Replace(option, GetRemotePath(url));
  288. break;
  289. case "{UserInput}":
  290. using (SimplePrompt Prompt = new SimplePrompt())
  291. {
  292. Prompt.ShowDialog();
  293. argument = argument.Replace(option, Prompt.UserInput);
  294. }
  295. break;
  296. }
  297. }
  298. if (!scriptInfo.RunInBackground)
  299. FormProcess.ShowDialog(owner, command, argument, aModule.WorkingDir, null, true);
  300. else
  301. {
  302. if (originalCommand.Equals("{openurl}", StringComparison.CurrentCultureIgnoreCase))
  303. Process.Start(argument);
  304. else
  305. aModule.RunExternalCmdDetached(command, argument);
  306. }
  307. return !scriptInfo.RunInBackground;
  308. }
  309. private static GitRevision CalculateSelectedRevision(RevisionGrid revisionGrid, List<GitRef> selectedRemoteBranches,
  310. List<string> selectedRemotes, List<GitRef> selectedLocalBranches,
  311. List<GitRef> selectedBranches, List<GitRef> selectedTags)
  312. {
  313. GitRevision selectedRevision = revisionGrid.GetRevision(revisionGrid.LastRow);
  314. foreach (GitRef head in selectedRevision.Refs)
  315. {
  316. if (head.IsTag)
  317. selectedTags.Add(head);
  318. else if (head.IsHead || head.IsRemote)
  319. {
  320. selectedBranches.Add(head);
  321. if (head.IsRemote)
  322. {
  323. selectedRemoteBranches.Add(head);
  324. if (!selectedRemotes.Contains(head.Remote))
  325. selectedRemotes.Add(head.Remote);
  326. }
  327. else
  328. selectedLocalBranches.Add(head);
  329. }
  330. }
  331. return selectedRevision;
  332. }
  333. private static GitRevision GetCurrentRevision(GitModule aModule, RevisionGrid RevisionGrid, List<GitRef> currentTags, List<GitRef> currentLocalBranches,
  334. List<GitRef> currentRemoteBranches, List<GitRef> currentBranches,
  335. GitRevision currentRevision, string option)
  336. {
  337. if (option.StartsWith("{c") && currentRevision == null)
  338. {
  339. IList<GitRef> refs;
  340. if (RevisionGrid == null)
  341. {
  342. string currentRevisionGuid = aModule.GetCurrentCheckout();
  343. refs = aModule.GetRefs(true, true).Where(gitRef => gitRef.Guid == currentRevisionGuid).ToList();
  344. }
  345. else
  346. {
  347. currentRevision = RevisionGrid.GetCurrentRevision();
  348. refs = currentRevision.Refs;
  349. }
  350. foreach (GitRef gitRef in refs)
  351. {
  352. if (gitRef.IsTag)
  353. currentTags.Add(gitRef);
  354. else if (gitRef.IsHead || gitRef.IsRemote)
  355. {
  356. currentBranches.Add(gitRef);
  357. if (gitRef.IsRemote)
  358. currentRemoteBranches.Add(gitRef);
  359. else
  360. currentLocalBranches.Add(gitRef);
  361. }
  362. }
  363. }
  364. return currentRevision;
  365. }
  366. private static string[] Options
  367. {
  368. get
  369. {
  370. string[] options =
  371. {
  372. "{sTag}",
  373. "{sBranch}",
  374. "{sLocalBranch}",
  375. "{sRemoteBranch}",
  376. "{sRemote}",
  377. "{sRemoteUrl}",
  378. "{sRemotePathFromUrl}",
  379. "{sHash}",
  380. "{sMessage}",
  381. "{sAuthor}",
  382. "{sCommitter}",
  383. "{sAuthorDate}",
  384. "{sCommitDate}",
  385. "{cTag}",
  386. "{cBranch}",
  387. "{cLocalBranch}",
  388. "{cRemoteBranch}",
  389. "{cHash}",
  390. "{cMessage}",
  391. "{cAuthor}",
  392. "{cCommitter}",
  393. "{cAuthorDate}",
  394. "{cCommitDate}",
  395. "{cDefaultRemote}",
  396. "{cDefaultRemoteUrl}",
  397. "{cDefaultRemotePathFromUrl}",
  398. "{UserInput}"
  399. };
  400. return options;
  401. }
  402. }
  403. private static string OverrideCommandWhenNecessary(string originalCommand)
  404. {
  405. //Make sure we are able to run git, even if git is not in the path
  406. if (originalCommand.Equals("git", StringComparison.CurrentCultureIgnoreCase) ||
  407. originalCommand.Equals("{git}", StringComparison.CurrentCultureIgnoreCase))
  408. return AppSettings.GitCommand;
  409. if (originalCommand.Equals("gitextensions", StringComparison.CurrentCultureIgnoreCase) ||
  410. originalCommand.Equals("{gitextensions}", StringComparison.CurrentCultureIgnoreCase) ||
  411. originalCommand.Equals("gitex", StringComparison.CurrentCultureIgnoreCase) ||
  412. originalCommand.Equals("{gitex}", StringComparison.CurrentCultureIgnoreCase))
  413. return AppSettings.GetGitExtensionsFullPath();
  414. if (originalCommand.Equals("{openurl}", StringComparison.CurrentCultureIgnoreCase))
  415. return "explorer";
  416. return originalCommand;
  417. }
  418. private static string askToSpecify(IEnumerable<GitRef> options, string title)
  419. {
  420. using (var f = new FormRunScriptSpecify(options, title))
  421. {
  422. f.ShowDialog();
  423. return f.ret;
  424. }
  425. }
  426. private static string askToSpecify(IEnumerable<string> options, string title)
  427. {
  428. using (var f = new FormRunScriptSpecify(options, title))
  429. {
  430. f.ShowDialog();
  431. return f.ret;
  432. }
  433. }
  434. }
  435. }