PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/GitUI/CommandsDialogs/RepoHosting/ForkAndCloneForm.cs

https://github.com/qgppl/gitextensions
C# | 387 lines | 331 code | 56 blank | 0 comment | 50 complexity | 56b3910e91b6f5eae998308d322127ff MD5 | raw file
Possible License(s): GPL-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Windows.Forms;
  7. using GitCommands;
  8. using GitCommands.Repository;
  9. using GitUIPluginInterfaces.RepositoryHosts;
  10. using ResourceManager;
  11. namespace GitUI.CommandsDialogs.RepoHosting
  12. {
  13. public partial class ForkAndCloneForm : GitExtensionsForm
  14. {
  15. #region Translation
  16. private readonly TranslationString _strError = new TranslationString("Error");
  17. private readonly TranslationString _strLoading = new TranslationString(" : LOADING : ");
  18. private readonly TranslationString _strYes = new TranslationString("Yes");
  19. private readonly TranslationString _strNo = new TranslationString("No");
  20. private readonly TranslationString _strFailedToGetRepos = new TranslationString("Failed to get repositories. This most likely means you didn't configure {0}, please do so via the menu \"Plugins/{0}\".");
  21. private readonly TranslationString _strWillCloneWithPushAccess = new TranslationString("Will clone {0} into {1}.\r\nYou will have push access. {2}");
  22. private readonly TranslationString _strWillCloneInfo = new TranslationString("Will clone {0} into {1}.\r\nYou can not push unless you are a collaborator. {2}");
  23. private readonly TranslationString _strWillBeAddedAsARemote = new TranslationString("\"{0}\" will be added as a remote.");
  24. private readonly TranslationString _strCouldNotAddRemote = new TranslationString("Could not add remote");
  25. private readonly TranslationString _strNoHomepageDefined = new TranslationString("No homepage defined");
  26. private readonly TranslationString _strFailedToFork = new TranslationString("Failed to fork:");
  27. private readonly TranslationString _strSearchFailed = new TranslationString("Search failed!");
  28. private readonly TranslationString _strUserNotFound = new TranslationString("User not found!");
  29. private readonly TranslationString _strCouldNotFetchReposOfUser = new TranslationString("Could not fetch repositories of user!");
  30. private readonly TranslationString _strSearching = new TranslationString(" : SEARCHING : ");
  31. private readonly TranslationString _strSelectOneItem = new TranslationString("You must select exactly one item");
  32. private readonly TranslationString _strCloneFolderCanNotBeEmpty = new TranslationString("Clone folder can not be empty");
  33. #endregion
  34. readonly IRepositoryHostPlugin _gitHoster;
  35. private EventHandler<GitModuleEventArgs> GitModuleChanged;
  36. public ForkAndCloneForm(IRepositoryHostPlugin gitHoster, EventHandler<GitModuleEventArgs> GitModuleChanged)
  37. {
  38. this.GitModuleChanged = GitModuleChanged;
  39. _gitHoster = gitHoster;
  40. InitializeComponent();
  41. Translate();
  42. }
  43. private void ForkAndCloneForm_Load(object sender, EventArgs e)
  44. {
  45. Init();
  46. }
  47. private void Init()
  48. {
  49. if (!string.IsNullOrEmpty(AppSettings.DefaultCloneDestinationPath))
  50. {
  51. _destinationTB.Text = AppSettings.DefaultCloneDestinationPath;
  52. }
  53. else
  54. {
  55. var hist = Repositories.RepositoryHistory;
  56. var lastRepo = hist.Repositories.FirstOrDefault();
  57. if (lastRepo != null && !string.IsNullOrEmpty(lastRepo.Path))
  58. {
  59. string p = lastRepo.Path.Trim('/', '\\');
  60. _destinationTB.Text = Path.GetDirectoryName(p);
  61. }
  62. }
  63. Text = _gitHoster.Description + ": " + Text;
  64. UpdateCloneInfo();
  65. UpdateMyRepos();
  66. }
  67. private void UpdateMyRepos()
  68. {
  69. _myReposLV.Items.Clear();
  70. _myReposLV.Items.Add(new ListViewItem { Text = _strLoading.Text });
  71. AsyncLoader.DoAsync(
  72. () => _gitHoster.GetMyRepos(),
  73. repos =>
  74. {
  75. _myReposLV.Items.Clear();
  76. foreach (var repo in repos)
  77. {
  78. var lvi = new ListViewItem { Tag = repo, Text = repo.Name };
  79. lvi.SubItems.Add(repo.IsAFork ? _strYes.Text : _strNo.Text);
  80. lvi.SubItems.Add(repo.Forks.ToString());
  81. lvi.SubItems.Add(repo.IsPrivate ? _strYes.Text : _strNo.Text);
  82. _myReposLV.Items.Add(lvi);
  83. }
  84. },
  85. ex =>
  86. {
  87. _myReposLV.Items.Clear();
  88. _helpTextLbl.Text = string.Format(_strFailedToGetRepos.Text, _gitHoster.Description) +
  89. "\r\n\r\nException: " + ex.Exception.Message + "\r\n\r\n" + _helpTextLbl.Text;
  90. });
  91. }
  92. #region GUI Handlers
  93. private void _searchBtn_Click(object sender, EventArgs e)
  94. {
  95. var search = _searchTB.Text;
  96. if (search == null || search.Trim().Length == 0)
  97. return;
  98. PrepareSearch(sender, e);
  99. AsyncLoader.DoAsync(
  100. () => _gitHoster.SearchForRepository(search),
  101. HandleSearchResult,
  102. ex =>
  103. {
  104. MessageBox.Show(this, _strSearchFailed.Text + Environment.NewLine + ex.Exception.Message,
  105. _strError.Text);
  106. _searchBtn.Enabled = true;
  107. });
  108. }
  109. private void _getFromUserBtn_Click(object sender, EventArgs e)
  110. {
  111. var search = _searchTB.Text;
  112. if (search == null || search.Trim().Length == 0)
  113. return;
  114. PrepareSearch(sender, e);
  115. AsyncLoader.DoAsync(
  116. () => _gitHoster.GetRepositoriesOfUser(search.Trim()),
  117. HandleSearchResult,
  118. ex =>
  119. {
  120. if (ex.Exception.Message.Contains("404"))
  121. MessageBox.Show(this, _strUserNotFound.Text, _strError.Text);
  122. else
  123. MessageBox.Show(this, _strCouldNotFetchReposOfUser.Text + Environment.NewLine +
  124. ex.Exception.Message, _strError.Text);
  125. _searchBtn.Enabled = true;
  126. });
  127. }
  128. private void PrepareSearch(object sender, EventArgs e)
  129. {
  130. _searchResultsLV.Items.Clear();
  131. _searchResultsLV_SelectedIndexChanged(sender, e);
  132. _searchBtn.Enabled = false;
  133. _searchResultsLV.Items.Add(new ListViewItem { Text = _strSearching.Text });
  134. }
  135. private void HandleSearchResult(IList<IHostedRepository> repos)
  136. {
  137. _searchResultsLV.Items.Clear();
  138. foreach (var repo in repos)
  139. {
  140. var lvi = new ListViewItem { Tag = repo, Text = repo.Name };
  141. lvi.SubItems.Add(repo.Owner);
  142. lvi.SubItems.Add(repo.Forks.ToString());
  143. lvi.SubItems.Add(repo.IsAFork ? _strYes.Text : _strNo.Text);
  144. _searchResultsLV.Items.Add(lvi);
  145. }
  146. _searchBtn.Enabled = true;
  147. }
  148. private void _forkBtn_Click(object sender, EventArgs e)
  149. {
  150. if (_searchResultsLV.SelectedItems.Count != 1)
  151. {
  152. MessageBox.Show(this, _strSelectOneItem.Text, _strError.Text);
  153. return;
  154. }
  155. var hostedRepo = _searchResultsLV.SelectedItems[0].Tag as IHostedRepository;
  156. try
  157. {
  158. if (hostedRepo != null) hostedRepo.Fork();
  159. }
  160. catch (Exception ex)
  161. {
  162. MessageBox.Show(this, _strFailedToFork.Text + Environment.NewLine + ex.Message, _strError.Text);
  163. }
  164. _tabControl.SelectedTab = _myReposPage;
  165. UpdateMyRepos();
  166. }
  167. private void _searchTB_Enter(object sender, EventArgs e)
  168. {
  169. AcceptButton = _searchBtn;
  170. }
  171. private void _searchTB_Leave(object sender, EventArgs e)
  172. {
  173. AcceptButton = null;
  174. }
  175. private void _searchResultsLV_SelectedIndexChanged(object sender, EventArgs e)
  176. {
  177. UpdateCloneInfo();
  178. if (_searchResultsLV.SelectedItems.Count != 1)
  179. {
  180. _forkBtn.Enabled = false;
  181. return;
  182. }
  183. _forkBtn.Enabled = true;
  184. var hostedRepo = (IHostedRepository)_searchResultsLV.SelectedItems[0].Tag;
  185. _searchResultItemDescription.Text = hostedRepo.Description;
  186. }
  187. private void _browseForCloneToDirbtn_Click(object sender, EventArgs e)
  188. {
  189. var initialDir = _destinationTB.Text.Length > 0 ? _destinationTB.Text : "C:\\";
  190. var userSelectedPath = OsShellUtil.PickFolder(this, initialDir);
  191. if (userSelectedPath != null)
  192. {
  193. _destinationTB.Text = userSelectedPath;
  194. _destinationTB_TextChanged(sender, e);
  195. }
  196. }
  197. private void _cloneBtn_Click(object sender, EventArgs e)
  198. {
  199. Clone(CurrentySelectedGitRepo);
  200. }
  201. private void _openGitupPageBtn_Click(object sender, EventArgs e)
  202. {
  203. if (CurrentySelectedGitRepo == null)
  204. return;
  205. string hp = CurrentySelectedGitRepo.Homepage;
  206. if (string.IsNullOrEmpty(hp) || (!hp.StartsWith("http://") && !hp.StartsWith("https://")))
  207. MessageBox.Show(this, _strNoHomepageDefined.Text, _strError.Text);
  208. else
  209. Process.Start(CurrentySelectedGitRepo.Homepage);
  210. }
  211. private void _closeBtn_Click(object sender, EventArgs e)
  212. {
  213. DialogResult = DialogResult.OK;
  214. }
  215. private void _tabControl_SelectedIndexChanged(object sender, EventArgs e)
  216. {
  217. UpdateCloneInfo();
  218. if (_tabControl.SelectedTab == _searchReposPage)
  219. _searchTB.Focus();
  220. }
  221. private void _myReposLV_SelectedIndexChanged(object sender, EventArgs e)
  222. {
  223. UpdateCloneInfo();
  224. }
  225. private void _createDirTB_TextChanged(object sender, EventArgs e)
  226. {
  227. UpdateCloneInfo(false);
  228. }
  229. private void _destinationTB_TextChanged(object sender, EventArgs e)
  230. {
  231. UpdateCloneInfo(false);
  232. }
  233. private void _addRemoteAsTB_TextChanged(object sender, EventArgs e)
  234. {
  235. UpdateCloneInfo(false);
  236. }
  237. #endregion
  238. private void Clone(IHostedRepository repo)
  239. {
  240. string targetDir = GetTargetDir();
  241. if (targetDir == null)
  242. return;
  243. string repoSrc = repo.CloneReadWriteUrl;
  244. string cmd = GitCommandHelpers.CloneCmd(repoSrc, targetDir);
  245. FormRemoteProcess formRemoteProcess = new FormRemoteProcess(new GitModule(null), AppSettings.GitCommand, cmd);
  246. formRemoteProcess.Remote = repoSrc;
  247. formRemoteProcess.ShowDialog();
  248. if (formRemoteProcess.ErrorOccurred())
  249. return;
  250. GitModule module = new GitModule(targetDir);
  251. if (_addRemoteAsTB.Text.Trim().Length > 0 && !string.IsNullOrEmpty(repo.ParentReadOnlyUrl))
  252. {
  253. var error = module.AddRemote(_addRemoteAsTB.Text.Trim(), repo.ParentReadOnlyUrl);
  254. if (!string.IsNullOrEmpty(error))
  255. MessageBox.Show(this, error, _strCouldNotAddRemote.Text);
  256. }
  257. if (GitModuleChanged != null)
  258. GitModuleChanged(this, new GitModuleEventArgs(module));
  259. Close();
  260. }
  261. private IHostedRepository CurrentySelectedGitRepo
  262. {
  263. get
  264. {
  265. if (_tabControl.SelectedTab == _searchReposPage)
  266. {
  267. if (_searchResultsLV.SelectedItems.Count != 1)
  268. return null;
  269. return (IHostedRepository)_searchResultsLV.SelectedItems[0].Tag;
  270. }
  271. if (_myReposLV.SelectedItems.Count != 1)
  272. return null;
  273. return (IHostedRepository)_myReposLV.SelectedItems[0].Tag;
  274. }
  275. }
  276. private void UpdateCloneInfo()
  277. {
  278. UpdateCloneInfo(true);
  279. }
  280. private void UpdateCloneInfo(bool updateCreateDirTB)
  281. {
  282. var repo = CurrentySelectedGitRepo;
  283. if (repo != null)
  284. {
  285. if (updateCreateDirTB)
  286. {
  287. _createDirTB.Text = repo.Name;
  288. _addRemoteAsTB.Text = repo.ParentOwner ?? "";
  289. _addRemoteAsTB.Enabled = repo.ParentOwner != null;
  290. }
  291. _cloneBtn.Enabled = true;
  292. var moreInfo = !string.IsNullOrEmpty(_addRemoteAsTB.Text) ? string.Format(_strWillBeAddedAsARemote.Text, _addRemoteAsTB.Text.Trim()) : "";
  293. if (_tabControl.SelectedTab == _searchReposPage)
  294. _cloneInfoText.Text = string.Format(_strWillCloneInfo.Text, repo.CloneReadWriteUrl, GetTargetDir(), moreInfo);
  295. else if (_tabControl.SelectedTab == _myReposPage)
  296. _cloneInfoText.Text = string.Format(_strWillCloneWithPushAccess.Text, repo.CloneReadWriteUrl, GetTargetDir(), moreInfo);
  297. }
  298. else
  299. {
  300. _cloneBtn.Enabled = false;
  301. _cloneInfoText.Text = "";
  302. _createDirTB.Text = "";
  303. }
  304. }
  305. private string GetTargetDir()
  306. {
  307. string targetDir = _destinationTB.Text.Trim();
  308. if (targetDir.Length == 0)
  309. {
  310. MessageBox.Show(this, _strCloneFolderCanNotBeEmpty.Text, _strError.Text);
  311. return null;
  312. }
  313. targetDir = Path.Combine(targetDir, _createDirTB.Text);
  314. return targetDir;
  315. }
  316. private void _destinationTB_Validating(object sender, System.ComponentModel.CancelEventArgs e)
  317. {
  318. if (_destinationTB.Text.IndexOfAny(Path.GetInvalidPathChars()) != -1)
  319. e.Cancel = true;
  320. }
  321. private void _createDirTB_Validating(object sender, System.ComponentModel.CancelEventArgs e)
  322. {
  323. if (_createDirTB.Text.IndexOfAny(Path.GetInvalidPathChars()) != -1)
  324. e.Cancel = true;
  325. }
  326. }
  327. }