Skip to content

Commit 75c2362

Browse files
committed
Handle exception if an installation has already been started
1 parent 06824ce commit 75c2362

File tree

1 file changed

+43
-6
lines changed

1 file changed

+43
-6
lines changed

src/ExtensionManager/Installation/ExtensionInstaller.cs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
34
using System.IO;
45
using System.Linq;
56
using System.Net.Http;
@@ -43,13 +44,16 @@ public async Task InstallAsync(IReadOnlyCollection<IVSExtension> extensions, boo
4344

4445
try
4546
{
46-
IReadOnlyList<ExtensionDownloader> downloaders;
47+
IReadOnlyList<ExtensionDownloader>? downloaders;
4748

4849
using (var httpMessageHandler = new HttpClientHandler())
4950
{
5051
httpMessageHandler.MaxConnectionsPerServer = 100;
5152

52-
downloaders = CreateDownloaders(httpMessageHandler, extensions, uiProgress, cancellationToken);
53+
var optDownloaders = await CreateDownloadersAsync(httpMessageHandler, extensions, uiProgress, cancellationToken);
54+
55+
if (!optDownloaders.HasValue(out downloaders))
56+
return;
5357

5458
if (downloaders.Count == 0)
5559
return;
@@ -71,12 +75,15 @@ public async Task InstallAsync(IReadOnlyCollection<IVSExtension> extensions, boo
7175
}
7276
}
7377

74-
private IReadOnlyList<ExtensionDownloader> CreateDownloaders(HttpMessageHandler httpMessageHandler, IReadOnlyCollection<IVSExtension> extensions, IProgress<ProgressStep<InstallStep>> uiProgress, CancellationToken cancellationToken)
78+
private async Task<Opt<IReadOnlyList<ExtensionDownloader>>> CreateDownloadersAsync(HttpMessageHandler httpMessageHandler, IReadOnlyCollection<IVSExtension> extensions, IProgress<ProgressStep<InstallStep>> uiProgress, CancellationToken cancellationToken)
7579
{
7680
var progress = new DownloadProgres(uiProgress, _statusBar, extensions.Count);
7781
var entries = new List<ExtensionDownloader>();
7882

79-
var targetFolder = PrepareDownloadTargetFolder(cancellationToken);
83+
var optTargetFolder = await PrepareDownloadTargetFolderAsync(cancellationToken);
84+
85+
if (!optTargetFolder.HasValue(out var targetFolder))
86+
return default;
8087

8188
foreach (var extension in extensions)
8289
{
@@ -95,14 +102,27 @@ private IReadOnlyList<ExtensionDownloader> CreateDownloaders(HttpMessageHandler
95102

96103
return entries;
97104
}
98-
private static string PrepareDownloadTargetFolder(CancellationToken cancellationToken)
105+
private async Task<Opt<string>> PrepareDownloadTargetFolderAsync(CancellationToken cancellationToken)
99106
{
100107
cancellationToken.ThrowIfCancellationRequested();
101108

102109
var tempFolder = Path.Combine(Path.GetTempPath(), nameof(ExtensionManager));
103110

104111
if (Directory.Exists(tempFolder))
105-
Directory.Delete(tempFolder, true);
112+
{
113+
try
114+
{
115+
Directory.Delete(tempFolder, true);
116+
}
117+
catch (IOException ex) when ((ex.HResult & 0xFFFF) == 32)
118+
{
119+
await _messageBox.ShowErrorAsync(
120+
"The file is already in use.",
121+
"Has an installation already started and not yet completed?");
122+
123+
return default;
124+
}
125+
}
106126

107127
Directory.CreateDirectory(tempFolder);
108128

@@ -169,4 +189,21 @@ private async Task RunInstallationAsync(IReadOnlyCollection<ExtensionDownloader>
169189
await _statusBar.ShowMessageAsync($"Extensions downloaded. Starting VSIX Installer ...");
170190
await _extensions.StartInstallerAsync(vsixFiles, installSystemWide);
171191
}
192+
193+
private readonly struct Opt<T>
194+
where T : class
195+
{
196+
public static implicit operator Opt<T>(T value) => new(value);
197+
198+
private readonly T _value;
199+
200+
private Opt(T value)
201+
=> _value = value;
202+
203+
public bool HasValue([MaybeNullWhen(false)] out T value)
204+
{
205+
value = _value;
206+
return value is not null;
207+
}
208+
}
172209
}

0 commit comments

Comments
 (0)