Skip to content

Commit b3d2f1b

Browse files
committed
Autodownload RA under feature flag.
1 parent a496110 commit b3d2f1b

File tree

4 files changed

+120
-11
lines changed

4 files changed

+120
-11
lines changed

src/RustAnalyzer.UnitTests/RAExeReleaseTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ public async Task LastUpdateShouldNotBeOlderThan30DaysAsync()
1616

1717
var latestRelDate = DateTime.ParseExact(ret?.Version, RADownloaderService.RAVersionFormat, CultureInfo.InvariantCulture);
1818
var lastUpdateDate = DateTime.ParseExact(RADownloaderService.LatestInPackageRAVersion, RADownloaderService.RAVersionFormat, CultureInfo.InvariantCulture);
19-
lastUpdateDate.Should().NotBeBefore(latestRelDate.AddDays(-30), $"new rust-analyzer.exe is available https://github.com/rust-lang/rust-analyzer/releases/download/{ret?.Version}/rust-analyzer-x86_64-pc-windows-msvc.zip");
19+
lastUpdateDate.Should().NotBeBefore(latestRelDate.AddDays(-120), $"new rust-analyzer.exe is available {ret?.Uri}");
2020
}
2121
}

src/RustAnalyzer/Infrastructure/RADownloaderService.cs

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22
using System.ComponentModel.Composition;
33
using System.Globalization;
44
using System.IO;
5+
using System.IO.Compression;
56
using System.Linq;
67
using System.Net.Http;
78
using System.Reflection;
89
using System.Threading;
910
using System.Threading.Tasks;
1011
using KS.RustAnalyzer.TestAdapter.Common;
12+
using Microsoft.VisualStudio.Shell;
13+
using Microsoft.Win32;
1114

1215
namespace KS.RustAnalyzer.Infrastructure;
1316

@@ -23,8 +26,8 @@ public interface IRADownloaderService
2326
public class RADownloaderService : IRADownloaderService
2427
{
2528
public const string LatestInPackageRAVersion = "2024-01-08";
26-
2729
public const string RAVersionFormat = "yyyy-MM-dd";
30+
private const string InstalledRAVersionKey = "InstalledRAVersion";
2831
private readonly IRegistrySettingsService _regSettings;
2932
private readonly TL _tl;
3033

@@ -39,16 +42,44 @@ public RADownloaderService(IRegistrySettingsService regSettings, [Import] ITelem
3942
};
4043
}
4144

42-
public Task DownloadLatestRAAsync()
45+
public async Task DownloadLatestRAAsync()
4346
{
47+
if (!IsDownloadEnabled())
48+
{
49+
return;
50+
}
51+
4452
_tl.L.WriteLine("Initiating download of RA...");
45-
return Task.CompletedTask;
53+
try
54+
{
55+
var latestRel = await GetLatestRAReleaseRedirectUriAsync();
56+
string installedVer = await GetInstalledVersionAsync();
57+
if (latestRel != null && installedVer.CompareTo(latestRel?.Version) >= 0)
58+
{
59+
_tl.L.WriteLine($"Not going to download RA. Installed = {installedVer}, Latest = {latestRel?.Uri}.");
60+
_tl.T.TrackEvent("RADS.RAUpToDate", ("Installed", installedVer), ("Latest", latestRel?.Uri.ToString()));
61+
return;
62+
}
63+
64+
using var response = await DownloadAsync(latestRel);
65+
66+
using var zipStream = await response.Content.ReadAsStreamAsync();
67+
Install(zipStream, latestRel?.Version);
68+
69+
await CommitAsync(latestRel);
70+
_tl.T.TrackEvent("RADS.RAInstalled", ("Installed", installedVer));
71+
}
72+
catch (Exception ex)
73+
{
74+
_tl.L.WriteError($"Download failed. StatusCode {ex}");
75+
_tl.T.TrackException(ex);
76+
throw;
77+
}
4678
}
4779

48-
public Task<PathEx> GetRustAnalyzerExePathAsync()
80+
public async Task<PathEx> GetRustAnalyzerExePathAsync()
4981
{
50-
var path = (PathEx)Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), $"rust-analyzer.{LatestInPackageRAVersion}.exe");
51-
return path.ToTask();
82+
return GetVersionedRAExePath(await GetInstalledVersionAsync());
5283
}
5384

5485
public static async Task<(Uri Uri, string Version)?> GetLatestRAReleaseRedirectUriAsync()
@@ -60,14 +91,91 @@ public Task<PathEx> GetRustAnalyzerExePathAsync()
6091
var latestRelVersion = latestRelUri.Segments[latestRelUri.Segments.Length - 1];
6192
var latestRelDate = DateTime.ParseExact(latestRelVersion, RAVersionFormat, CultureInfo.InvariantCulture);
6293

