From f49d8764fb6d53650cb7fa719360d25bbcb49163 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 28 Sep 2023 15:53:25 +0700 Subject: [PATCH 01/13] Added public StartClone() option This is necessary so that flexbridge can supply required cloning information and start a repo download without direct/manual user input. This order will come from Fieldworks when launched from CMD or protocol handler with the proper arguments. --- .../UI/Clone/GetCloneFromInternetDialog.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index 5cfc5b84..34fecb10 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -261,11 +261,27 @@ private void _cancelButton_Click(object sender, EventArgs e) } private void OnDownloadClick(object sender, EventArgs e) + { + StartClone(); + } + + public void StartClone(string username, string password, Uri targetUri) + { + _model.Username = username; + _model.Password = password; + _model.CustomUrl = targetUri.ToString(); + _model.IsCustomUrl = true; + _model.LocalFolderName = GetProjectName(targetUri); + + StartClone(); + } + + private void StartClone() { lock (this) { _logBox.Clear(); - if(_backgroundWorker.IsBusy) + if (_backgroundWorker.IsBusy) return; UpdateDisplay(State.MakingClone); _model.SaveUserSettings(); @@ -275,6 +291,10 @@ private void OnDownloadClick(object sender, EventArgs e) } } + private string GetProjectName(Uri uri) + { + return uri.Segments[1].ToString(); + } public string ThreadSafeUrl { From ad42833cdecaa4bbce8574110589374854693e40 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 29 Sep 2023 09:39:07 +0700 Subject: [PATCH 02/13] Split project name from URI to its own param +semver:major --- .../UI/Clone/GetCloneFromInternetDialog.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index 34fecb10..0adfd4b8 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -265,13 +265,21 @@ private void OnDownloadClick(object sender, EventArgs e) StartClone(); } - public void StartClone(string username, string password, Uri targetUri) + + /// + /// Starts a clone operation with the supplied information. + /// Username for Mercurial authentication + /// Password for Mercurial authentication + /// Host name (with scheme), e.g. https://www.google.com + /// Name of the project to clone (will be combined with the host Uri) + /// + public void StartClone(string username, string password, Uri host, string projectName) { _model.Username = username; _model.Password = password; - _model.CustomUrl = targetUri.ToString(); + _model.CustomUrl = new Uri(host, projectName).ToString(); _model.IsCustomUrl = true; - _model.LocalFolderName = GetProjectName(targetUri); + _model.LocalFolderName = projectName; StartClone(); } @@ -291,11 +299,6 @@ private void StartClone() } } - private string GetProjectName(Uri uri) - { - return uri.Segments[1].ToString(); - } - public string ThreadSafeUrl { get; From 0f884e83fbe22fa98f6b1a64dd74fded78683f2a Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 29 Sep 2023 13:35:05 +0700 Subject: [PATCH 03/13] Using full URI to pass to Mercurial This gives us more flexibility (less security) for changing URI structure. --- src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index 0adfd4b8..a555f60c 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -270,14 +270,14 @@ private void OnDownloadClick(object sender, EventArgs e) /// Starts a clone operation with the supplied information. /// Username for Mercurial authentication /// Password for Mercurial authentication - /// Host name (with scheme), e.g. https://www.google.com - /// Name of the project to clone (will be combined with the host Uri) + /// Name of the project to clone + /// URI where the project can be found /// - public void StartClone(string username, string password, Uri host, string projectName) + public void StartClone(string username, string password, string projectName, Uri projectUri) { _model.Username = username; _model.Password = password; - _model.CustomUrl = new Uri(host, projectName).ToString(); + _model.CustomUrl = projectUri.ToString(); _model.IsCustomUrl = true; _model.LocalFolderName = projectName; From 0baa93709b1040b58066e2d1c70bc1e503845bcb Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 5 Oct 2023 14:44:52 +0700 Subject: [PATCH 04/13] Made the method static --- .../UI/Clone/GetCloneFromInternetDialog.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index a555f60c..f0793417 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -270,18 +270,26 @@ private void OnDownloadClick(object sender, EventArgs e) /// Starts a clone operation with the supplied information. /// Username for Mercurial authentication /// Password for Mercurial authentication + /// The parent directory to put the clone in /// Name of the project to clone /// URI where the project can be found /// - public void StartClone(string username, string password, string projectName, Uri projectUri) + public static GetCloneFromInternetDialog StartClone(string username, string password, string projectFolder, string projectName, Uri projectUri) { - _model.Username = username; - _model.Password = password; - _model.CustomUrl = projectUri.ToString(); - _model.IsCustomUrl = true; - _model.LocalFolderName = projectName; - - StartClone(); + var model = new GetCloneFromInternetModel(projectFolder) + { + Username = username, + Password = password, + CustomUrl = projectUri.ToString(), + IsCustomUrl = true, + LocalFolderName = projectName + }; + + var dialog = new GetCloneFromInternetDialog(model); + dialog.Show(); + dialog.StartClone(); + + return dialog; } private void StartClone() From 31df94d0530831cf56a3c32f8a9e816baff7e3be Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 5 Oct 2023 14:53:38 +0700 Subject: [PATCH 05/13] Updated changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b21b93..4d1f9fbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - [SIL.Chorus.LibChorus] Add webm as additional audio file type +- [SIL.Chorus] Add ability to clone project without direct user interaction ### Changed From 6d98401451651555e9a9f32a9499489fe23ce6aa Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 6 Oct 2023 11:00:24 +0700 Subject: [PATCH 06/13] Moved all caller operations into the method --- .../UI/Clone/GetCloneFromInternetDialog.cs | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index f0793417..88d4565e 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -96,6 +96,38 @@ public GetCloneFromInternetDialog(GetCloneFromInternetModel model) } + + /// + /// Performs a clone operation with the supplied information. + /// Username for Mercurial authentication + /// Password for Mercurial authentication + /// The parent directory to put the clone in + /// Name for the project on the local machine + /// URI where the project can be found + /// + public static CloneResult DoClone(string username, string password, string projectFolder, string projectName, Uri projectUri) + { + var model = new GetCloneFromInternetModel(projectFolder) + { + Username = username, + Password = password, + CustomUrl = projectUri.ToString(), + IsCustomUrl = true, + LocalFolderName = projectName + }; + + var dialog = new GetCloneFromInternetDialog(model); + DialogResult? res = null; + dialog.FormClosing += (sender, args) => res = dialog.DialogResult; + + dialog.Show(); + dialog.StartClone(); + Application.Run(dialog); + + var cloneStatus = res == DialogResult.OK ? CloneStatus.Created : CloneStatus.NotCreated; + return new CloneResult(dialog.PathToNewlyClonedFolder, cloneStatus); + } + private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if (_statusProgress.ErrorEncountered) @@ -265,33 +297,6 @@ private void OnDownloadClick(object sender, EventArgs e) StartClone(); } - - /// - /// Starts a clone operation with the supplied information. - /// Username for Mercurial authentication - /// Password for Mercurial authentication - /// The parent directory to put the clone in - /// Name of the project to clone - /// URI where the project can be found - /// - public static GetCloneFromInternetDialog StartClone(string username, string password, string projectFolder, string projectName, Uri projectUri) - { - var model = new GetCloneFromInternetModel(projectFolder) - { - Username = username, - Password = password, - CustomUrl = projectUri.ToString(), - IsCustomUrl = true, - LocalFolderName = projectName - }; - - var dialog = new GetCloneFromInternetDialog(model); - dialog.Show(); - dialog.StartClone(); - - return dialog; - } - private void StartClone() { lock (this) From 45ba1ef41f7c792541a188daf8a80ef3b5b78b3b Mon Sep 17 00:00:00 2001 From: Hasso Date: Fri, 6 Oct 2023 17:04:12 -0500 Subject: [PATCH 07/13] Centralise CloneResult generation and simplify DoClone --- .../UI/Clone/GetSharedProjectModelTests.cs | 22 ++++- .../UI/Clone/GetCloneFromInternetDialog.cs | 16 ++-- src/Chorus/UI/Clone/GetSharedProjectModel.cs | 92 +++++++------------ src/LibChorus/CloneResult.cs | 6 +- 4 files changed, 64 insertions(+), 72 deletions(-) diff --git a/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs b/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs index 6716c624..2ad47c54 100644 --- a/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs +++ b/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.IO; +using System.Windows.Forms; using Chorus.UI.Clone; using Chorus.VcsDrivers.Mercurial; using NUnit.Framework; @@ -10,6 +11,25 @@ namespace Chorus.Tests.UI.Clone [TestFixture] public class GetSharedProjectModelTests { + [Test] + public void GetResult([Values(true, false)] bool success) + { + const string cloneLocation = "D:\\uno"; + var result = GetSharedProjectModel.GetResult(DialogResult.OK, cloneLocation, success); + Assert.That(result.CloneStatus, Is.EqualTo(success ? CloneStatus.Created : CloneStatus.NotCreated)); + Assert.That(result.ActualLocation, Is.EqualTo(success ? cloneLocation : null)); + } + + [TestCase(DialogResult.OK, "C:\\somewhere", CloneStatus.Created)] + [TestCase(DialogResult.Cancel, "S:\\miles", CloneStatus.Cancelled)] + [TestCase(DialogResult.Abort, "E:\\elsewhere", CloneStatus.NotCreated)] + public void GetResult(DialogResult dialogResult, string cloneLocation, CloneStatus expectedStatus) + { + var result = GetSharedProjectModel.GetResult(dialogResult, cloneLocation); + Assert.That(result.CloneStatus, Is.EqualTo(expectedStatus)); + Assert.That(result.ActualLocation, Is.EqualTo(expectedStatus == CloneStatus.Created ? cloneLocation : null)); + } + [Test] public void HasNoExtantRepositories() { diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index 88d4565e..d910c61b 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -116,16 +116,14 @@ public static CloneResult DoClone(string username, string password, string proje LocalFolderName = projectName }; - var dialog = new GetCloneFromInternetDialog(model); - DialogResult? res = null; - dialog.FormClosing += (sender, args) => res = dialog.DialogResult; - - dialog.Show(); - dialog.StartClone(); - Application.Run(dialog); + using (var dialog = new GetCloneFromInternetDialog(model)) + { + dialog.Show(); + dialog.StartClone(); + Application.Run(dialog); - var cloneStatus = res == DialogResult.OK ? CloneStatus.Created : CloneStatus.NotCreated; - return new CloneResult(dialog.PathToNewlyClonedFolder, cloneStatus); + return GetSharedProjectModel.GetResult(dialog.DialogResult, dialog.PathToNewlyClonedFolder); + } } private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) diff --git a/src/Chorus/UI/Clone/GetSharedProjectModel.cs b/src/Chorus/UI/Clone/GetSharedProjectModel.cs index d7685480..8ce1fa5e 100644 --- a/src/Chorus/UI/Clone/GetSharedProjectModel.cs +++ b/src/Chorus/UI/Clone/GetSharedProjectModel.cs @@ -76,6 +76,8 @@ public CloneResult GetSharedProjectUsing(Form parent, string baseProjectDirForNe // "Seeing fit' may mean to warn the user they already have some repository, or as a filter to not show ones that already exist. // What to do with the list of extant repos is left up to a view+model pair. + var result = new CloneResult(null, CloneStatus.NotCreated); + // Select basic source type. using (var getSharedProjectDlg = new GetSharedProjectDlg()) { @@ -83,13 +85,11 @@ public CloneResult GetSharedProjectUsing(Form parent, string baseProjectDirForNe getSharedProjectDlg.ShowDialog(parent); if (getSharedProjectDlg.DialogResult != DialogResult.OK) { - return new CloneResult(null, CloneStatus.NotCreated); + return result; } } // Make clone from some source. - string actualCloneLocation = null; - var cloneStatus = CloneStatus.NotCreated; switch (RepositorySource) { case ExtantRepoSource.Internet: @@ -99,19 +99,7 @@ public CloneResult GetSharedProjectUsing(Form parent, string baseProjectDirForNe }; using (var cloneFromInternetDialog = new GetCloneFromInternetDialog(cloneFromInternetModel)) { - switch (cloneFromInternetDialog.ShowDialog(parent)) - { - default: - cloneStatus = CloneStatus.NotCreated; - break; - case DialogResult.Cancel: - cloneStatus = CloneStatus.Cancelled; - break; - case DialogResult.OK: - actualCloneLocation = cloneFromInternetDialog.PathToNewlyClonedFolder; - cloneStatus = CloneStatus.Created; - break; - } + result = GetResult(cloneFromInternetDialog.ShowDialog(parent), cloneFromInternetDialog.PathToNewlyClonedFolder); } break; @@ -125,26 +113,9 @@ public CloneResult GetSharedProjectUsing(Form parent, string baseProjectDirForNe using (var getCloneFromChorusHubDialog = new GetCloneFromChorusHubDialog(getCloneFromChorusHubModel)) { - switch (getCloneFromChorusHubDialog.ShowDialog(parent)) - { - default: - cloneStatus = CloneStatus.NotCreated; - break; - case DialogResult.Cancel: - cloneStatus = CloneStatus.Cancelled; - break; - case DialogResult.OK: - if (getCloneFromChorusHubModel.CloneSucceeded) - { - actualCloneLocation = getCloneFromChorusHubDialog.PathToNewlyClonedFolder; - cloneStatus = CloneStatus.Created; - } - else - { - cloneStatus = CloneStatus.NotCreated; - } - break; - } + result = GetResult(getCloneFromChorusHubDialog.ShowDialog(parent), + getCloneFromChorusHubDialog.PathToNewlyClonedFolder, + getCloneFromChorusHubModel.CloneSucceeded); } break; @@ -154,40 +125,43 @@ public CloneResult GetSharedProjectUsing(Form parent, string baseProjectDirForNe cloneFromUsbDialog.Model.ProjectFilter = projectFilter ?? DefaultProjectFilter; cloneFromUsbDialog.Model.ReposInUse = existingRepositories; cloneFromUsbDialog.Model.ExistingProjects = existingProjectNames; - switch (cloneFromUsbDialog.ShowDialog(parent)) - { - default: - cloneStatus = CloneStatus.NotCreated; - break; - case DialogResult.Cancel: - cloneStatus = CloneStatus.Cancelled; - break; - case DialogResult.OK: - actualCloneLocation = cloneFromUsbDialog.PathToNewlyClonedFolder; - cloneStatus = CloneStatus.Created; - break; - } + // USB repositories have already been checked for to see if the same repo has already been cloned; return before this check + return GetResult(cloneFromUsbDialog.ShowDialog(parent), cloneFromUsbDialog.PathToNewlyClonedFolder); } - break; } // Warn the user if they already have this by another name. - // Not currently needed for USB, since those have already been checked. - if (RepositorySource != ExtantRepoSource.Usb && cloneStatus == CloneStatus.Created) + if (result.CloneStatus == CloneStatus.Created) { - var repo = new HgRepository(actualCloneLocation, new NullProgress()); - string projectWithExistingRepo; - if (repo.Identifier != null && existingRepositories.TryGetValue(repo.Identifier, out projectWithExistingRepo)) + var repo = new HgRepository(result.ActualLocation, new NullProgress()); + if (repo.Identifier != null && existingRepositories.TryGetValue(repo.Identifier, out var projectWithExistingRepo)) { using (var warningDlg = new DuplicateProjectWarningDialog()) warningDlg.Run(projectWithExistingRepo, howToSendReceiveMessageText); - Directory.Delete(actualCloneLocation, true); - actualCloneLocation = null; - cloneStatus = CloneStatus.Cancelled; + Directory.Delete(result.ActualLocation, true); + return new CloneResult(null, CloneStatus.NotCreated); } + } + return result; + } + internal static CloneResult GetResult(DialogResult dialogResult, string cloneLocation, bool success = true) + { + CloneStatus cloneStatus; + switch (dialogResult) + { + default: + cloneStatus = CloneStatus.NotCreated; + break; + case DialogResult.Cancel: + cloneStatus = CloneStatus.Cancelled; + break; + case DialogResult.OK: + cloneStatus = success ? CloneStatus.Created : CloneStatus.NotCreated; + break; } - return new CloneResult(actualCloneLocation, cloneStatus); + + return new CloneResult(cloneStatus == CloneStatus.Created ? cloneLocation : null, cloneStatus); } internal static bool DefaultProjectFilter(string path) diff --git a/src/LibChorus/CloneResult.cs b/src/LibChorus/CloneResult.cs index c5ee6dc7..d0ab6aed 100644 --- a/src/LibChorus/CloneResult.cs +++ b/src/LibChorus/CloneResult.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2015 SIL International +// Copyright (c) 2015 SIL International // This software is licensed under the MIT License (http://opensource.org/licenses/MIT) using System; @@ -17,9 +17,9 @@ public CloneResult(string actualLocation, CloneStatus cloneStatus) } /// Get the actual location of a clone. (May, or may not, be the same as the desired location.) - public string ActualLocation { get; private set; } + public string ActualLocation { get; } /// Get the status of the clone attempt. - public CloneStatus CloneStatus { get; private set; } + public CloneStatus CloneStatus { get; } } /// From 57ce43469552845a8a269cc9fcc3159ff5be2bb0 Mon Sep 17 00:00:00 2001 From: Hasso Date: Fri, 6 Oct 2023 17:08:50 -0500 Subject: [PATCH 08/13] Simplify GetSharedProjectModel.GetResult --- .../UI/Clone/GetSharedProjectModelTests.cs | 10 +--------- src/Chorus/UI/Clone/GetSharedProjectModel.cs | 14 +++++++++----- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs b/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs index 2ad47c54..4c2ab956 100644 --- a/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs +++ b/src/Chorus.Tests/UI/Clone/GetSharedProjectModelTests.cs @@ -11,18 +11,10 @@ namespace Chorus.Tests.UI.Clone [TestFixture] public class GetSharedProjectModelTests { - [Test] - public void GetResult([Values(true, false)] bool success) - { - const string cloneLocation = "D:\\uno"; - var result = GetSharedProjectModel.GetResult(DialogResult.OK, cloneLocation, success); - Assert.That(result.CloneStatus, Is.EqualTo(success ? CloneStatus.Created : CloneStatus.NotCreated)); - Assert.That(result.ActualLocation, Is.EqualTo(success ? cloneLocation : null)); - } - [TestCase(DialogResult.OK, "C:\\somewhere", CloneStatus.Created)] [TestCase(DialogResult.Cancel, "S:\\miles", CloneStatus.Cancelled)] [TestCase(DialogResult.Abort, "E:\\elsewhere", CloneStatus.NotCreated)] + [TestCase(DialogResult.None, "~/no/where", CloneStatus.NotCreated)] public void GetResult(DialogResult dialogResult, string cloneLocation, CloneStatus expectedStatus) { var result = GetSharedProjectModel.GetResult(dialogResult, cloneLocation); diff --git a/src/Chorus/UI/Clone/GetSharedProjectModel.cs b/src/Chorus/UI/Clone/GetSharedProjectModel.cs index 8ce1fa5e..c288e2c3 100644 --- a/src/Chorus/UI/Clone/GetSharedProjectModel.cs +++ b/src/Chorus/UI/Clone/GetSharedProjectModel.cs @@ -113,9 +113,13 @@ public CloneResult GetSharedProjectUsing(Form parent, string baseProjectDirForNe using (var getCloneFromChorusHubDialog = new GetCloneFromChorusHubDialog(getCloneFromChorusHubModel)) { - result = GetResult(getCloneFromChorusHubDialog.ShowDialog(parent), - getCloneFromChorusHubDialog.PathToNewlyClonedFolder, - getCloneFromChorusHubModel.CloneSucceeded); + var dlgResult = getCloneFromChorusHubDialog.ShowDialog(parent); + if (dlgResult == DialogResult.OK && !getCloneFromChorusHubModel.CloneSucceeded) + { + // User clicked OK, but clone failed. Pass anything other than OK or Cancel to get CloneStatus.NotCreated + dlgResult = DialogResult.Abort; + } + result = GetResult(dlgResult, getCloneFromChorusHubDialog.PathToNewlyClonedFolder); } break; @@ -145,7 +149,7 @@ public CloneResult GetSharedProjectUsing(Form parent, string baseProjectDirForNe return result; } - internal static CloneResult GetResult(DialogResult dialogResult, string cloneLocation, bool success = true) + internal static CloneResult GetResult(DialogResult dialogResult, string cloneLocation) { CloneStatus cloneStatus; switch (dialogResult) @@ -157,7 +161,7 @@ internal static CloneResult GetResult(DialogResult dialogResult, string cloneLoc cloneStatus = CloneStatus.Cancelled; break; case DialogResult.OK: - cloneStatus = success ? CloneStatus.Created : CloneStatus.NotCreated; + cloneStatus = CloneStatus.Created; break; } From 448125f394e24f75d9e04a53ebc9fee575ad4ec2 Mon Sep 17 00:00:00 2001 From: Hasso Date: Mon, 9 Oct 2023 12:04:29 -0500 Subject: [PATCH 09/13] Add public GCFInternetDlg.ConfirmAndDoClone --- .../UI/Clone/GetCloneFromInternetDialog.cs | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index d910c61b..375766cd 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -96,15 +96,38 @@ public GetCloneFromInternetDialog(GetCloneFromInternetModel model) } + /// + /// Confirms with a dialog, then performs a clone operation with the supplied information. + /// + /// Username for Mercurial authentication + /// Password for Mercurial authentication + /// The parent directory to put the clone in + /// Name for the project on the local machine + /// URI where the project can be found + public static CloneResult ConfirmAndDoClone(string username, string password, string projectFolder, string projectName, Uri projectUri) + { + var projectNameExtractor = new GetCloneFromInternetModel(); + projectNameExtractor.InitFromUri(projectUri.ToString()); + var proj = string.IsNullOrEmpty(projectNameExtractor.ProjectId) ? projectName : projectNameExtractor.ProjectId; + var host = new Uri(projectUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped)); + + var msg = string.Format(LocalizationManager.GetString("GetCloneFromInternet.DownloadProjectFromHost", "Download {0} from {1}?"), + proj, host); + var caption = LocalizationManager.GetString("GetCloneFromInternet.ConfirmDownload", "Confirm Download"); + + return MessageBox.Show(msg, caption, MessageBoxButtons.YesNo) == DialogResult.Yes + ? DoClone(username, password, projectFolder, projectName, projectUri) + : null; + } /// /// Performs a clone operation with the supplied information. + /// /// Username for Mercurial authentication /// Password for Mercurial authentication /// The parent directory to put the clone in /// Name for the project on the local machine /// URI where the project can be found - /// public static CloneResult DoClone(string username, string password, string projectFolder, string projectName, Uri projectUri) { var model = new GetCloneFromInternetModel(projectFolder) @@ -305,7 +328,6 @@ private void StartClone() UpdateDisplay(State.MakingClone); _model.SaveUserSettings(); ThreadSafeUrl = _model.URL; - //_backgroundWorker.RunWorkerAsync(new object[] { ThreadSafeUrl, PathToNewProject, _progress }); _backgroundWorker.RunWorkerAsync(new object[0]); } } From dd31a7e3284b58ce50df259dfed57c7a814be212 Mon Sep 17 00:00:00 2001 From: Hasso Date: Mon, 9 Oct 2023 13:50:12 -0500 Subject: [PATCH 10/13] Pass URI as a string to match other ServerSettingsModel --- src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index 375766cd..3cc8aac9 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -104,12 +104,12 @@ public GetCloneFromInternetDialog(GetCloneFromInternetModel model) /// The parent directory to put the clone in /// Name for the project on the local machine /// URI where the project can be found - public static CloneResult ConfirmAndDoClone(string username, string password, string projectFolder, string projectName, Uri projectUri) + public static CloneResult ConfirmAndDoClone(string username, string password, string projectFolder, string projectName, string projectUri) { var projectNameExtractor = new GetCloneFromInternetModel(); - projectNameExtractor.InitFromUri(projectUri.ToString()); + projectNameExtractor.InitFromUri(projectUri); var proj = string.IsNullOrEmpty(projectNameExtractor.ProjectId) ? projectName : projectNameExtractor.ProjectId; - var host = new Uri(projectUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped)); + var host = new Uri(projectUri).GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped); var msg = string.Format(LocalizationManager.GetString("GetCloneFromInternet.DownloadProjectFromHost", "Download {0} from {1}?"), proj, host); @@ -128,13 +128,13 @@ public static CloneResult ConfirmAndDoClone(string username, string password, st /// The parent directory to put the clone in /// Name for the project on the local machine /// URI where the project can be found - public static CloneResult DoClone(string username, string password, string projectFolder, string projectName, Uri projectUri) + public static CloneResult DoClone(string username, string password, string projectFolder, string projectName, string projectUri) { var model = new GetCloneFromInternetModel(projectFolder) { Username = username, Password = password, - CustomUrl = projectUri.ToString(), + CustomUrl = projectUri, IsCustomUrl = true, LocalFolderName = projectName }; From 2f15202f9a65e5deff89d843ed3229991897852e Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 12 Oct 2023 15:16:56 +0700 Subject: [PATCH 11/13] Revert user/pass after clone You certainly don't want to leave it just like this, but it's a start for an idea. You could add a flag to the method, or potentially interpret automatically from the existing inputs. Or you could change the ServerSettingsModel. --- .../UI/Clone/GetCloneFromInternetDialog.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index 3cc8aac9..e230c50f 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -130,14 +130,14 @@ public static CloneResult ConfirmAndDoClone(string username, string password, st /// URI where the project can be found public static CloneResult DoClone(string username, string password, string projectFolder, string projectName, string projectUri) { - var model = new GetCloneFromInternetModel(projectFolder) - { - Username = username, - Password = password, - CustomUrl = projectUri, - IsCustomUrl = true, - LocalFolderName = projectName - }; + var model = new GetCloneFromInternetModel(projectFolder); + var oldUser = model.Username; + var oldPass = model.Password; + model.Username = username; + model.Password = password; + model.CustomUrl = projectUri; + model.IsCustomUrl = true; + model.LocalFolderName = projectName; using (var dialog = new GetCloneFromInternetDialog(model)) { @@ -145,6 +145,10 @@ public static CloneResult DoClone(string username, string password, string proje dialog.StartClone(); Application.Run(dialog); + model.Username = oldUser; + model.Password = oldPass; + model.SaveUserSettings(); + return GetSharedProjectModel.GetResult(dialog.DialogResult, dialog.PathToNewlyClonedFolder); } } From 6e7c7752f051f1863138ac113d17707393dfd697 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 13 Oct 2023 09:40:02 +0700 Subject: [PATCH 12/13] Revert in finally block and behind optional flag We want to give callers the option to revert, e.g. if they know the user/pass is JWT, but default it to saving them. --- .../UI/Clone/GetCloneFromInternetDialog.cs | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index e230c50f..ba0dc43b 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -128,7 +128,8 @@ public static CloneResult ConfirmAndDoClone(string username, string password, st /// The parent directory to put the clone in /// Name for the project on the local machine /// URI where the project can be found - public static CloneResult DoClone(string username, string password, string projectFolder, string projectName, string projectUri) + /// Flag to persist username and password in settings + public static CloneResult DoClone(string username, string password, string projectFolder, string projectName, string projectUri, bool saveUserSettings = true) { var model = new GetCloneFromInternetModel(projectFolder); var oldUser = model.Username; @@ -141,13 +142,21 @@ public static CloneResult DoClone(string username, string password, string proje using (var dialog = new GetCloneFromInternetDialog(model)) { - dialog.Show(); - dialog.StartClone(); - Application.Run(dialog); - - model.Username = oldUser; - model.Password = oldPass; - model.SaveUserSettings(); + try + { + dialog.Show(); + dialog.StartClone(); + Application.Run(dialog); + } + finally + { + if (!saveUserSettings) + { + model.Username = oldUser; + model.Password = oldPass; + model.SaveUserSettings(); + } + } return GetSharedProjectModel.GetResult(dialog.DialogResult, dialog.PathToNewlyClonedFolder); } From 473c7987c83d11a23ad4fee64199bec6807d7305 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Fri, 13 Oct 2023 13:36:30 +0700 Subject: [PATCH 13/13] Added flag for the other method, as well --- src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs index ba0dc43b..afb1742b 100644 --- a/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs +++ b/src/Chorus/UI/Clone/GetCloneFromInternetDialog.cs @@ -104,7 +104,8 @@ public GetCloneFromInternetDialog(GetCloneFromInternetModel model) /// The parent directory to put the clone in /// Name for the project on the local machine /// URI where the project can be found - public static CloneResult ConfirmAndDoClone(string username, string password, string projectFolder, string projectName, string projectUri) + /// Flag to persist username and password in settings + public static CloneResult ConfirmAndDoClone(string username, string password, string projectFolder, string projectName, string projectUri, bool saveUserSettings = true) { var projectNameExtractor = new GetCloneFromInternetModel(); projectNameExtractor.InitFromUri(projectUri); @@ -116,7 +117,7 @@ public static CloneResult ConfirmAndDoClone(string username, string password, st var caption = LocalizationManager.GetString("GetCloneFromInternet.ConfirmDownload", "Confirm Download"); return MessageBox.Show(msg, caption, MessageBoxButtons.YesNo) == DialogResult.Yes - ? DoClone(username, password, projectFolder, projectName, projectUri) + ? DoClone(username, password, projectFolder, projectName, projectUri, saveUserSettings) : null; }