-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix Repair-WinGetPackageManager cmdlet by retrieving dependencies from GitHub assets #4923
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -72,6 +72,9 @@ internal class AppxModuleHelper | |||||
private const string DependenciesZipName = "DesktopAppInstaller_Dependencies.zip"; | ||||||
private const string License = "License1.xml"; | ||||||
|
||||||
// Format of a dependency package such as 'x64\Microsoft.VCLibs.140.00.UWPDesktop_14.0.33728.0_x64.appx' | ||||||
private const string ExtractedDependencyPath = "{0}\\{1}_{2}_{3}.appx"; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
nit: I guess this isn't really that important, it just seems to suggest that the directory architecture and the file name architecture don't need to match. If taken, update the format calls to remove the second architecture. |
||||||
|
||||||
// Dependencies | ||||||
// VCLibs | ||||||
private const string VCLibsUWPDesktop = "Microsoft.VCLibs.140.00.UWPDesktop"; | ||||||
|
@@ -81,11 +84,7 @@ internal class AppxModuleHelper | |||||
private const string VCLibsUWPDesktopArm = "https://aka.ms/Microsoft.VCLibs.arm.14.00.Desktop.appx"; | ||||||
private const string VCLibsUWPDesktopArm64 = "https://aka.ms/Microsoft.VCLibs.arm64.14.00.Desktop.appx"; | ||||||
|
||||||
private const string AppxPackageTemplate = "{0}_{1}_{2}__8wekyb3d8bbwe.appx"; | ||||||
|
||||||
// Xaml | ||||||
private const string XamlPackageName = "Microsoft.UI.Xaml.2.8"; | ||||||
|
||||||
private const string XamlPackage28 = "Microsoft.UI.Xaml.2.8"; | ||||||
private const string XamlReleaseTag286 = "v2.8.6"; | ||||||
private const string MinimumWinGetReleaseTagForXaml28 = "v1.7.10514"; | ||||||
|
@@ -330,7 +329,7 @@ private async Task AddAppInstallerBundleAsync(string releaseTag, bool downgrade, | |||||
|
||||||
private async Task InstallDependenciesAsync(string releaseTag) | ||||||
{ | ||||||
bool result = await this.TryInstallDependenciesFromGitHubArchive(releaseTag); | ||||||
bool result = await this.InstallDependenciesFromGitHubArchive(releaseTag); | ||||||
|
||||||
if (!result) | ||||||
{ | ||||||
|
@@ -351,10 +350,10 @@ private Dictionary<string, string> GetDependenciesByArch(PackageDependency depen | |||||
Dictionary<string, string> appxPackages = new Dictionary<string, string>(); | ||||||
var arch = RuntimeInformation.OSArchitecture; | ||||||
|
||||||
string appxPackageX64 = string.Format(AppxPackageTemplate, dependencies.Name, dependencies.Version, "x64"); | ||||||
string appxPackageX86 = string.Format(AppxPackageTemplate, dependencies.Name, dependencies.Version, "x86"); | ||||||
string appxPackageArm = string.Format(AppxPackageTemplate, dependencies.Name, dependencies.Version, "arm"); | ||||||
string appxPackageArm64 = string.Format(AppxPackageTemplate, dependencies.Name, dependencies.Version, "arm64"); | ||||||
string appxPackageX64 = string.Format(ExtractedDependencyPath, "x64", dependencies.Name, dependencies.Version, "x64"); | ||||||
string appxPackageX86 = string.Format(ExtractedDependencyPath, "x86", dependencies.Name, dependencies.Version, "x86"); | ||||||
string appxPackageArm = string.Format(ExtractedDependencyPath, "arm", dependencies.Name, dependencies.Version, "arm"); | ||||||
string appxPackageArm64 = string.Format(ExtractedDependencyPath, "arm", dependencies.Name, dependencies.Version, "arm64"); | ||||||
|
||||||
if (arch == Architecture.X64) | ||||||
{ | ||||||
|
@@ -389,8 +388,6 @@ private void FindMissingDependencies(Dictionary<string, string> dependencies, st | |||||
{ Name, packageName }, | ||||||
}); | ||||||
|
||||||
// See if the minimum (or greater) version is installed. | ||||||
// TODO: Pull the minimum version from the target package | ||||||
Version minimumVersion = new Version(requiredVersion); | ||||||
|
||||||
if (result != null && | ||||||
|
@@ -452,79 +449,78 @@ private async Task InstallVCLibsDependenciesFromUriAsync() | |||||
} | ||||||
} | ||||||
|
||||||
private async Task<bool> TryInstallDependenciesFromGitHubArchive(string releaseTag) | ||||||
// Returns a boolean value indicating whether dependencies were successfully installed from the GitHub release assets. | ||||||
private async Task<bool> InstallDependenciesFromGitHubArchive(string releaseTag) | ||||||
{ | ||||||
try | ||||||
var githubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli); | ||||||
var release = await githubClient.GetReleaseAsync(releaseTag); | ||||||
|
||||||
ReleaseAsset? dependenciesJsonAsset = release.TryGetAsset(DependenciesJsonName); | ||||||
if (dependenciesJsonAsset is null) | ||||||
{ | ||||||
var githubClient = new GitHubClient(RepositoryOwner.Microsoft, RepositoryName.WinGetCli); | ||||||
var release = await githubClient.GetReleaseAsync(releaseTag); | ||||||
return false; | ||||||
} | ||||||
|
||||||
using var dependenciesJsonFile = new TempFile(); | ||||||
await this.httpClientHelper.DownloadUrlWithProgressAsync(dependenciesJsonAsset.BrowserDownloadUrl, dependenciesJsonFile.FullPath, this.pwshCmdlet); | ||||||
|
||||||
var dependenciesJsonAsset = release.GetAsset(DependenciesJsonName); | ||||||
var dependenciesZipAsset = release.GetAsset(DependenciesZipName); | ||||||
using StreamReader r = new StreamReader(dependenciesJsonFile.FullPath); | ||||||
string json = r.ReadToEnd(); | ||||||
WingetDependencies? wingetDependencies = JsonConvert.DeserializeObject<WingetDependencies>(json); | ||||||
|
||||||
using var dependenciesJsonFile = new TempFile(); | ||||||
await this.httpClientHelper.DownloadUrlWithProgressAsync(dependenciesJsonAsset.BrowserDownloadUrl, dependenciesJsonFile.FullPath, this.pwshCmdlet); | ||||||
if (wingetDependencies is null) | ||||||
{ | ||||||
this.pwshCmdlet.Write(StreamType.Verbose, $"Failed to deserialize dependencies json file."); | ||||||
return false; | ||||||
} | ||||||
|
||||||
using StreamReader r = new StreamReader(dependenciesJsonFile.FullPath); | ||||||
string json = r.ReadToEnd(); | ||||||
WingetDependencies? wingetDependencies = JsonConvert.DeserializeObject<WingetDependencies>(json); | ||||||
List<string> missingDependencies = new List<string>(); | ||||||
foreach (var dependency in wingetDependencies.Dependencies) | ||||||
{ | ||||||
Dictionary<string, string> dependenciesByArch = this.GetDependenciesByArch(dependency); | ||||||
this.FindMissingDependencies(dependenciesByArch, dependency.Name, dependency.Version); | ||||||
|
||||||
if (wingetDependencies is null) | ||||||
foreach (var pair in dependenciesByArch) | ||||||
{ | ||||||
this.pwshCmdlet.Write(StreamType.Verbose, $"Failed to deserialize dependencies json file."); | ||||||
return false; | ||||||
missingDependencies.Add(pair.Value); | ||||||
} | ||||||
} | ||||||
|
||||||
List<string> missingDependencies = new List<string>(); | ||||||
foreach (var dependency in wingetDependencies.Dependencies) | ||||||
{ | ||||||
Dictionary<string, string> dependenciesByArch = this.GetDependenciesByArch(dependency); | ||||||
this.FindMissingDependencies(dependenciesByArch, dependency.Name, dependency.Version); | ||||||
if (missingDependencies.Count != 0) | ||||||
{ | ||||||
using var dependenciesZipFile = new TempFile(); | ||||||
using var extractedDirectory = new TempDirectory(); | ||||||
|
||||||
foreach (var pair in dependenciesByArch) | ||||||
{ | ||||||
missingDependencies.Add(pair.Value); | ||||||
} | ||||||
ReleaseAsset? dependenciesZipAsset = release.TryGetAsset(DependenciesZipName); | ||||||
if (dependenciesZipAsset is null) | ||||||
{ | ||||||
this.pwshCmdlet.Write(StreamType.Verbose, $"Dependencies zip asset not found on GitHub asset."); | ||||||
return false; | ||||||
} | ||||||
|
||||||
if (missingDependencies.Count != 0) | ||||||
{ | ||||||
using var dependenciesZipFile = new TempFile(); | ||||||
using var extractedDirectory = new TempDirectory(); | ||||||
await this.httpClientHelper.DownloadUrlWithProgressAsync(dependenciesZipAsset.BrowserDownloadUrl, dependenciesZipFile.FullPath, this.pwshCmdlet); | ||||||
ZipFile.ExtractToDirectory(dependenciesZipFile.FullPath, extractedDirectory.FullDirectoryPath); | ||||||
await this.httpClientHelper.DownloadUrlWithProgressAsync(dependenciesZipAsset.BrowserDownloadUrl, dependenciesZipFile.FullPath, this.pwshCmdlet); | ||||||
ZipFile.ExtractToDirectory(dependenciesZipFile.FullPath, extractedDirectory.FullDirectoryPath); | ||||||
|
||||||
foreach (var entry in missingDependencies) | ||||||
foreach (var entry in missingDependencies) | ||||||
{ | ||||||
string fullPath = System.IO.Path.Combine(extractedDirectory.FullDirectoryPath, DependenciesAssetName, entry); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see how this directory ends up in the path, unless you are expecting the archive to have every dependency under this one directory. I also don't know why we need to increase the length of the path just to put this name in. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I made a mistake with how I created the test zip. I will fix this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed this extra directory as its not needed anymore. Basically, I compressed the folder containing the arch folders. I had to instead select all the arch folders and compress from there. |
||||||
if (!File.Exists(fullPath)) | ||||||
{ | ||||||
string fullPath = entry; | ||||||
if (!File.Exists(fullPath)) | ||||||
{ | ||||||
this.pwshCmdlet.Write(StreamType.Verbose, $"Package dependency not found in archive: {fullPath}"); | ||||||
return false; | ||||||
} | ||||||
|
||||||
_ = this.ExecuteAppxCmdlet( | ||||||
AddAppxPackage, | ||||||
new Dictionary<string, object> | ||||||
{ | ||||||
{ Path, fullPath }, | ||||||
{ ErrorAction, Stop }, | ||||||
}); | ||||||
this.pwshCmdlet.Write(StreamType.Verbose, $"Package dependency not found in archive: {fullPath}"); | ||||||
return false; | ||||||
} | ||||||
} | ||||||
|
||||||
return true; | ||||||
} | ||||||
catch (WinGetRepairException e) | ||||||
{ | ||||||
this.pwshCmdlet.Write(StreamType.Verbose, $"Dependency assets not found in GitHub release."); | ||||||
} | ||||||
catch (Exception e) | ||||||
{ | ||||||
this.pwshCmdlet.Write(StreamType.Verbose, $"Failed to install dependencies from GitHub release. {e.ToString()}"); | ||||||
_ = this.ExecuteAppxCmdlet( | ||||||
AddAppxPackage, | ||||||
new Dictionary<string, object> | ||||||
{ | ||||||
{ Path, fullPath }, | ||||||
{ ErrorAction, Stop }, | ||||||
}); | ||||||
} | ||||||
} | ||||||
|
||||||
return false; | ||||||
return true; | ||||||
} | ||||||
|
||||||
private Dictionary<string, string> GetVCLibsDependencies() | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did you remove this output?