11using System ;
22using System . Collections . Generic ;
3+ using System . Diagnostics . CodeAnalysis ;
34using System . IO ;
45using System . Linq ;
56using 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