8000 Allow cloning of repositories into empty directories by YuPeiHenry · Pull Request #2316 · github/VisualStudio · GitHub
[go: up one dir, main page]

Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Allow cloning of repositories into empty directories #2316

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions src/GitHub.App/Services/RepositoryCloneService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
{
Expand Down Expand Up @@ -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
{
Expand All @@ -232,6 +235,9 @@ public async Task CloneRepository(
/// <inheritdoc/>
public bool DestinationDirectoryExists(string path) => operatingSystem.Directory.DirectoryExists(path);

/// <inheritdoc/>
public bool DestinationDirectoryEmpty(string path) => operatingSystem.Directory.GetDirectory(path).IsEmpty;

/// <inheritdoc/>
public bool DestinationFileExists(string path) => operatingSystem.File.Exists(path);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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();
Expand All @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions src/GitHub.Exports.Reactive/Services/IRepositoryCloneService.cs 8000
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ Task CloneOrOpenRepository(
/// </returns>
bool DestinationDirectoryExists(string path);

/// <summary>
/// Checks whether the specified destination directory is empty.
/// </summary>
/// <param name="path">The destination path.</param>
/// <returns>
/// true if a directory is empty <paramref name="path"/>; otherwise false.
/// </returns>
bool DestinationDirectoryEmpty(string path);

/// <summary>
/// Checks whether the specified destination file already exists.
/// </summary>
Expand Down
18 changes: 9 additions & 9 deletions src/GitHub.Resources/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.cs-CZ.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>V aktuálním úložišti se nepodařilo najít cílovou adresu URL. Zkuste to znovu po načtení změn.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>V tomto umístění je už adresář, ale neobsahuje úložiště.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>Úložiště už v tomto umístění existuje, ale nemá vzdálené úložiště s názvem origin.</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.de-DE.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>Die Ziel-URL wurde im aktuellen Repository nicht gefunden. Versuchen Sie es nach einem Abrufvorgang (fetch) noch einmal.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>An diesem Speicherort liegt bereits ein Verzeichnis vor, aber es enthält kein Repository.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>An diesem Speicherort ist bereits ein Repository vorhanden, das aber kein Remoterepository namens "origin" aufweist.</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.es-ES.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>No se encontró la dirección URL de destino en el repositorio actual. Vuelva a intentarlo tras una recuperación de cambios.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>Ya hay un directorio en esta ubicación, pero no contiene un repositorio.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>Ya existe un repositorio en esta ubicación, pero no tiene un repositorio remoto con el nombre "origen".</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.fr-FR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>L'URL cible est introuvable dans le dépôt actuel. Réessayez après une récupération (fetch).</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>Un répertoire est déjà présent à cet emplacement, mais il ne contient pas de dépôt.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>Un dépôt existe déjà à cet emplacement, mais il n'a pas de dépôt distant nommé « origin ».</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.it-IT.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>Non è stato trovato alcun URL di destinazione nel repository corrente. Riprovare dopo aver eseguito il comando fetch.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>In questo percorso esiste già una directory che però non contiene un repository.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>In questo percorso esiste già un repository che però non include un repository remoto denominato "origin".</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.ja-JP.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>現在のリポジトリにターゲット URL が見つかりませんでした。フェッチを実行した後、もう一度お試しください。</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>この場所に既にディレクトリがありますが、リポジトリが含まれていません。</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>この場所にリポジトリが既に存在しますが、そのリポジトリには "origin" という名前のリモートがありません。</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.ko-KR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>현재 리포지토리에서 대상 URL을 찾을 수 없습니다. 페치를 수행한 후 다시 시도하세요.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>이 위치에 이미 디렉터리가 있지만, 디렉터리에 리포지토리가 없습니다.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>리포지토리가 이 위치에 이미 있지만, "origin"이라는 원격 항목을 포함하지 않습니다.</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.pl-PL.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>Nie można odnaleźć docelowego adresu URL w bieżącym repozytorium. Spróbuj ponownie po zakończeniu pobierania.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>W tej lokalizacji istnieje już katalog, ale nie zawiera on repozytorium.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>Repozytorium już istnieje w tej lokalizacji, ale nie ma zdalnego repozytorium o nazwie „origin”.</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.pt-BR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>Não foi possível encontrar a URL de destino no repositório atual. Tente novamente depois de efetuar um fetch.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>Já existe um diretório neste local, mas ele não contém um repositório.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>Já existe um repositório neste local, mas ele não tem um repositório remoto com o nome "origem".</value>
Expand Down
6 changes: 3 additions & 3 deletions src/GitHub.Resources/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>Couldn't find target URL in current repository. Try again after doing a fetch.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>There is already a directory at this location, but it doesn't contain a repository.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>A repository already exists at this location, but it doesn't have a remote named "origin".</value>
Expand Down Expand Up @@ -878,4 +878,4 @@ https://git-scm.com/download/win</value>
<data name="RepositorySelectContributedRepositories" xml:space="preserve">
<value>Contributed to repositories</value>
</data>
</root>
</root>
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.ru-RU.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>Не удалось найти целевой URL-адрес в текущем репозитории. Выполните принесение и повторите попытку.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>В этом расположении уже существует каталог, но он не содержит репозиторий.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>В этом расположении уже существует репозиторий, но у него отсутствует удаленный репозиторий с именем "origin".</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.tr-TR.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>Hedef URL geçerli depoda bulunamadı. Getirme işlemi gerçekleştirdikten sonra yeniden deneyin.</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>Bu konumda zaten bir dizin var ancak bir depo içermiyor.</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>Bu konumda bir depo zaten var ancak bu deponun "origin" adlı bir uzak deposu yok.</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.zh-CN.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>当前存储库中找不到目标 URL。请执行提取后重试。</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>在此位置已存在一个目录,但它不包含存储库。</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>此位置已存在一个存储库,但该存储库不具有名为 "origin" 的远程库。</value>
Expand Down
4 changes: 2 additions & 2 deletions src/GitHub.Resources/Resources.zh-TW.resx
Original file line number Diff line number Diff line change
Expand Up @@ -809,8 +809,8 @@ https://git-scm.com/download/win</value>
<data name="NoResolveSameOwnerMessage" xml:space="preserve">
<value>在目前存放庫中找不到目標 URL。請在執行擷取後再試一次。</value>
</data>
<data name="CantFindARepositoryAtLocalPath" xml:space="preserve">
<value>此位置已經有一個目錄,但它並未包含存放庫。</value>
<data name="DirectoryAtDestinationNotEmpty" xml:space="preserve">
<value>The directory at the destination path is not empty.</value>
</data>
<data name="LocalRepositoryDoesntHaveARemoteOrigin" xml:space="preserve">
<value>存放庫已存在於此位置,但其不具有名為 "origin" 的遠端存放庫。</value>
Expand Down
22 changes: 20 additions & 2 deletions test/GitHub.App.UnitTests/Services/RepositoryCloneServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IOperatingSystem>();
var vsGitServices = Substitute.For<IVSGitServices>();
vsGitServices.Clone(cloneUrl, clonePath, true).Returns(x => { throw new Exception(); });
Expand All @@ -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<IOperatingSystem>();
operatingSystem.Directory.DirectoryExists(clonePath).Returns(true);
operatingSystem.Directory.IsEmpty(clonePath).Returns(true);
var vsGitServices = Substitute.For<IVSGitServices>();
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)
Expand Down
Loading
0