diff --git a/src/GitHub.App/Services/RepositoryCloneService.cs b/src/GitHub.App/Services/RepositoryCloneService.cs
index 7fc5e6e3e4..4b543f6daa 100644
--- a/src/GitHub.App/Services/RepositoryCloneService.cs
+++ b/src/GitHub.App/Services/RepositoryCloneService.cs
@@ -129,7 +129,7 @@ public async Task CloneOrOpenRepository(
var repositoryUrl = url.ToRepositoryUrl();
var isDotCom = HostAddress.IsGitHubDotComUri(repositoryUrl);
- if (DestinationDirectoryExists(repositoryPath))
+ if (DestinationDirectoryExists(repositoryPath) && !DestinationDirectoryEmpty(repositoryPath))
{
if (!IsSolutionInRepository(repositoryPath))
{
@@ -206,9 +206,12 @@ public async Task CloneRepository(
// Switch to a thread pool thread for IO then back to the main thread to call
// vsGitServices.Clone() as this must be called on the main thread.
- await ThreadingHelper.SwitchToPoolThreadAsync();
- operatingSystem.Directory.CreateDirectory(repositoryPath);
- await ThreadingHelper.SwitchToMainThreadAsync();
+ if (!DestinationDirectoryExists(repositoryPath))
+ {
+ await ThreadingHelper.SwitchToPoolThreadAsync();
+ operatingSystem.Directory.CreateDirectory(repositoryPath);
+ await ThreadingHelper.SwitchToMainThreadAsync();
+ }
try
{
@@ -232,6 +235,9 @@ public async Task CloneRepository(
///
public bool DestinationDirectoryExists(string path) => operatingSystem.Directory.DirectoryExists(path);
+ ///
+ public bool DestinationDirectoryEmpty(string path) => operatingSystem.Directory.GetDirectory(path).IsEmpty;
+
///
public bool DestinationFileExists(string path) => operatingSystem.File.Exists(path);
diff --git a/src/GitHub.App/ViewModels/Dialog/Clone/RepositoryCloneViewModel.cs b/src/GitHub.App/ViewModels/Dialog/Clone/RepositoryCloneViewModel.cs
index 585f57c5cb..ff30629bfa 100644
--- a/src/GitHub.App/ViewModels/Dialog/Clone/RepositoryCloneViewModel.cs
+++ b/src/GitHub.App/ViewModels/Dialog/Clone/RepositoryCloneViewModel.cs
@@ -67,11 +67,13 @@ public RepositoryCloneViewModel(
var canClone = Observable.CombineLatest(
repository, this.WhenAnyValue(x => x.Path),
- (repo, path) => repo != null && !service.DestinationFileExists(path) && !service.DestinationDirectoryExists(path));
+ (repo, path) => repo != null && !service.DestinationFileExists(path) &&
+ (!service.DestinationDirectoryExists(path)) || service.DestinationDirectoryEmpty(path));
var canOpen = Observable.CombineLatest(
repository, this.WhenAnyValue(x => x.Path),
- (repo, path) => repo != null && !service.DestinationFileExists(path) && service.DestinationDirectoryExists(path));
+ (repo, path) => repo != null && !service.DestinationFileExists(path) && service.DestinationDirectoryExists(path)
+ && !service.DestinationDirectoryEmpty(path));
Browse = ReactiveCommand.Create(() => BrowseForDirectory());
Clone = ReactiveCommand.CreateFromObservable(
@@ -236,13 +238,13 @@ string ValidatePathWarning(RepositoryModel repositoryModel, string path)
return Resources.DestinationAlreadyExists;
}
- if (service.DestinationDirectoryExists(path))
+ if (service.DestinationDirectoryExists(path) && !service.DestinationDirectoryEmpty(path))
{
using (var repository = gitService.GetRepository(path))
{
if (repository == null)
{
- return Resources.CantFindARepositoryAtLocalPath;
+ return Resources.DirectoryAtDestinationNotEmpty;
}
var localUrl = gitService.GetRemoteUri(repository)?.ToRepositoryUrl();
@@ -254,7 +256,8 @@ string ValidatePathWarning(RepositoryModel repositoryModel, string path)
var targetUrl = repositoryModel.CloneUrl?.ToRepositoryUrl();
if (localUrl != targetUrl)
{
- return string.Format(CultureInfo.CurrentCulture, Resources.LocalRepositoryHasARemoteOf, localUrl);
+ return string.Format(CultureInfo.CurrentCulture, Resources.LocalRepositoryHasARemoteOf,
+ localUrl);
}
return Resources.YouHaveAlreadyClonedToThisLocation;
diff --git a/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs b/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs
index 152a203d60..791aa25734 100644
--- a/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs
+++ b/src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs
@@ -58,6 +58,15 @@ Task CloneOrOpenRepository(
///
bool DestinationDirectoryExists(string path);
+ ///
+ /// Checks whether the specified destination directory is empty.
+ ///
+ /// The destination path.
+ ///
+ /// true if a directory is empty ; otherwise false.
+ ///
+ bool DestinationDirectoryEmpty(string path);
+
///
/// Checks whether the specified destination file already exists.
///
diff --git a/src/GitHub.Resources/Resources.Designer.cs b/src/GitHub.Resources/Resources.Designer.cs
index 52383bf054..5aa9144ed9 100644
--- a/src/GitHub.Resources/Resources.Designer.cs
+++ b/src/GitHub.Resources/Resources.Designer.cs
@@ -267,15 +267,6 @@ public static string CancelPendingReviewConfirmationCaption {
}
}
- ///
- /// Looks up a localized string similar to There is already a directory at this location, but it doesn't contain a repository..
- ///
- public static string CantFindARepositoryAtLocalPath {
- get {
- return ResourceManager.GetString("CantFindARepositoryAtLocalPath", resourceCulture);
- }
- }
-
///
/// Looks up a localized string similar to Can't find GitHub URL for repository.
///
@@ -603,6 +594,15 @@ public static string DifferentRepositoryMessage {
}
}
+ ///
+ /// Looks up a localized string similar to The directory at the destination path is not empty..
+ ///
+ public static string DirectoryAtDestinationNotEmpty {
+ get {
+ return ResourceManager.GetString("DirectoryAtDestinationNotEmpty", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Don’t have an account? .
///
diff --git a/src/GitHub.Resources/Resources.cs-CZ.resx b/src/GitHub.Resources/Resources.cs-CZ.resx
index 787a8a0323..89d9096aed 100644
--- a/src/GitHub.Resources/Resources.cs-CZ.resx
+++ b/src/GitHub.Resources/Resources.cs-CZ.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
V aktuálním úložišti se nepodařilo najít cílovou adresu URL. Zkuste to znovu po načtení změn.
-
- V tomto umístění je už adresář, ale neobsahuje úložiště.
+
+ The directory at the destination path is not empty.
Úložiště už v tomto umístění existuje, ale nemá vzdálené úložiště s názvem origin.
diff --git a/src/GitHub.Resources/Resources.de-DE.resx b/src/GitHub.Resources/Resources.de-DE.resx
index c66c0bfd50..1b0e34db11 100644
--- a/src/GitHub.Resources/Resources.de-DE.resx
+++ b/src/GitHub.Resources/Resources.de-DE.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
Die Ziel-URL wurde im aktuellen Repository nicht gefunden. Versuchen Sie es nach einem Abrufvorgang (fetch) noch einmal.
-
- An diesem Speicherort liegt bereits ein Verzeichnis vor, aber es enthält kein Repository.
+
+ The directory at the destination path is not empty.
An diesem Speicherort ist bereits ein Repository vorhanden, das aber kein Remoterepository namens "origin" aufweist.
diff --git a/src/GitHub.Resources/Resources.es-ES.resx b/src/GitHub.Resources/Resources.es-ES.resx
index d416d9875c..c243ffb369 100644
--- a/src/GitHub.Resources/Resources.es-ES.resx
+++ b/src/GitHub.Resources/Resources.es-ES.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
No se encontró la dirección URL de destino en el repositorio actual. Vuelva a intentarlo tras una recuperación de cambios.
-
- Ya hay un directorio en esta ubicación, pero no contiene un repositorio.
+
+ The directory at the destination path is not empty.
Ya existe un repositorio en esta ubicación, pero no tiene un repositorio remoto con el nombre "origen".
diff --git a/src/GitHub.Resources/Resources.fr-FR.resx b/src/GitHub.Resources/Resources.fr-FR.resx
index b30b2784b1..9642a486c4 100644
--- a/src/GitHub.Resources/Resources.fr-FR.resx
+++ b/src/GitHub.Resources/Resources.fr-FR.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
L'URL cible est introuvable dans le dépôt actuel. Réessayez après une récupération (fetch).
-
- Un répertoire est déjà présent à cet emplacement, mais il ne contient pas de dépôt.
+
+ The directory at the destination path is not empty.
Un dépôt existe déjà à cet emplacement, mais il n'a pas de dépôt distant nommé « origin ».
diff --git a/src/GitHub.Resources/Resources.it-IT.resx b/src/GitHub.Resources/Resources.it-IT.resx
index c825f5bae4..493973019b 100644
--- a/src/GitHub.Resources/Resources.it-IT.resx
+++ b/src/GitHub.Resources/Resources.it-IT.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
Non è stato trovato alcun URL di destinazione nel repository corrente. Riprovare dopo aver eseguito il comando fetch.
-
- In questo percorso esiste già una directory che però non contiene un repository.
+
+ The directory at the destination path is not empty.
In questo percorso esiste già un repository che però non include un repository remoto denominato "origin".
diff --git a/src/GitHub.Resources/Resources.ja-JP.resx b/src/GitHub.Resources/Resources.ja-JP.resx
index a20cf8c660..f117b67c15 100644
--- a/src/GitHub.Resources/Resources.ja-JP.resx
+++ b/src/GitHub.Resources/Resources.ja-JP.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
現在のリポジトリにターゲット URL が見つかりませんでした。フェッチを実行した後、もう一度お試しください。
-
- この場所に既にディレクトリがありますが、リポジトリが含まれていません。
+
+ The directory at the destination path is not empty.
この場所にリポジトリが既に存在しますが、そのリポジトリには "origin" という名前のリモートがありません。
diff --git a/src/GitHub.Resources/Resources.ko-KR.resx b/src/GitHub.Resources/Resources.ko-KR.resx
index 6825c48f1e..b97c8af695 100644
--- a/src/GitHub.Resources/Resources.ko-KR.resx
+++ b/src/GitHub.Resources/Resources.ko-KR.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
현재 리포지토리에서 대상 URL을 찾을 수 없습니다. 페치를 수행한 후 다시 시도하세요.
-
- 이 위치에 이미 디렉터리가 있지만, 디렉터리에 리포지토리가 없습니다.
+
+ The directory at the destination path is not empty.
리포지토리가 이 위치에 이미 있지만, "origin"이라는 원격 항목을 포함하지 않습니다.
diff --git a/src/GitHub.Resources/Resources.pl-PL.resx b/src/GitHub.Resources/Resources.pl-PL.resx
index c8366cd109..7b019685b2 100644
--- a/src/GitHub.Resources/Resources.pl-PL.resx
+++ b/src/GitHub.Resources/Resources.pl-PL.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
Nie można odnaleźć docelowego adresu URL w bieżącym repozytorium. Spróbuj ponownie po zakończeniu pobierania.
-
- W tej lokalizacji istnieje już katalog, ale nie zawiera on repozytorium.
+
+ The directory at the destination path is not empty.
Repozytorium już istnieje w tej lokalizacji, ale nie ma zdalnego repozytorium o nazwie „origin”.
diff --git a/src/GitHub.Resources/Resources.pt-BR.resx b/src/GitHub.Resources/Resources.pt-BR.resx
index f15054ec12..9acb25c9db 100644
--- a/src/GitHub.Resources/Resources.pt-BR.resx
+++ b/src/GitHub.Resources/Resources.pt-BR.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
Não foi possível encontrar a URL de destino no repositório atual. Tente novamente depois de efetuar um fetch.
-
- Já existe um diretório neste local, mas ele não contém um repositório.
+
+ The directory at the destination path is not empty.
Já existe um repositório neste local, mas ele não tem um repositório remoto com o nome "origem".
diff --git a/src/GitHub.Resources/Resources.resx b/src/GitHub.Resources/Resources.resx
index c9cde7d183..acc5d80621 100644
--- a/src/GitHub.Resources/Resources.resx
+++ b/src/GitHub.Resources/Resources.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
Couldn't find target URL in current repository. Try again after doing a fetch.
-
- There is already a directory at this location, but it doesn't contain a repository.
+
+ The directory at the destination path is not empty.
A repository already exists at this location, but it doesn't have a remote named "origin".
@@ -878,4 +878,4 @@ https://git-scm.com/download/win
Contributed to repositories
-
\ No newline at end of file
+
diff --git a/src/GitHub.Resources/Resources.ru-RU.resx b/src/GitHub.Resources/Resources.ru-RU.resx
index 0be42538bd..3a6e991a9c 100644
--- a/src/GitHub.Resources/Resources.ru-RU.resx
+++ b/src/GitHub.Resources/Resources.ru-RU.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
Не удалось найти целевой URL-адрес в текущем репозитории. Выполните принесение и повторите попытку.
-
- В этом расположении уже существует каталог, но он не содержит репозиторий.
+
+ The directory at the destination path is not empty.
В этом расположении уже существует репозиторий, но у него отсутствует удаленный репозиторий с именем "origin".
diff --git a/src/GitHub.Resources/Resources.tr-TR.resx b/src/GitHub.Resources/Resources.tr-TR.resx
index d9b282c804..9c6a2e687e 100644
--- a/src/GitHub.Resources/Resources.tr-TR.resx
+++ b/src/GitHub.Resources/Resources.tr-TR.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
Hedef URL geçerli depoda bulunamadı. Getirme işlemi gerçekleştirdikten sonra yeniden deneyin.
-
- Bu konumda zaten bir dizin var ancak bir depo içermiyor.
+
+ The directory at the destination path is not empty.
Bu konumda bir depo zaten var ancak bu deponun "origin" adlı bir uzak deposu yok.
diff --git a/src/GitHub.Resources/Resources.zh-CN.resx b/src/GitHub.Resources/Resources.zh-CN.resx
index 398d8b0478..057bc9bcf4 100644
--- a/src/GitHub.Resources/Resources.zh-CN.resx
+++ b/src/GitHub.Resources/Resources.zh-CN.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
当前存储库中找不到目标 URL。请执行提取后重试。
-
- 在此位置已存在一个目录,但它不包含存储库。
+
+ The directory at the destination path is not empty.
此位置已存在一个存储库,但该存储库不具有名为 "origin" 的远程库。
diff --git a/src/GitHub.Resources/Resources.zh-TW.resx b/src/GitHub.Resources/Resources.zh-TW.resx
index 64db419743..3ef86dfdd2 100644
--- a/src/GitHub.Resources/Resources.zh-TW.resx
+++ b/src/GitHub.Resources/Resources.zh-TW.resx
@@ -809,8 +809,8 @@ https://git-scm.com/download/win
在目前存放庫中找不到目標 URL。請在執行擷取後再試一次。
-
- 此位置已經有一個目錄,但它並未包含存放庫。
+
+ The directory at the destination path is not empty.
存放庫已存在於此位置,但其不具有名為 "origin" 的遠端存放庫。
diff --git a/test/GitHub.App.UnitTests/Services/RepositoryCloneServiceTests.cs b/test/GitHub.App.UnitTests/Services/RepositoryCloneServiceTests.cs
index 28ca979afe..dc77d5dd1f 100644
--- a/test/GitHub.App.UnitTests/Services/RepositoryCloneServiceTests.cs
+++ b/test/GitHub.App.UnitTests/Services/RepositoryCloneServiceTests.cs
@@ -121,9 +121,11 @@ await usageTracker.Received(numberOfCalls).IncrementCounter(
((MemberExpression)x.Body).Member.Name == counterName));
}
- [TestCase("https://github.com/failing/url", @"c:\dev\bar")]
- public async Task CleansDirectoryOnCloneFailed(string cloneUrl, string clonePath)
+ [Test]
+ public async Task CleansDirectoryOnCloneFailed()
{
+ var cloneUrl = "https://github.com/failing/url";
+ var clonePath = @"c:\dev\bar";
var operatingSystem = Substitute.For();
var vsGitServices = Substitute.For();
vsGitServices.Clone(cloneUrl, clonePath, true).Returns(x => { throw new Exception(); });
@@ -136,6 +138,22 @@ public async Task CleansDirectoryOnCloneFailed(string cloneUrl, string clonePath
await vsGitServices.Received().Clone(cloneUrl, clonePath, true);
}
+ [Test]
+ public async Task CloneIntoEmptyDirectory()
+ {
+ var cloneUrl = "https://github.com/foo/bar";
+ var clonePath = @"c:\empty\directory";
+ var operatingSystem = Substitute.For();
+ operatingSystem.Directory.DirectoryExists(clonePath).Returns(true);
+ operatingSystem.Directory.IsEmpty(clonePath).Returns(true);
+ var vsGitServices = Substitute.For();
+ var cloneService = CreateRepositoryCloneService(operatingSystem: operatingSystem, vsGitServices: vsGitServices);
+ await cloneService.CloneRepository(cloneUrl, clonePath);
+
+ operatingSystem.Directory.DidNotReceive().CreateDirectory(clonePath);
+ await vsGitServices.Received().Clone(cloneUrl, clonePath, true);
+ }
+
static RepositoryCloneService CreateRepositoryCloneService(IOperatingSystem operatingSystem = null,
IVSGitServices vsGitServices = null, IUsageTracker usageTracker = null,
ITeamExplorerServices teamExplorerServices = null, IGitHubServiceProvider serviceProvider = null)
diff --git a/test/GitHub.App.UnitTests/ViewModels/Dialog/Clone/RepositoryCloneViewModelTests.cs b/test/GitHub.App.UnitTests/ViewModels/Dialog/Clone/RepositoryCloneViewModelTests.cs
index 8d3b26f210..4ee276d691 100644
--- a/test/GitHub.App.UnitTests/ViewModels/Dialog/Clone/RepositoryCloneViewModelTests.cs
+++ b/test/GitHub.App.UnitTests/ViewModels/Dialog/Clone/RepositoryCloneViewModelTests.cs
@@ -17,6 +17,7 @@ namespace GitHub.App.UnitTests.ViewModels.Dialog.Clone
{
public class RepositoryCloneViewModelTests
{
+ const string directoryEmpty = "d:\\empty\\directory";
const string directoryExists = "d:\\exists\\directory";
const string fileExists = "d:\\exists\\file";
const string defaultPath = "d:\\default\\path";
@@ -224,7 +225,7 @@ public void PathWarning_Is_Set_For_Directory_With_No_Repository()
SetRepository(target.GitHubTab, CreateRepositoryModel(owner, repo));
target.Path = directoryExists;
- Assert.That(target.PathWarning, Is.EqualTo(Resources.CantFindARepositoryAtLocalPath));
+ Assert.That(target.PathWarning, Is.EqualTo(Resources.DirectoryAtDestinationNotEmpty));
}
[Test]
@@ -244,6 +245,16 @@ public void PathWarning_Is_Set_For_Existing_Repository_At_Destination_With_Diffe
Assert.That(target.PathWarning, Is.EqualTo(expectMessage));
}
+ [Test]
+ public void PathWarning_Is_Not_Set_When_EmptyDirectoryExists_Selected()
+ {
+ var target = CreateTarget();
+
+ target.Path = directoryEmpty;
+
+ Assert.That(target.PathWarning, Is.Null);
+ }
+
[Test]
public void Repository_Name_Replaces_Last_Part_Of_Non_Base_Path()
{
@@ -342,6 +353,21 @@ public async Task Open_Is_Enabled_When_Path_DirectoryExists()
Assert.That(target.Open.CanExecute(null), Is.True);
}
+ [Test]
+ public async Task Clone_Is_Enabled_When_Path_EmptyDirectoryExists()
+ {
+ var target = CreateTarget();
+
+ await target.InitializeAsync(null);
+
+ SetRepository(target.GitHubTab, CreateRepositoryModel());
+ Assert.That(target.Clone.CanExecute(null), Is.True);
+
+ target.Path = directoryEmpty;
+
+ Assert.That(target.Clone.CanExecute(null), Is.True);
+ }
+
static void SetRepository(IRepositoryCloneTabViewModel vm, RepositoryModel repository)
{
vm.Repository.Returns(repository);
@@ -385,6 +411,8 @@ static IRepositoryCloneService CreateRepositoryCloneService(string defaultCloneP
var result = Substitute.For();
result.DefaultClonePath.Returns(defaultClonePath);
result.DestinationDirectoryExists(directoryExists).Returns(true);
+ result.DestinationDirectoryExists(directoryEmpty).Returns(true);
+ result.DestinationDirectoryEmpty(directoryEmpty).Returns(true);
result.DestinationFileExists(directoryExists).Returns(false);
result.DestinationDirectoryExists(fileExists).Returns(false);
result.DestinationFileExists(fileExists).Returns(true);