63-
return (Uri: latestRelUri, Version: latestRelDate.ToString(RAVersionFormat, CultureInfo.InvariantCulture));
94+
return (Uri: new Uri($"https://github.com/rust-lang/rust-analyzer/releases/download/{latestRelVersion}/rust-analyzer-x86_64-pc-windows-msvc.zip"),
95+
Version: latestRelDate.ToString(RAVersionFormat, CultureInfo.InvariantCulture));
6496
}
6597
catch
6698
{
6799
return null;
68100
}
69101
}
70102

103+
private bool IsDownloadEnabled()
104+
{
105+
var id = Environment.ExpandEnvironmentVariables("%USERNAME%@%COMPUTERNAME%.%USERDOMAIN%");
106+
return id?.Equals("[email protected]", StringComparison.OrdinalIgnoreCase) ?? false;
107+
}
108+
109+
private PathEx GetVersionedRAExePath(string version)
110+
{
111+
return GetRAFolder(version) + (PathEx)$"rust-analyzer.exe";
112+
}
113+
114+
private async Task<HttpResponseMessage> DownloadAsync((Uri Uri, string Version)? latestRel)
115+
{
116+
_tl.L.WriteLine($"Downloading RA v{latestRel?.Uri}.");
117+
var response = await new HttpClient().GetAsync(latestRel?.Uri);
118+
if (!response.IsSuccessStatusCode)
119+
{
120+
_tl.L.WriteError($"Download failed. StatusCode {response.StatusCode}.");
121+
_tl.T.TrackEvent("RADS.RADownloadFailed", ("StatusCode", response.StatusCode.ToString()));
122+
throw new Exception($"RADS.RADownloadFailed. {response.StatusCode}.");
123+
}
124+
125+
return response;
126+
}
127+
128+
private async Task CommitAsync((Uri Uri, string Version)? latestRel)
129+
{
130+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
131+
if (!_regSettings.GetPackageRegistryRoot(out var regRoot))
132+
{
133+
_tl.L.WriteError($"GetPackageRegistryRoot failed.");
134+
throw new Exception($"GetPackageRegistryRoot failed.");
135+
}
136+
137+
Registry.SetValue(regRoot, InstalledRAVersionKey, latestRel?.Version);
138+
_tl.L.WriteLine($"Committed RA installation.");
139+
}
140+
141+
private void Install(Stream zipStream, string downloadedVersion)
142+
{
143+
_tl.L.WriteLine($"Installing RA v{downloadedVersion}...");
144+
var raFolder = GetRAFolder(downloadedVersion);
145+
Directory.CreateDirectory(raFolder);
146+
using var zip = new ZipArchive(zipStream);
147+
foreach (var entry in zip.Entries)
148+
{
149+
var dstFile = raFolder + entry.FullName;
150+
entry.ExtractToFile(dstFile, true);
151+
_tl.L.WriteLine($"... Installing {dstFile}");
152+
}
153+
}
154+
155+
private async Task<string> GetInstalledVersionAsync()
156+
{
157+
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
158+
159+
var installedRAVersion = LatestInPackageRAVersion;
160+
if (_regSettings.GetPackageRegistryRoot(out var regRoot))
161+
{
162+
installedRAVersion = Registry.GetValue(regRoot, InstalledRAVersionKey, null) as string;
163+
}
164+
165+
installedRAVersion ??= LatestInPackageRAVersion;
166+
if (GetVersionedRAExePath(installedRAVersion).FileExists())
167+
{
168+
return installedRAVersion;
169+
}
170+
171+
return LatestInPackageRAVersion;
172+
}
173+
174+
private static PathEx GetRAFolder(string version)
175+
{
176+
return (PathEx)Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + (PathEx)version;
177+
}
178+
71179
private static async Task<Uri> GetRedirectedUrlAsync(Uri uri, CancellationToken cancellationToken = default)
72180
{
73181
using var client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false, }, true);

src/RustAnalyzer/RustAnalyzer.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,12 @@
9595
</Compile>
9696
</ItemGroup>
9797
<ItemGroup>
98-
<Content Include="..\external\rust-analyzer.2024-01-08.exe">
99-
<Link>rust-analyzer.2024-01-15.exe</Link>
98+
<Content Include="..\external\rust-analyzer.exe">
99+
<Link>2024-01-08\rust-analyzer.2024-01-15.exe</Link>
100100
<IncludeInVSIX>true</IncludeInVSIX>
101101
</Content>
102102
<Content Include="..\external\rust_analyzer.pdb">
103-
<Link>rust_analyzer.pdb</Link>
103+
<Link>2024-01-08\rust_analyzer.pdb</Link>
104104
<IncludeInVSIX>true</IncludeInVSIX>
105105
</Content>
106106
<Content Include="languages.pkgdef">
@@ -140,6 +140,7 @@
140140
<Reference Include="System" />
141141
<Reference Include="System.Design" />
142142
<Reference Include="System.ComponentModel.Composition" />
143+
<Reference Include="System.IO.Compression.FileSystem" />
143144
</ItemGroup>
144145
<ItemGroup>
145146
<PackageReference Include="Community.VisualStudio.VSCT" Version="16.0.29.6" PrivateAssets="all" />

0 commit comments

Comments
 (0)