-
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
Record Product Codes in pinning table #3167
Conversation
I think that it's acceptable to not create a new DB schema version. Like you said, it's still an experimental feature. That said, it is annoying to have to go in and manually delete a file, and I'm sure there will be a few issues opened about it and closed after we link back to this PR. @denelon may have a rough estimate of how many users are using the pin command? To make it a bit more seamless, perhaps it may be beneficial to add a check that the pinning table matches at least one of the valid schemas. If it doesn't match any known schema, delete it and create a new one. Or perhaps make a method to restore the table to match the schema using the SQLite The "delete" or "repair" functionality could potentially be useful in the future as the installed.db is leveraged more and as new functionality is added. |
Co-authored-by: Kaleb Luedtke <[email protected]>
# Conflicts: # src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw
I changed it to actually use a new schema version. The pinning index now uses v1.1, but it is not backwards compatible with v1.0. (Now that I'm typing it, I realize that it doesn't respect sem-ver...). If, when opening an existing index, we see that it has version 1.0, we delete it and create a new one with the new version. This would no longer require manual deletion of the index, but we're still dropping all existing pins. I could try to recover the pins, but I think it is better to re-add them to get the new fields I'm adding in this PR. |
I think dropping them all is fine since its experimental anyways. Thanks for at least removing the manual step!! |
{ | ||
pinType = m_pin->GetType(); | ||
// A gating pin behaves the same as no pin when the version fits the gated version | ||
if (!(pin.GetType() == Pinning::PinType::Gating && pin.GetGatedVersion().IsValidVersion(versionKey.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.
Maybe I missed something, is logic here basically same as logic in line 420 above?
The initial thought for pinning a specific installed version is to add a pin from installed source to the pinning table so the previous pinning table will not break. PackageId SourceId But if this approach works, it's ok too since this is still in experimental (and seems easier in implementation?) |
After talking offline with @yao-msft I realize that this change is breaking the basic use case of "I update this app outside of winget, so don't touch it" because once there is an update, the product code will change and the pin will no longer apply. The case I was thinking for this PR was the one we see with Windows SDK, where multiple installed packages match with the same available package, so we need to pin the specific installed version, which is done with the product code. Taking into account both cases makes it weird. For upgrades outside of winget, we have to pin just by package ID & source to be able to track across versions. But for packages where matching doesn't quite work or have multiple installed packages, we have to pin by product code. I'm thinking the solution will have to be guessing the intent at the time of adding a pin and either add it by ID or by product code. I like @yao-msft 's idea for the DB so we don't have to change the schema, so I'll change it to that. That way we don't have to deal with deleting old DBs. It also makes sense because for specific installed packages the source doesn't matter; there could be multiple sources for it but the moment one of them updates the package, the pin stops applying to all of them. |
I've updated the PR to follow the schema suggested by @yao-msft for representing the pins in the DB. Given how different it all is I could probably have made a new PR but I want to keep the discussion... I'm introducing the concept of pinning an available package or pinning an installed package
By default pinning works on available. To pin a specific installed app I'm adding a --installed flag. Would be great if we can just guess the intent and avoid the arg, but I could not find an easy way to do it Pins for an installed package are represented in the DB by using the ProductCode or PFN as package ID and *PredefinedInstalledSource for the source ID (this could be any string, doesn't actually have to match the real installed source ID) Most of the work is done in the CompositeSource. When creating a composite package, we query the pinning index for pins on the installed and available packages that make it up. Then when querying the composite package (e.g. for IsUpdateAvailable) we just reason about what the pin state would be for each version. |
This comment has been minimized.
This comment has been minimized.
Perhaps if pin by available fails (due to multiple packages, as one scenario) then pinning by installed could be a fallback? |
Workflow::OpenSource() << | ||
Workflow::OpenCompositeSource(Repository::PredefinedSource::Installed); | ||
} | ||
|
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
src/AppInstallerRepositoryCore/Microsoft/Schema/Pinning_1_0/PinTable.cpp
Show resolved
Hide resolved
if (context.Args.Contains(Execution::Args::Type::Id)) | ||
{ | ||
// When we are given an ID, just pin that available package without checking for installed. | ||
// This helps when there are matching issues, for example due to multiple side-by-side installs. |
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.
So previously, our goal for pinning available package is: if we find one available package to pin, all other available packages from other sources are pinned, except if user provides -s <source>
Do you think we should do this for --id pins as well?
And our previous statement is we only pin packages that we can find an installed one with. This is allowing pinning packages that may not be installed yet. I guess it's ok, but just wanted to bring up, so that we think through all scenarios and it's ok.
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.
So previously, our goal for pinning available package is: if we find one available package to pin, all other available packages from other sources are pinned, except if user provides -s
Do you think we should do this for --id pins as well?
I hadn't thought about that. With the code as it is, it will add pins to all sources matching the query (--id or otherwise). So if you do pin add Microsoft.PowerToys
and multiple sources have Microsoft.PowerToys
we'd be adding pins to all of them, which seems okay to me. But if the ID in one of the sources is just "PowerToys" we wouldn't pin it. That also seems okay to me because we can't guess what queries we'd have to make to match the package from another source as it can be totally different. And this applies whether we are using --id or some other filter
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.
We could construct a query for systemReferenceStrings to find available packages from other sources. We can do it later if such asks emerges. But the behavior is different from what I specc'ed before.
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 PR changes the pinning table to record an installed pinned app's Product Code or Package Family Name. This allows us to distinguish between multiple installed apps that we want to pin and have the same package ID, in particular the Windows SDK.
This includes a breaking change to the schema of the pinning DB. The pinning index now uses v1.1, but it is not backwards compatible with v1.0. If, when opening an existing index, we see that it has version 1.0, we delete it and create a new one with the new version. This will drop all existing pins; requiring them to be re-added.I could try to recover the pins, but I think it is better to re-add them to get the new fields I'm adding in this PR.
I'm adding the ProductCode or PackageFamilyName as an extra identifier in the PinKey. If an installed package has multiple, we create multiple pins.
Closes #2974
Closes #3142, as the new DB schema won't even allow null for the version field
Edit: Seems to also fix #2977
Edit: Updated note about deleting old DB
Microsoft Reviewers: Open in CodeFlow