PageRenderTime 155ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/GitUI/CommandsDialogs/FormClone.cs

https://github.com/qgppl/gitextensions
C# | 402 lines | 336 code | 51 blank | 15 comment | 38 complexity | 42a6430c555f2fab921393b15517a379 MD5 | raw file
Possible License(s): GPL-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Windows.Forms;
  7. using GitCommands;
  8. using GitCommands.Config;
  9. using GitCommands.Repository;
  10. using GitUIPluginInterfaces;
  11. using ResourceManager;
  12. namespace GitUI.CommandsDialogs
  13. {
  14. public partial class FormClone : GitModuleForm
  15. {
  16. private readonly TranslationString _infoNewRepositoryLocation =
  17. new TranslationString("The repository will be cloned to a new directory located here:" + Environment.NewLine +
  18. "{0}");
  19. private readonly TranslationString _infoDirectoryExists =
  20. new TranslationString("(Directory already exists)");
  21. private readonly TranslationString _infoDirectoryNew =
  22. new TranslationString("(New directory)");
  23. private readonly TranslationString _questionOpenRepo =
  24. new TranslationString("The repository has been cloned successfully." + Environment.NewLine +
  25. "Do you want to open the new repository \"{0}\" now?");
  26. private readonly TranslationString _questionOpenRepoCaption =
  27. new TranslationString("Open");
  28. private readonly TranslationString _branchDefaultRemoteHead = new TranslationString("(default: remote HEAD)" /* Has a colon, so won't alias with any valid branch name */);
  29. private readonly TranslationString _branchNone = new TranslationString("(none: don't checkout after clone)" /* Has a colon, so won't alias with any valid branch name */);
  30. private bool openedFromProtocolHandler;
  31. private readonly string url;
  32. private EventHandler<GitModuleEventArgs> GitModuleChanged;
  33. private readonly IList<string> _defaultBranchItems;
  34. // for translation only
  35. private FormClone()
  36. : this(null, null, false, null)
  37. {
  38. }
  39. public FormClone(GitUICommands aCommands, string url, bool openedFromProtocolHandler, EventHandler<GitModuleEventArgs> GitModuleChanged)
  40. : base(aCommands)
  41. {
  42. this.GitModuleChanged = GitModuleChanged;
  43. InitializeComponent();
  44. Translate();
  45. this.openedFromProtocolHandler = openedFromProtocolHandler;
  46. this.url = url;
  47. _defaultBranchItems = new[] {_branchDefaultRemoteHead.Text, _branchNone.Text};
  48. _NO_TRANSLATE_Branches.DataSource = _defaultBranchItems;
  49. }
  50. protected override void OnRuntimeLoad(EventArgs e)
  51. {
  52. base.OnRuntimeLoad(e);
  53. FillFromDropDown();
  54. _NO_TRANSLATE_To.Text = AppSettings.DefaultCloneDestinationPath;
  55. if (url.IsNotNullOrWhitespace())
  56. {
  57. _NO_TRANSLATE_From.Text = url;
  58. }
  59. else
  60. {
  61. // Try to be more helpful to the user.
  62. // Use the cliboard text as a potential source URL.
  63. try
  64. {
  65. if (Clipboard.ContainsText(TextDataFormat.Text))
  66. {
  67. string text = Clipboard.GetText(TextDataFormat.Text) ?? string.Empty;
  68. // See if it's a valid URL.
  69. string lowerText = text.ToLowerInvariant();
  70. if (lowerText.StartsWith("http") ||
  71. lowerText.StartsWith("git") ||
  72. lowerText.StartsWith("ssh"))
  73. {
  74. _NO_TRANSLATE_From.Text = text;
  75. }
  76. }
  77. }
  78. catch (Exception)
  79. {
  80. // We tried.
  81. }
  82. //if the From field is empty, then fill it with the current repository remote URL in hope
  83. //that the cloned repository is hosted on the same server
  84. if (_NO_TRANSLATE_From.Text.IsNullOrWhiteSpace())
  85. {
  86. var currentBranchRemote = Module.GetSetting(string.Format(SettingKeyString.BranchRemote, Module.GetSelectedBranch()));
  87. if (currentBranchRemote.IsNullOrEmpty())
  88. {
  89. var remotes = Module.GetRemotes();
  90. if (remotes.Any(s => s.Equals("origin", StringComparison.InvariantCultureIgnoreCase)))
  91. currentBranchRemote = "origin";
  92. else
  93. currentBranchRemote = remotes.FirstOrDefault();
  94. }
  95. string pushUrl = Module.GetPathSetting(string.Format(SettingKeyString.RemotePushUrl, currentBranchRemote));
  96. if (pushUrl.IsNullOrEmpty())
  97. {
  98. pushUrl = Module.GetPathSetting(string.Format(SettingKeyString.RemoteUrl, currentBranchRemote));
  99. }
  100. _NO_TRANSLATE_From.Text = pushUrl;
  101. }
  102. }
  103. try
  104. {
  105. //if there is no destination directory, then use the parent directory of the current repository
  106. if (_NO_TRANSLATE_To.Text.IsNullOrWhiteSpace() && Module.WorkingDir.IsNotNullOrWhitespace())
  107. _NO_TRANSLATE_To.Text = Path.GetDirectoryName(Module.WorkingDir.TrimEnd(Path.DirectorySeparatorChar));
  108. }
  109. catch (Exception)
  110. { }
  111. FromTextUpdate(null, null);
  112. }
  113. private void OkClick(object sender, EventArgs e)
  114. {
  115. try
  116. {
  117. Cursor = Cursors.Default;
  118. _branchListLoader.Cancel();
  119. var dirTo = Path.Combine(_NO_TRANSLATE_To.Text, _NO_TRANSLATE_NewDirectory.Text);
  120. Repositories.AddMostRecentRepository(_NO_TRANSLATE_From.Text);
  121. if (!Directory.Exists(dirTo))
  122. Directory.CreateDirectory(dirTo);
  123. // Shallow clone params
  124. int? depth = null;
  125. bool? isSingleBranch = null;
  126. if(!cbDownloadFullHistory.Checked)
  127. {
  128. depth = 1;
  129. // Single branch considerations:
  130. // If neither depth nor single-branch family params are specified, then it's like no-single-branch by default.
  131. // If depth is specified, then single-branch is assumed.
  132. // But with single-branch it's really nontrivial to switch to another branch in the GUI, and it's very hard in cmdline (obvious choices to fetch another branch lead to local repo corruption).
  133. // So let's reset it to no-single-branch to (a) have the same branches behavior as with full clone, and (b) make it easier for users when switching branches.
  134. isSingleBranch = false;
  135. }
  136. // Branch name param
  137. string branch = _NO_TRANSLATE_Branches.Text;
  138. if(branch == _branchDefaultRemoteHead.Text)
  139. branch = "";
  140. else if(branch == _branchNone.Text)
  141. branch = null;
  142. var cloneCmd = GitCommandHelpers.CloneCmd(_NO_TRANSLATE_From.Text, dirTo,
  143. CentralRepository.Checked, cbIntializeAllSubmodules.Checked, branch, depth, isSingleBranch);
  144. using (var fromProcess = new FormRemoteProcess(Module, AppSettings.GitCommand, cloneCmd))
  145. {
  146. fromProcess.SetUrlTryingToConnect(_NO_TRANSLATE_From.Text);
  147. fromProcess.ShowDialog(this);
  148. if (fromProcess.ErrorOccurred() || Module.InTheMiddleOfPatch())
  149. return;
  150. }
  151. Repositories.AddMostRecentRepository(dirTo);
  152. if (openedFromProtocolHandler && AskIfNewRepositoryShouldBeOpened(dirTo))
  153. {
  154. Hide();
  155. GitUICommands uiCommands = new GitUICommands(dirTo);
  156. uiCommands.StartBrowseDialog();
  157. }
  158. else if (ShowInTaskbar == false && GitModuleChanged != null &&
  159. AskIfNewRepositoryShouldBeOpened(dirTo))
  160. GitModuleChanged(this, new GitModuleEventArgs(new GitModule(dirTo)));
  161. Close();
  162. }
  163. catch (Exception ex)
  164. {
  165. MessageBox.Show(this, "Exception: " + ex.Message, "Clone failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
  166. }
  167. }
  168. private bool AskIfNewRepositoryShouldBeOpened(string dirTo)
  169. {
  170. return MessageBox.Show(this, string.Format(_questionOpenRepo.Text, dirTo), _questionOpenRepoCaption.Text,
  171. MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
  172. }
  173. private void FromBrowseClick(object sender, EventArgs e)
  174. {
  175. var userSelectedPath = OsShellUtil.PickFolder(this, _NO_TRANSLATE_From.Text);
  176. if (userSelectedPath != null)
  177. {
  178. _NO_TRANSLATE_From.Text = userSelectedPath;
  179. }
  180. FromTextUpdate(sender, e);
  181. }
  182. private void ToBrowseClick(object sender, EventArgs e)
  183. {
  184. var userSelectedPath = OsShellUtil.PickFolder(this, _NO_TRANSLATE_To.Text);
  185. if (userSelectedPath != null)
  186. {
  187. _NO_TRANSLATE_To.Text = userSelectedPath;
  188. }
  189. ToTextUpdate(sender, e);
  190. }
  191. private void FillFromDropDown()
  192. {
  193. System.ComponentModel.BindingList<Repository> repos = Repositories.RemoteRepositoryHistory.Repositories;
  194. if (_NO_TRANSLATE_From.Items.Count != repos.Count)
  195. {
  196. _NO_TRANSLATE_To.Items.Clear();
  197. foreach (Repository repo in repos)
  198. _NO_TRANSLATE_From.Items.Add(repo.Path);
  199. }
  200. }
  201. private void ToDropDown(object sender, EventArgs e)
  202. {
  203. System.ComponentModel.BindingList<Repository> repos = Repositories.RepositoryHistory.Repositories;
  204. if (_NO_TRANSLATE_To.Items.Count != repos.Count)
  205. {
  206. _NO_TRANSLATE_To.Items.Clear();
  207. foreach (Repository repo in repos)
  208. _NO_TRANSLATE_To.Items.Add(repo.Path);
  209. }
  210. }
  211. private void LoadSshKeyClick(object sender, EventArgs e)
  212. {
  213. BrowseForPrivateKey.BrowseAndLoad(this);
  214. }
  215. private void FormCloneLoad(object sender, EventArgs e)
  216. {
  217. if (!GitCommandHelpers.Plink())
  218. LoadSSHKey.Visible = false;
  219. }
  220. private void FromSelectedIndexChanged(object sender, EventArgs e)
  221. {
  222. FromTextUpdate(sender, e);
  223. }
  224. private void FromTextUpdate(object sender, EventArgs e)
  225. {
  226. string path = PathUtil.GetRepositoryName(_NO_TRANSLATE_From.Text);
  227. if (path != "")
  228. {
  229. _NO_TRANSLATE_NewDirectory.Text = path;
  230. }
  231. _NO_TRANSLATE_Branches.DataSource = _defaultBranchItems;
  232. _NO_TRANSLATE_Branches.Select(0,0); // Kill full selection on the default branch text
  233. ToTextUpdate(sender, e);
  234. }
  235. private void ToTextUpdate(object sender, EventArgs e)
  236. {
  237. string destinationPath = string.Empty;
  238. if (string.IsNullOrEmpty(_NO_TRANSLATE_To.Text))
  239. destinationPath += "[" + label2.Text + "]";
  240. else
  241. destinationPath += _NO_TRANSLATE_To.Text.TrimEnd(new[] { '\\', '/' });
  242. destinationPath += "\\";
  243. if (string.IsNullOrEmpty(_NO_TRANSLATE_NewDirectory.Text))
  244. destinationPath += "[" + label3.Text + "]";
  245. else
  246. destinationPath += _NO_TRANSLATE_NewDirectory.Text;
  247. Info.Text = string.Format(_infoNewRepositoryLocation.Text, destinationPath);
  248. if (destinationPath.Contains("[") || destinationPath.Contains("]"))
  249. {
  250. Info.ForeColor = Color.Red;
  251. return;
  252. }
  253. if (Directory.Exists(destinationPath))
  254. {
  255. if (Directory.GetDirectories(destinationPath).Length > 0 || Directory.GetFiles(destinationPath).Length > 0)
  256. {
  257. Info.Text += " " + _infoDirectoryExists.Text;
  258. Info.ForeColor = Color.Red;
  259. }
  260. else
  261. {
  262. Info.ForeColor = Color.Black;
  263. }
  264. }
  265. else
  266. {
  267. Info.Text += " " + _infoDirectoryNew.Text;
  268. Info.ForeColor = Color.Black;
  269. }
  270. }
  271. private void NewDirectoryTextChanged(object sender, EventArgs e)
  272. {
  273. ToTextUpdate(sender, e);
  274. }
  275. private void ToSelectedIndexChanged(object sender, EventArgs e)
  276. {
  277. ToTextUpdate(sender, e);
  278. }
  279. private readonly AsyncLoader _branchListLoader = new AsyncLoader();
  280. private void UpdateBranches(RemoteActionResult<IList<IGitRef>> branchList)
  281. {
  282. Cursor = Cursors.Default;
  283. if (branchList.HostKeyFail)
  284. {
  285. string remoteUrl = _NO_TRANSLATE_From.Text;
  286. if (FormRemoteProcess.AskForCacheHostkey(this, Module, remoteUrl))
  287. {
  288. LoadBranches();
  289. }
  290. }
  291. else if (branchList.AuthenticationFail)
  292. {
  293. string loadedKey;
  294. if (FormPuttyError.AskForKey(this, out loadedKey))
  295. {
  296. LoadBranches();
  297. }
  298. }
  299. else
  300. {
  301. string text = _NO_TRANSLATE_Branches.Text;
  302. List<string> branchlist = _defaultBranchItems.Concat(branchList.Result.Select(o => o.LocalName)).ToList();
  303. _NO_TRANSLATE_Branches.DataSource = branchlist;
  304. if (branchlist.Any(a => a == text))
  305. {
  306. _NO_TRANSLATE_Branches.Text = text;
  307. }
  308. }
  309. }
  310. private void LoadBranches()
  311. {
  312. string from = _NO_TRANSLATE_From.Text;
  313. Cursor = Cursors.AppStarting;
  314. _branchListLoader.Load(() => Module.GetRemoteServerRefs(from, false, true), UpdateBranches);
  315. }
  316. private void Branches_DropDown(object sender, EventArgs e)
  317. {
  318. LoadBranches();
  319. }
  320. /// <summary>
  321. /// Clean up any resources being used.
  322. /// </summary>
  323. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  324. protected override void Dispose(bool disposing)
  325. {
  326. if (disposing)
  327. {
  328. _branchListLoader.Cancel();
  329. _branchListLoader.Dispose();
  330. if (components != null)
  331. components.Dispose();
  332. }
  333. base.Dispose(disposing);
  334. }
  335. }
  336. }