-
Notifications
You must be signed in to change notification settings - Fork 1.6k
PowerShell Repair enhancements #5711
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
base: master
Are you sure you want to change the base?
Conversation
src/PowerShell/Help/Microsoft.WinGet.Client/Repair-WinGetPackageManager.md
Outdated
Show resolved
Hide resolved
src/PowerShell/Help/Microsoft.WinGet.Client/Repair-WinGetPackageManager.md
Outdated
Show resolved
Hide resolved
src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
Outdated
Show resolved
Hide resolved
src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
Outdated
Show resolved
Hide resolved
src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
Outdated
Show resolved
Hide resolved
| // WinGet Source | ||
| private const string WinGetSourceName = "Microsoft.Winget.Source"; | ||
| private const string WinGetSourceMsixName = "source2.msix"; | ||
| private const string WinGetSourceUrl = "https://cdn.winget.microsoft.com/cache/source2.msix"; |
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.
Is there a COM API for fetching source information? Since the winget source is a well-known source (can be disabled, but not removed), would it be a possible consideration to dynamically fetch the source URL through the API? That way, in the event a source3.msix ever becomes the default, this portion of the cmdlet would just work?
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.
I was able to find the CDN URL https://cdn.winget.microsoft.com/cache but not the source2.msix file as part of the COM API. @JohnMcPMS, is there a recommended/forward compatible method to obtain the source2.msix URL instead of hardcoding it in the powershell module? Or specifying it here is okay?
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.
It is an internal implementation detail, so there isn't a way to get the file name. I don't see why we need to specify it here twice though.
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.
Can we not have the file name twice? Use string concatenation or formatting or whatever to only have source2.msix the one time.
| return partPattern == partValue.ToString(); | ||
| } | ||
|
|
||
| private async Task<string> ResolveVersionAsync(string version, bool includePrerelease) |
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.
This function and its helpers should be members of Microsoft.WinGet.Client.Engine.Helpers.GitHubClient like GetLatestReleaseTagNameAsync is.
Also, it should have a heuristic looking for wildcards before invoking a bunch of web calls and shortcut return the input version if no wildcard is present.
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.
Good call, I’ve moved that logic into the helper class.
We’re only making a single GetAll() web request to resolve the version, which I think is sufficient.
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.
I fully disagree, don't make any web request when we don't need one.
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.
I think if you moved functionality for the matching to WinGetVersion, you could easily have something like:
if (!WinGetVersion.VersionHasWildcard(version))
{
return version;
}
| VersionPartMatch(minor, v.Version.Minor) && | ||
| VersionPartMatch(build, v.Version.Build) && | ||
| VersionPartMatch(revision, v.Version.Revision)) | ||
| .OrderBy(f => f.Version); |
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.
In the current GetLatestReleaseAsync, we assume that the releases are returned in a sorted order (latest firstest). If that is true and maintained by all of the LINQ queries, then a First should be sufficient and optimal.
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.
I don’t think “latest release” necessarily means “latest version,” since you could technically release version 1.0.3 before 1.2.9. Releases are probably sorted by their creation date, which makes sense for identifying the latest release. But for this algorithm, it’s key to make sure the version list is sorted semantically, not just by release date.
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.
Then we should update GetLatestReleaseAsync to match this understanding of semantics. It is definitely not intended to be latest in terms of calendar, but latest in terms of the highest version. Fortunately, these are the same sort order for release only listing. When pre-release is involved, they could become interleaved, as the latest calendar date might be a release with a lower version number than a pre-release from before.
The documentation for listing releases does not mention ANY ordering, so even assuming calendar is faulty.
I would suggest making GetAllReleasesAsync return a collection of some type containing both a WinGetVersion and the Release, sorted so that the highest version is first. This makes the existing "latest" function more correct and your new function more efficient as it can simply get the First object matching the predicate rather than examining all of them.
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.
This apparently is a bug right now, actually, since the latest Pre-Release is 1.12.240-preview, but using Repair-WinGetPackageManager -IncludePrerelease -Latest selects 1.11.510
Would be really nice to have this fixed
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.
I just faced the same issue tonight. I believe my winget was previously on 1.11.x but when running Repair-WinGetPackageManager -Force -IncludePrerelease -Verbose it wasn't getting the pre-release version. After stumbling upon what you wrote, I manually specified the latest pre-release version and passed it in alongside -Version and it finally worked.
src/PowerShell/Microsoft.WinGet.Client.Engine/Commands/WinGetPackageManagerCommand.cs
Outdated
Show resolved
Hide resolved
| // WinGet Source | ||
| private const string WinGetSourceName = "Microsoft.Winget.Source"; | ||
| private const string WinGetSourceMsixName = "source2.msix"; | ||
| private const string WinGetSourceUrl = "https://cdn.winget.microsoft.com/cache/source2.msix"; |
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.
It is an internal implementation detail, so there isn't a way to get the file name. I don't see why we need to specify it here twice though.
src/PowerShell/Microsoft.WinGet.Client.Engine/Helpers/AppxModuleHelper.cs
Outdated
Show resolved
Hide resolved
| /// <param name="includePrerelease">Include prerelease versions.</param> | ||
| /// <param name="result">The resulting version.</param> | ||
| /// <returns>True if a matching version was found.</returns> | ||
| private static bool TryGetLatestMatchingVersion(IEnumerable<WinGetVersion> versions, string pattern, bool includePrerelease, out WinGetVersion result) |
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.
| private static bool TryGetLatestMatchingVersion(IEnumerable<WinGetVersion> versions, string pattern, bool includePrerelease, out WinGetVersion result) | |
| private static bool TryGetLatestMatchingVersion(IEnumerable<WinGetVersion> versions, string pattern, bool includePrerelease, out WinGetVersion? result) |
Because you very clearly return a null in some cases. You can annotate with the appropriate attribute to mark it as not null when returning true.
Register AppInstaller when using
AddProvisionPackageAsyncwhich was not registering the package prior to this PR change.Added a "best effort" approach to programmatically attempt to downloading the source2.msix and install it.
Keeping this as-is since the code includes a descriptive message. In my repro, the issue occurred when App Installer was not installed, and the code attempted to invoke winget.exe to check if the application was present.
This is not addressed in this PR. It's unclear which constraints should be relaxed, as the current implementation already attempts to ensure the requested parameters are satisfied. The Force flag is currently used to trigger
ForceTargetApplicationShutdownduring package addition, which appears appropriate. I recommend opening a separate issue to propose and discuss the desired behavior.Added support for leading and trailing wildcard:
1.2.*,1.2*,1.*2.3Related issues:
-Versionfor `Repair-WinGetPackageManager #5704Microsoft Reviewers: Open in CodeFlow