pwsh-cs-tools / core

Adds missing features available in C# but not natively available in PowerShell
MIT License
11 stars 2 forks source link

FR (Versioning): Improve NuGet Version Range Support #50

Open anonhostpi opened 10 months ago

anonhostpi commented 10 months ago

Should fix the following comment from #49:
- https://github.com/pwsh-cs-tools/core/issues/49#issuecomment-1898185715

+1, sharing the temp path causes errors if two packages contain the same file eg large depencency trees like Azure.Monitor.OpenTelemetry.Exporter

Part of the issue is that Azure.Monitor.OpenTelemetry.Explorer is likely using an older version, and that the Bootstrapper is detecting an unbounded version range (which is currently not supported).

However, a bit of work has been already done to improve Import-Package's versioning control when the -CachePath parameter was introduced, so logic to compare semantic versions may already be available.

anonhostpi commented 10 months ago

Improving the NuGet Version Range handling should also help with 2 other problems:

  1. What to do when 2 dependencies in the dependency tree require 2 different ranges of the same package
  2. Should help improve the $loaded logic.
anonhostpi commented 10 months ago

To make this work this would require a change to all of the versioning and version control logic.

Thankfully, we could likely get away with using $bootstrapper.GetAllVersions() to help with most of it.

Figuring out which packages are in range she probably be done by Resolve-CachedPackage.

However, something clever will have to be done about determining the range overlap.

anonhostpi commented 10 months ago

I think a starting point would be to add a field to PackageData that caches a call to GetAllVersions().

In theory, this would do 2 things:

This could also allow for a lot more advanced version control logic, since PackageData is currently limited to GetStable() and GetPrerelease()

anonhostpi commented 10 months ago

This would likely warrant recursion when selecting dependencies for the best range of a package.

To optimize looping, I think the best option is to only recurse when the upper bounds of a range has changed.

anonhostpi commented 10 months ago

The upper and lower bounds should include 3 versions:

anonhostpi commented 10 months ago

Another problem that would warrant a complete refactor is that currently due to Import-Package's simplistic version control, Import-Package is able to load dependencies at the same time that it builds the dependency tree.

While I might be able to keep this design in mind:

To optimize looping, I think the best option is to only recurse when the upper bounds of a range has changed.

I think it might be best to separate loading and tree parsing into 2 separate steps. This would slow Import-Package down, but would allow me to add more features down the road.

anonhostpi commented 10 months ago

An optimization that could help with dependency loading is using the v3-flatcontainer API to download just the nuspec, instead of the entire .nupkg when parsing the dependency tree.

EDIT: PartialZip is available in C# and could be transpiled to PowerShell (or installed during the bootstrapper process)

anonhostpi commented 10 months ago

An optimization that could help with dependency loading is using the v3-flatcontainer API to download just the nuspec, instead of the entire .nupkg when parsing the dependency tree.

Example implementation:

# NuGet Package ID and Version
$packageId = "YOUR_PACKAGE_ID"
$packageVersion = "YOUR_PACKAGE_VERSION"

# NuGet API URL
$url = "https://api.nuget.org/v3-flatcontainer/$packageId/$packageVersion/$packageId.nuspec"

# Fetch and parse the .nuspec XML data
try {
    $response = Invoke-WebRequest -Uri $url
    $nuspecXml = [xml]$response.Content  # Parses the content as XML

    # The XML data is now stored in the variable $nuspecXml
    Write-Host "Successfully fetched and parsed .nuspec data for package $packageId version $packageVersion"
    # Display the XML content
    $nuspecXml.OuterXml
} catch {
    Write-Host "Error fetching or parsing .nuspec data: $_"
}

# You can now use the variable $nuspecXml to work with the XML data
anonhostpi commented 10 months ago

Adding such support would also likely warrant refactoring any filesystem modifications done by Resolve-CachedPackages, as the current design would cause a performance hit any time the ranges are updated, if this change is implemented.

anonhostpi commented 10 months ago

EDIT: PartialZip is available in C# and could be transpiled to PowerShell (or installed during the bootstrapper process)

It doesn't look like NuGet supports byte ranges. It also looks like they don't have an API for exposing the content of the .nupkgs:

anonhostpi commented 10 months ago

Feature implementation started. See: https://github.com/pwsh-cs-tools/Import-Package/commit/28550db1e6588af8eab31f13e43784f2aed8fde9