Skip to content

Instantly share code, notes, and snippets.

@anonhostpi
Last active October 7, 2023 11:29
Show Gist options
  • Save anonhostpi/f385e0ec2bca28cc5cc2a136627a4c69 to your computer and use it in GitHub Desktop.
Save anonhostpi/f385e0ec2bca28cc5cc2a136627a4c69 to your computer and use it in GitHub Desktop.
NuGet.Frameworks and Microsft.NETCore.Platforms wrappers for PowerShell (bootstrap code for writing an Import-Package cmdlet)
& {
Add-Type -AssemblyName System.Runtime # Useful for RID detection
Add-Type -AssemblyName System.IO.Compression.FileSystem # Useful for reading nupkg/zip files
# Exported methods and properties
$Exported = New-Object psobject
$Exported | Add-Member `
-MemberType ScriptMethod `
-Name GetLatest `
-Value {
param( $Name )
$apis = Invoke-WebRequest https://api.nuget.org/v3/index.json
$apis = ConvertFrom-Json $apis
$resource = $apis.resources | Where-Object {
($_."@type" -eq "SearchQueryService") -and
($_.comment -like "*(primary)*")
}
$id = $resource."@id"
$results = Invoke-WebRequest "$id`?q=packageid:$Name&prerelease=false&take=1"
$results = ConvertFrom-Json $results
$results.data[0].version
}
$Exported | Add-Member `
-MemberType ScriptMethod `
-Name ReadNuspec `
-Value {
param( $Package )
$nupkg = $Package.Source
$nupkg = [System.IO.Compression.ZipFile]::OpenRead( $nupkg )
$nuspec = $nupkg.Entries | Where-Object { $_.FullName -eq "$($Package.Name).nuspec" }
$stream = $nuspec.Open()
$reader = New-Object System.IO.StreamReader( $stream )
[xml]($reader.ReadToEnd())
$reader.Close()
$stream.Close()
$nupkg.Dispose()
}
$Exported | Add-Member `
-MemberType ScriptMethod `
-Name Load `
-Value {
param(
[string] $Path,
[bool] $Partial = $false
)
# todo: add handling of native/unmanaged assemblies
try {
$AddTypeParams = @{
# PassThru = $false
}
if( $Partial ) {
$AddTypeParams.AssemblyName = $Path
} elseif ( Test-Path $Path ) {
$AddTypeParams.Path = $Path
} else {
Write-Host "Unable to load $Path"
return
}
Add-Type @AddTypeParams
} catch { Write-Host "Unable to load $Path" }
}
$Exported | Add-Member `
-MemberType ScriptMethod `
-Name Init `
-Value {
$Loaded = Try {
[NuGet.Frameworks.FrameworkConstants+FrameworkIdentifiers]
} Catch {
$false
}
If( -not( $Loaded )){
$load_order = [System.Collections.ArrayList]::new()
$load_order.Add( "NuGet.Frameworks" ) | Out-Null
# Loop init
$i = 0
$package_name = ""
# Caching for performance
$package_table = @{}
while( $i -lt $load_order.count ){
$package_name = $load_order[$i]
If( -not( $package_table.ContainsKey( $package_name ) ) ){
$package = Get-Package $package_name -ProviderName NuGet -ErrorAction SilentlyContinue
$latest = Try {
$this.GetLatest( $package_name )
} Catch { $package.Version }
if( (-not $package) -or ($package.Version -ne $latest) ){
Try {
Install-Package $package_name `
-ProviderName NuGet `
-SkipDependencies `
-Force | Out-Null
} Catch {}
$package = Get-Package $package_name -ProviderName NuGet -ErrorAction Stop
}
$package_table[ $package_name ] = $package.Source.ToString()
$dependencies = ($this.ReadNuspec( $package ).package.metadata.dependencies.group | Where-Object { $_.targetframework -eq "netstandard2.0" }).dependency | Where-Object { $_.id }
foreach( $dependency in $dependencies ){
$load_order.Add( $dependency.id ) | Out-Null
}
} else {
$oldindex = $load_order.IndexOf( $package_name )
$load_order.RemoveAt( $oldindex )
$load_order.Add( $package_name )
}
$i += 1
}
$this | Add-Member `
-MemberType NoteProperty `
-Name Dependencies `
-Value ($load_order | Select-Object -Unique)
[array]::Reverse( $this.Dependencies )
$this.Dependencies | ForEach-Object {
$package_source = $package_table[ $_ ]
$dll = Resolve-Path "$(Split-Path $package_source -ErrorAction SilentlyContinue)\lib\netstandard2.0\$_.dll" -ErrorAction SilentlyContinue
$this.Load( $dll )
}
$this | Add-Member `
-MemberType NoteProperty `
-Name Reducer `
-Value ([NuGet.Frameworks.FrameworkReducer]::new())
$this | Add-Member `
-MemberType NoteProperty `
-Name Frameworks `
-Value @{}
[NuGet.Frameworks.FrameworkConstants+FrameworkIdentifiers].DeclaredFields | ForEach-Object {
$this.Frameworks[$_.Name] = $_.GetValue( $null )
}
$this | Add-Member `
-MemberType NoteProperty `
-Name System `
-Value (& {
$runtime = [System.Runtime.InteropServices.RuntimeInformation, mscorlib]::FrameworkDescription
$version = $runtime -split " " | Select-Object -Last 1
$framework_name = ($runtime -split " " | Select-Object -SkipLast 1) -join " "
If( $framework_name -eq ".NET Framework" ) {
$framework_name = "Net"
} else {
$framework_name = "NETCoreApp"
}
[NuGet.Frameworks.NuGetFramework]::new( "$($this.Frameworks[ $framework_name ]),Version=v$version" )
})
Try {
& {
If( [System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier ){
$package = Get-Package "Microsoft.NETCore.Platforms" -ProviderName NuGet -ErrorAction SilentlyContinue
$latest = Try {
$this.GetLatest( "Microsoft.NETCore.Platforms" )
} Catch { $package.Version }
if( (-not $package) -or ($package.Version -ne $latest) ){
Try {
Install-Package "Microsoft.NETCore.Platforms" `
-ProviderName NuGet `
-SkipDependencies `
-Force | Out-Null
} Catch {}
$package = Get-Package "Microsoft.NETCore.Platforms" -ProviderName NuGet -ErrorAction Stop
}
$this | Add-Member `
-MemberType NoteProperty `
-Name Runtimes `
-Value (Get-Content "$($package.source | Split-Path )\runtime.json" -Raw | ConvertFrom-Json).runtimes
$this | Add-Member `
-MemberType NoteProperty `
-Name Runtime `
-Value ([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier.ToString())
$this | Add-Member `
-MemberType NoteProperty `
-Name Graphs `
-Value ([System.Collections.ArrayList]::new())
$this.Graphs.Add( [System.Collections.ArrayList]::new() ) | Out-Null
$grapher = {
param( [string] $_rid, [System.Collections.ArrayList] $_graph )
if( $_rid ){
$_graph.Add( $_rid ) | Out-Null
$_kids = $this.Runtimes."$_rid".'#import'
If( $_kids.Count -gt 0 ){
$_kids | Select-Object -Skip 1 | ForEach-Object {
$_clone = $_graph.Clone()
$this.Graphs.Add( $_clone ) | Out-Null
& $grapher $_ $_clone
}
}
& $grapher $_kids[0] $_graph
}
}
& $grapher $this.Runtime $this.Graphs[0]
}
}
} Catch {}
}
$this
}
$Exported.Init()
} | % { $global:Test = $_ }
@anonhostpi
Copy link
Author

anonhostpi commented Oct 6, 2023

Optimization 1:

@anonhostpi
Copy link
Author

anonhostpi commented Oct 6, 2023

Improvement 2:

@anonhostpi
Copy link
Author

anonhostpi commented Oct 6, 2023

Improvement 3:

@anonhostpi
Copy link
Author

anonhostpi commented Oct 7, 2023

Improvement 4:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment