Skip to content

Platform-aware Install-PSResource: filter runtimes by RID, libs by TFM - #1963

Open
Justin Chung (jshigetomi) wants to merge 9 commits into
PowerShell:masterfrom
jshigetomi:runtimePackageResolution
Open

Platform-aware Install-PSResource: filter runtimes by RID, libs by TFM#1963
Justin Chung (jshigetomi) wants to merge 9 commits into
PowerShell:masterfrom
jshigetomi:runtimePackageResolution

Conversation

@jshigetomi

@jshigetomi Justin Chung (jshigetomi) commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

PR Summary

Adds automatic RID (Runtime Identifier) and TFM (Target Framework Moniker) filtering during package extraction, plus two new parameters (-RuntimeIdentifier, -TargetFramework) for explicit cross-platform/cross-framework deployment.


Design Decisions for Review

1. Root-level RID folders, not NuGet runtimes/ convention

PowerShell modules use win-x64/, linux-x64/ at the package root for native assets, not the standard NuGet runtimes/{rid}/native/ layout. Filtering targets this PS-ecosystem convention.

2. Merge semantics on re-install with explicit overrides

  • No override specified + already installed → warn and skip (unchanged behavior)
  • Explicit -TargetFramework or -RuntimeIdentifier + already installed → merge new content into existing version directory without overwriting files
  • -Reinstall + override → full replace (clean filtered install)

This enables incremental multi-target builds:

Install-PSResource -Name MyModule                             # gets net8.0
Install-PSResource -Name MyModule -TargetFramework 'net472'   # merges net472 into same dir

3. Singular TFM selection — no fallback extraction

NuGet.Frameworks.FrameworkReducer picks the single best-match TFM from lib/. Only that TFM's assemblies are extracted — no fallback that extracts multiple TFMs. This prevents accidental cross-lineage mixing but means users must explicitly merge if they need both.

4. Cross-lineage warning

When the selected TFM is .NETCoreApp but the package also has net472 (or vice versa), a non-fatal warning tells the user how to add the other lineage:

WARNING: This package contains assemblies for net472 which were not installed
because the current runtime selected net8.0. If you also use this module on
Windows PowerShell 5.1, run: Install-PSResource -Name <ModuleName> -TargetFramework 'net472'

PR Context

Platform aware installation was brought up in issue: MicrosoftDocs/PowerShell-Docs#794.

PR Checklist

@SydneyhSmith

Copy link
Copy Markdown
Collaborator

Justin Chung (@jshigetomi) is this PR still needed? were you able to add tests?

Copilot AI lite review requested due to automatic review settings September 9, 2026 23:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are correctness and state-leak risks (RID parsing not handling runtimes/{rid}/... as tested, and a global merge flag that can affect unrelated installs) that should be fixed before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds platform-aware filtering to Install-PSResource so package extraction can select runtime assets by RID and assemblies by TFM, with opt-in overrides for cross-platform/cross-framework deployments.

Changes:

  • Adds -RuntimeIdentifier and -TargetFramework parameters to Install-PSResource, plus argument completers.
  • Implements RID filtering (package assets) and TFM filtering (lib/ selection) during extraction, including cross-lineage warnings.
  • Updates dependency parsing to select a best-matching dependency group by TFM (JSON and nuspec paths), and introduces merge semantics when re-installing with explicit overrides.
File summaries
File Description
test/PlatformFilteringTests/RuntimePackageHelper.Tests.ps1 Adds unit tests for runtime package entry filtering behavior.
test/PlatformFilteringTests/RuntimeIdentifierHelper.Tests.ps1 Adds unit tests for RID detection and compatibility chains.
test/PlatformFilteringTests/PlatformAwareInstall.Tests.ps1 Adds integration tests covering RID/TFM filtering, overrides, merge behavior, and nuspec deps parsing.
src/code/Utils.cs Adds a directory-merge helper used for override “merge” installs.
src/code/RuntimePackageHelper.cs Introduces helper functions to detect RID-rooted entries and filter extraction accordingly.
src/code/RuntimeIdentifierHelper.cs Adds RID detection + compatibility logic for platform-aware filtering.
src/code/PSResourceInfo.cs Makes dependency parsing TFM-aware and adds nuspec dependency-group selection.
src/code/InternalHooks.cs Exposes new internal helpers for test access.
src/code/InstallPSResource.cs Adds new public parameters and passes them into install flow.
src/code/InstallHelper.cs Implements extraction-time RID/TFM filtering and override merge behavior.
src/code/ArgumentCompleter.cs Adds completers for RID and TFM parameters.
Review details

Suppressed comments (1)

src/code/RuntimePackageHelper.cs:126

  • GetRidFromRuntimesEntry() currently only extracts the RID from root-level {rid}/... entries. If the entry is in the NuGet form runtimes/{rid}/..., this returns null, which breaks RID discovery/filtering for that layout.
            string normalizedPath = entryFullName.Replace('\\', ZipPathSeparator);
            string[] parts = normalizedPath.Split(ZipPathSeparator);

            if (parts.Length >= 2 && IsRidFolder(parts[0]))
            {
  • Files reviewed: 11/11 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/code/InstallHelper.cs
Comment on lines +579 to +583
if (hasExplicitOverride)
{
_cmdletPassedIn.WriteVerbose($"Resource '{pkgToInstall.Name}' with version '{pkgVersion}' is already installed. " +
$"Proceeding to merge additional platform content (TargetFramework='{_targetFramework}', RuntimeIdentifier='{_runtimeIdentifier}').");
_mergeFilteredContent = true;
Comment on lines +103 to +107
string normalizedPath = entryFullName.Replace('\\', ZipPathSeparator);
string[] segments = normalizedPath.Split(ZipPathSeparator);

// Pattern: {rid}/... (root-level RID folders like win-x64/native.dll)
return segments.Length >= 2 && IsRidFolder(segments[0]);
Comment thread src/code/InternalHooks.cs
Comment on lines +4 to +8
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.InteropServices;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants