microsoft / winget-cli

WinGet is the Windows Package Manager. This project includes a CLI (Command Line Interface), PowerShell modules, and a COM (Component Object Model) API (Application Programming Interface).
https://learn.microsoft.com/windows/package-manager/
MIT License
23.25k stars 1.45k forks source link

Better support for Side by Side packages #2129

Open JohnMcPMS opened 2 years ago

JohnMcPMS commented 2 years ago

Description of the new feature / enhancement

winget should better support multiple versions of the same package being installed on the same machine. This happens, and we currently try to pretend it doesn't.

Proposed technical implementation details

The current design is a simple 1:1 mapping between installed artifacts and available packages. This has been largely effective, but it certainly belies the true complexities of some packages / installed states. Any complete solution will have to expand to support a full graph, but fortunately we can do small steps to get there.

As far as available packages go, we can control the graph quite a bit. We currently have only two concepts: package and version. The only available relationship is that packages have 1 to N versions. Dependencies are relevant here, as they are simply references, not containment. The only other concept that I am aware of having been discussed is that of a "group" package (name made up on the spot). This "group" package would name several other packages, which would all be considered a part of the group. Consider a group graph like: python contains {python.3, python.2 } and python.3 contains { python.3.12, python.3.11, ... }. A dependency on python would allow any version to satisfy it, while a dependency on python.3 would require major version 3. Some ordering mechanism or "default" tagging would allow the preferred package to install when appropriate (or to provide the available options for choice when the group is less coupled like JDK/JRE). I mention all of this because the side-by-side support would be strictly required to implement "group" packages. Effectively though, these are still packages in our graph, they just have more complex handling requirements.

The installed artifacts are quite a bit more complex and not under our control. But I believe that they fall into two top level categories: primary components and subcomponents. In reality, there are likely many different flavors of subcomponents that might require special handling, but they are all not primary. Currently the goal of the 1:1 mapping is to create a link between the primary component and the available package. Side-by-side support requires allowing multiple primary components to be associated with available package, but it is not concerned with subcomponents. The issue with current reality is that there are manifests with subcomponent details listed that would likely lead to improper side-by-side views even with only one package version installed (without at least some effort placed there).

So, to cover my entire vision on the graph of relationships:

  1. A "group" package is composed of [1, N] packages (some of which may also be groups)
  2. A package is composed of [1, N] versions
  3. A version is composed of [1, N] installers, which I sneak in here because it is important at an implementation level to have this information so that we can better categorize installed artifacts
  4. An installed package version is composed of [1, N] components, with exactly 1 primary component
  5. A package may be associated with [0, N] installed package versions

For a minimal side-by-side implementation to work, we will need to implement 5, enough of 4 to separate out primary components, and the portions of 3 to allow the improved categorization of the installed package versions.

The achievable graph is much more likely:

graph TD;
    p(Package)-->v1(Available Version 1)
    p-->v2(Available Version 2)
    p-->i1u(Installed Version 1 User)
    p-->i1m(Installed Version 1 Machine)
    p-->i2(Installed Version 3)
    i1u-->pC1u(Primary Component)
    i1m-->pC1m(Primary Component)
    i2-->pC2(Primary Component)
    p-->sub(Subcomponents)
    i1u-->v1
    i1m-->v1

Note that installed versions are not linked through available versions, but do allow for a potential link back to the available version if it exists. Also note that I am pessimistic about the likelihood of successfully associating subcomponents with their installed version. We could allow for that by having both versioned and unversioned buckets, but I would not start there. Finally, note that side-by-side needs to support not only multiple versions, but potentially the different flavors of a single version (whether differentiated by scope, architecture, etc.)

"Group" packages fit into this model, but we would likely want to have a richer object interface to support them specifically.

Care will need to be taken in designing the user experience to prevent the need for more data than we can comfortably add to the index. We want to be able to lump installed artifacts in with available packages quickly, but at the same time we will need more information than we currently have to be able to determine primary components and the set of versions/flavors of installed items. For programmatic access we can lazily determine some of it with the manifest, but we want to make sure that the CLI experience doesn't force that on winget list, but rather only when a single result is found.

denelon commented 2 years ago

@JohnMcPMS I think this is a great call out. I think we should also take this into consideration as it relates to channels and how we can handle software that doesn't install side by side.

I know Ultimaker.Cura as an example of one package where the .exe during upgrade simply installs a new version of the package. We should also include the impact on the import scenario.

JohnLukeBentley commented 2 years ago

I think we should also take this into consideration as it relates to channels and how we can handle software that doesn't install side by side.

Another example in my case is with respect to Typora. https://typora.io/

I currently have a dev channel release installed, 1.3.3-dev (From https://typora.io/releases/all > [Dev/Beta Releases])

> winget upgrade 

... gives ...

Typora 1.3     Typora.Typora       1.3.3          1.3.6         winget

... That is, winget is not recognizing the dev channel and, if allowed, will (undesirably) upgrade the dev channel 1.3.3-dev to the stable release channel 1.3.6 (From https://typora.io/releases/all > [Stable releases]).

Unless, that is, that the Typora developer is failing to configure their winget manifest correctly (but given this issue is open presumably multiple channels is not supported in winget currently)

JohnLukeBentley commented 2 years ago

147 "Support different release channels [released, beta, alpha]" is the better place for the channels issue.

ppvnf commented 2 years ago

I don't really understand why Microsoft Visual C++ Redistributables have different packages for x86 and x64 architectures, but .NET Desktop Runtimes don't have both as separate packages.

jedieaston commented 2 years ago

Dependency management, mostly. We currently can't say in the manifest that a package relies on a certain architecture of another package, so we have to have per architecture pacakges for the VCRedists (many packages specifically want the x86 redists). And no one has added a package that relies on a certain architecture of the .NET Desktop Runtime.

aadithya96 commented 1 year ago

Another example of this being an issue would be SSMS. Major versions like 18,19 can be installed side-by-side. Winget would still mark v18 as outdated and show the upgrade to v19.

Trenly commented 1 year ago

[Policy] Area-Matching

dryo commented 1 year ago

Another example of this being an issue would be SSMS. Major versions like 18,19 can be installed side-by-side. Winget would still mark v18 as outdated and show the upgrade to v19.

Well, this happens now and winget installs v19. But it keeps v18 intact, so we run into the issue that winget installs v19 every time winget upgrade --all is issued. Like here: #1392

denelon commented 11 months ago

I just linked a draft specification for anyone following this issue.

Wallby commented 8 months ago

@denelon

I know Ultimaker.Cura as an example of one package where the .exe during upgrade simply installs a new version of the package. We should also include the impact on the import scenario.

Also Vulkan SDK and blender on updating (seemingly silently) install a new version and then output no installed package found matching input criteria, but keep including the package in the output of winget update.

aaronliu0130 commented 8 months ago

Something simpler we could also do in the meantime is automatically try installing a package if updating gives "No installed package found matching input criteria", especially if --force is passed.

denelon commented 7 months ago

We've been working on the side-by-side scenarios. You could try the latest release and enable the experimental feature on:

Please provide feedback at:

Trenly commented 7 months ago

[Policy] Experimental