Skip to content

Commit

Permalink
NuGet fixes (#3335)
Browse files Browse the repository at this point in the history
Two new parameters on Sort-AppFilesByDependencies
(includeSystemDependencies and includeDependencyVersion)
Add Public Microsoft NuGet Feeds as settings constants
Fix issues in Download-BcNuGetPackageToFolder, where extensive amounts
of NuGet searches was performed to locate packages
Download-BcNuGetPackageToFolder now returns an array of apps downloaded
instead of True/False

---------

Co-authored-by: freddydk <[email protected]>
  • Loading branch information
freddydk and freddydk authored Feb 14, 2024
1 parent b0e2bbe commit 2bc6df4
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 81 deletions.
30 changes: 28 additions & 2 deletions AppHandling/Sort-AppFilesByDependencies.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
Array of AppIds. If specified, then include Only Apps in the specified AppFile array or archive which is contained in this Array and their dependencies
.Parameter unknownDependencies
If specified, this reference parameter will contain unresolved dependencies after sorting
.Parameter excludeRuntimePackages
If specified, runtime packages will be ignored
.Parameter includeSystemDependencies
If specified, dependencies on Microsoft.Application and Microsoft.Platform will be included
.Parameter includeDependencyVersion
If specified, the version of the dependencies will be included in the output
.Example
$files = Sort-AppFilesByDependencies -appFiles @($app1, $app2)
#>
Expand All @@ -22,7 +28,9 @@ function Sort-AppFilesByDependencies {
$excludeInstalledApps = @(),
[Parameter(Mandatory=$false)]
[ref] $unknownDependencies,
[switch] $excludeRuntimePackages
[switch] $excludeRuntimePackages,
[switch] $includeSystemDependencies,
[switch] $includeDependencyVersion
)

$telemetryScope = InitTelemetryScope -name $MyInvocation.InvocationName -parameterValues $PSBoundParameters -includeParameters @()
Expand Down Expand Up @@ -109,6 +117,24 @@ function Sort-AppFilesByDependencies {
$anApp.Dependencies | ForEach-Object { AddDependency -Dependency $_ }
}
}
if ($includeSystemDependencies.IsPresent) {
if ($anApp.psobject.Members | Where-Object name -eq "application") {
AddDependency -dependency ([PSCustomObject]@{
"publisher" = "Microsoft"
"name" = "Application"
"version" = $anApp.Application
"id" = 'Microsoft.Application'
})
}
if ($anApp.psobject.Members | Where-Object name -eq "platform") {
AddDependency -dependency ([PSCustomObject]@{
"publisher" = "Microsoft"
"name" = "Platform"
"version" = $anApp.Platform
"id" = 'Microsoft.Platform'
})
}
}
}
}

Expand Down Expand Up @@ -163,7 +189,7 @@ function Sort-AppFilesByDependencies {
}
if ($unknownDependencies) {
$unknownDependencies.value = @($script:unresolvedDependencies | ForEach-Object { if ($_) {
"$(if ($_.PSObject.Properties.name -eq 'AppId') { $_.AppId } else { $_.Id }):" + $("$($_.publisher)_$($_.name)_$($_.version).app".Split([System.IO.Path]::GetInvalidFileNameChars()) -join '')
"$(if ($_.PSObject.Properties.name -eq 'AppId') { $_.AppId } else { $_.Id }):$(if($includeDependencyVersion.IsPresent){"$($_.Version):"})" + $("$($_.publisher)_$($_.name)_$($_.version).app".Split([System.IO.Path]::GetInvalidFileNameChars()) -join '')
} })
}
}
Expand Down
2 changes: 2 additions & 0 deletions BC.HelperFunctions.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ function Get-ContainerHelperConfig {
"OAuthHostName" = "b52e8b6a-2953-4a08-8e28-5cf45a2dffdc"
"OAuthScopes" = "api://b52e8b6a-2953-4a08-8e28-5cf45a2dffdc/.default offline_access"
}
"MSSymbolsNuGetFeedUrl" = 'https://dynamicssmb2.pkgs.visualstudio.com/DynamicsBCPublicFeeds/_packaging/MSSymbols/nuget/v3/index.json'
"MSAppsNuGetFeedUrl" = 'https://dynamicssmb2.pkgs.visualstudio.com/DynamicsBCPublicFeeds/_packaging/MSApps/nuget/v3/index.json'
"TrustedNuGetFeeds" = @(
)
}
Expand Down
130 changes: 84 additions & 46 deletions NuGet/Download-BcNuGetPackageToFolder.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,67 @@ Function Download-BcNuGetPackageToFolder {
[PSCustomObject[]] $installedApps = @(),
[ValidateSet('all','own','allButMicrosoft','allButApplication','allButPlatform','none')]
[string] $downloadDependencies = 'allButApplication',
[switch] $allowPrerelease
[switch] $allowPrerelease,
[switch] $checkLocalVersion
)

try {
$returnValue = $false
$findSelect = $select
if ($select -eq 'LatestMatching') {
$findSelect = 'Latest'
}
$excludeVersions = @()
if ($checkLocalVersion) {
# Format Publisher.Name[.Country][.symbols][.AppId]
if ($packageName -match '^(Microsoft)\.([^\.]+)(\.[^\.][^\.])?(\.symbols)?(\.[0-9A-Fa-f]{8}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{12})?$') {
$publisher = $matches[1]
$name = $matches[2]
$countryPart = "$($matches[3])"
$symbolsPart = "$($matches[4])"
$appIdPart = "$($matches[5])"
$checkPackageName = ''
if ($name -ne 'Platform' -and $countryPart -eq '' -and $installedCountry -ne '') {
$countryPart = ".$installedCountry"
$checkPackageName = "$publisher.$name$countryPart$symbolsPart$appIdPart"
}
if ($checkPackageName -and $checkPackageName -ne $packageName) {
$downloadedPackages = Download-BcNuGetPackageToFolder -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -packageName $checkPackageName -version $version -folder $folder -copyInstalledAppsToFolder $copyInstalledAppsToFolder -installedPlatform $installedPlatform -installedCountry $installedCountry -installedApps $installedApps -downloadDependencies $downloadDependencies -verbose:($VerbosePreference -eq 'Continue') -select $select -allowPrerelease:$allowPrerelease
if ($downloadedPackages) {
return $downloadedPackages
}
}
return Download-BcNuGetPackageToFolder -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -packageName $packageName -version $version -folder $folder -copyInstalledAppsToFolder $copyInstalledAppsToFolder -installedPlatform $installedPlatform -installedCountry $installedCountry -installedApps $installedApps -downloadDependencies $downloadDependencies -verbose:($VerbosePreference -eq 'Continue') -select $select -allowPrerelease:$allowPrerelease
}
}
Write-Host "Looking for NuGet package $packageName version $version ($select match)"
if ($packageName -match '^Microsoft\.Platform(\.symbols)?$') {
if ($installedPlatform) {
$existingPlatform = $installedPlatform
}
else {
$existingPlatform = $installedApps | Where-Object { $_ -and $_.Name -eq 'Platform' } | Select-Object -ExpandProperty Version
}
if ($existingPlatform -and ([NuGetFeed]::IsVersionIncludedInRange($existingPlatform, $version))) {
Write-Host "Microsoft.Platform version $existingPlatform is already available"
return @()
}
}
elseif ($packageName -match '^([^\.]+\.)?Application(\.[^\.]+)?(\.symbols)?$') {
$installedApp = $installedApps | Where-Object { $_ -and $_.Name -eq 'Application' }
if ($installedApp -and ([NuGetFeed]::IsVersionIncludedInRange($installedApp.Version, $version))) {
Write-Host "Application version $($installedApp.Version) is already available"
return @()
}
}
elseif ($packageName -match '^([^\.]+)\.([^\.]+)(\.[^\.][^\.])?(\.symbols)?(\.[0-9A-Fa-f]{8}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{12})?$') {
$installedApp = $installedApps | Where-Object { $_ -and $_.id -and $packageName -like "*$($_.id)*" }
if ($installedApp -and ([NuGetFeed]::IsVersionIncludedInRange($installedApp.Version, $version))) {
Write-Host "$($installedApp.Name) from $($installedApp.publisher) version $($installedApp.Version) is already available (AppId=$($installedApp.id))"
return @()
}
}
while ($true) {
$returnValue = @()
$feed, $packageId, $packageVersion = Find-BcNugetPackage -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -packageName $packageName -version $version -excludeVersions $excludeVersions -verbose:($VerbosePreference -eq 'Continue') -select $findSelect -allowPrerelease:($allowPrerelease.IsPresent)
if (-not $feed) {
Write-Host "No package found matching package name $($packageName) Version $($version)"
Expand All @@ -96,6 +145,22 @@ try {
Write-Verbose "NUSPEC:"
$nuspec | ForEach-Object { Write-Verbose $_ }
$manifest = [xml]$nuspec
$appId = ''
$appName = $manifest.package.metadata.title
if ($manifest.package.metadata.id -match '^.*([0-9A-Fa-f]{8}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{12})$') {
# If packageId ends in a GUID (AppID) then use the AppId for the packageId
$appId = "$($matches[1])"
}
elseif ($manifest.package.metadata.id -like 'Microsoft.Platform*') {
# If packageId starts with Microsoft.Platform then use the packageId for the packageId
$appName = 'Platform'
}
$returnValue = @([PSCustomObject]@{
"Publisher" = $manifest.package.metadata.authors
"Name" = $appName
"id" = $appId
"Version" = $manifest.package.metadata.version
})
$dependenciesErr = ''
if ($manifest.package.metadata.PSObject.Properties.Name -eq 'Dependencies') {
$dependencies = $manifest.package.metadata.Dependencies.GetEnumerator()
Expand All @@ -104,50 +169,49 @@ try {
$dependencies = @()
}
foreach($dependency in $dependencies) {
if (-not $installedPlatform) {
$installedPlatform = $installedApps+$returnValue | Where-Object { $_ -and $_.Name -eq 'Platform' } | Select-Object -ExpandProperty Version
}
$dependencyVersion = $dependency.Version
$dependencyId = $dependency.Id
$dependencyCountry = ''
$downloadIt = $false
if ($dependencyId -eq 'Microsoft.Platform') {
if ($dependencyId -match '^Microsoft\.Platform(\.symbols)?$') {
$dependencyPublisher = 'Microsoft'
# Dependency is to the platform
if ($installedPlatform) {
if (!([NuGetFeed]::IsVersionIncludedInRange($installedPlatform, $dependencyVersion))) {
# The NuGet package found isn't compatible with the installed platform
$dependenciesErr = "NuGet package $packageId (version $packageVersion) requires platform $dependencyVersion. You cannot install it on version $installedPlatform"
}
$downloadIt = $false
}
else {
$downloadIt = ($downloadDependencies -eq 'all')
}
}
elseif ($dependencyId -match '^([^\.]+\.)?Application(\.[^\.]+)?$') {
elseif ($dependencyId -match '^([^\.]+\.)?Application(\.[^\.]+)?(\.symbols)?$') {
# Dependency is to the application
$dependencyPublisher = $matches[1].TrimEnd('.')
if ($matches.Count -gt 2) {
$dependencyCountry = $matches[2].TrimStart('.')
}
if ($installedCountry -and $dependencyCountry -and ($installedCountry -ne $dependencyCountry)) {
# The NuGet package found isn't compatible with the installed application
Write-Host "WARNING: NuGet package $packageId (version $packageVersion) requires $dependencyCountry application. You have $installedCountry application installed"
}
$dependencyCountry = "$($matches[2])".TrimStart('.')
$installedApp = $installedApps | Where-Object { $_ -and $_.Name -eq 'Application' }
if ($installedApp) {
if (!([NuGetFeed]::IsVersionIncludedInRange($installedApp.Version, $dependencyVersion))) {
$dependenciesErr = "NuGet package $packageId (version $packageVersion) requires application $dependencyVersion. You cannot install it on version $($installedApp.Version)"
}
$downloadIt = $false
}
else {
$downloadIt = ($downloadDependencies -eq 'all' -or $downloadDependencies -eq 'allButPlatform')
}
}
else {
$dependencyPublisher = ''
if ($dependencyId -match '^([^\.]+)\.([^\.]+)\.([^\.]+\.)?([0-9A-Fa-f]{8}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{12})$') {
# Matches publisher.name.[country.].appId format (country section is only for microsoft apps)
if ($dependencyId -match '^([^\.]+)\.([^\.]+)(\.[^\.][^\.])?(\.symbols)?(\.[0-9A-Fa-f]{8}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{12})?$') {
# Matches publisher.name[.country][.symbols][.appId] format (country section is only for microsoft apps)
$dependencyPublisher = $matches[1]
if ($dependencyPublisher -eq 'microsoft' -and $matches.Count -gt 3) {
$dependencyCountry = $matches[3].TrimEnd('.')
if ($dependencyPublisher -eq 'microsoft') {
$dependencyCountry = "$($matches[3])".TrimStart('.')
}
}
$installedApp = $installedApps | Where-Object { $_ -and $_.id -and $dependencyId -like "*$($_.id)*" }
Expand All @@ -169,6 +233,10 @@ try {
$downloadIt = ($downloadDependencies -ne 'none')
}
}
if ($installedCountry -and $dependencyCountry -and ($installedCountry -ne $dependencyCountry)) {
# The NuGet package found isn't compatible with the installed application
Write-Host "WARNING: NuGet package $packageId (version $packageVersion) requires $dependencyCountry application. You have $installedCountry application installed"
}
if ($dependenciesErr) {
if ($select -ne 'LatestMatching') {
throw $dependenciesErr
Expand All @@ -180,36 +248,7 @@ try {
}
}
if ($downloadIt) {
$checkPackageName = ''
if ($dependencyId -match '^.*([0-9A-Fa-f]{8}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{4}\-[0-9A-Fa-f]{12})$') {
# If dependencyId ends in a GUID (AppID) then use the AppId for downloading dependencies
$dependencyId = $matches[1]
if ($dependencyCountry) {
# Dependency is to a specific country version - must find the country version of the dependency
$dependencyId = "$dependencyCountry.$dependencyId"
}
elseif ($installedCountry -and $dependencyPublisher -eq 'Microsoft') {
# Looking for a Microsoft package - check if it exists for the installed country (revert to appId if not)
$checkPackageName = "$installedCountry.$dependencyId"
}
}
elseif (($dependencyId -match '^Microsoft.Application(\.[^\.]+)?$') -and ($matches.Count -eq 1)) {
# If dependency is to the Application without a specific country, then check if a localization version of the application exists for the installed country
$checkPackageName = "Microsoft.Application.$installedCountry"
}
if ($checkPackageName) {
Write-Host -ForegroundColor Yellow $checkPackageName
if (Download-BcNuGetPackageToFolder -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -packageName $checkPackageName -version $dependencyVersion -folder $package -copyInstalledAppsToFolder $copyInstalledAppsToFolder -installedPlatform $installedPlatform -installedCountry $installedCountry -installedApps $installedApps -downloadDependencies $downloadDependencies -verbose:($VerbosePreference -eq 'Continue') -select $select -allowPrerelease:$allowPrerelease) {
$returnValue = $true
$downloadIt = $false
}
}
if ($downloadIt) {
Write-Host -ForegroundColor Yellow $dependencyId
if (Download-BcNuGetPackageToFolder -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -packageName $dependencyId -version $dependencyVersion -folder $package -copyInstalledAppsToFolder $copyInstalledAppsToFolder -installedPlatform $installedPlatform -installedCountry $installedCountry -installedApps $installedApps -downloadDependencies $downloadDependencies -verbose:($VerbosePreference -eq 'Continue') -select $select -allowPrerelease:$allowPrerelease) {
$returnValue = $true
}
}
$returnValue += Download-BcNuGetPackageToFolder -nuGetServerUrl $nuGetServerUrl -nuGetToken $nuGetToken -packageName $dependencyId -version $dependencyVersion -folder $package -copyInstalledAppsToFolder $copyInstalledAppsToFolder -installedPlatform $installedPlatform -installedCountry $installedCountry -installedApps @($installedApps+$returnValue) -downloadDependencies $downloadDependencies -verbose:($VerbosePreference -eq 'Continue') -select $select -allowPrerelease:$allowPrerelease -checkLocalVersion
}
}
if ($dependenciesErr) {
Expand All @@ -230,7 +269,6 @@ try {
$appFiles = Get-Item -Path (Join-Path $package "*.app")
}
foreach($appFile in $appFiles) {
$returnValue = $true
Copy-Item $appFile.FullName -Destination $folder -Force
if ($copyInstalledAppsToFolder) {
Copy-Item $appFile.FullName -Destination $copyInstalledAppsToFolder -Force
Expand Down
9 changes: 5 additions & 4 deletions NuGet/Find-BcNuGetPackage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,12 @@ Function Find-BcNuGetPackage {
if (!($feed.PSObject.Properties.Name -eq 'Patterns')) { $feed | Add-Member -MemberType NoteProperty -Name 'Patterns' -Value @('*') }
if (!($feed.PSObject.Properties.Name -eq 'Fingerprints')) { $feed | Add-Member -MemberType NoteProperty -Name 'Fingerprints' -Value @() }
$nuGetFeed = [NuGetFeed]::Create($feed.Url, $feed.Token, $feed.Patterns, $feed.Fingerprints)
$packageIds = $nuGetFeed.Search($packageName)
if ($packageIds) {
foreach($packageId in $packageIds) {
$packages = $nuGetFeed.Search($packageName)
if ($packages) {
foreach($package in $packages) {
$packageId = $package.Id
Write-Host "PackageId: $packageId"
$packageVersion = $nuGetFeed.FindPackageVersion($packageId, $version, $excludeVersions, $select, $allowPrerelease.IsPresent)
$packageVersion = $nuGetFeed.FindPackageVersion($package, $version, $excludeVersions, $select, $allowPrerelease.IsPresent)
if (!$packageVersion) {
Write-Host "No package found matching version '$version' for package id $($packageId)"
continue
Expand Down
Loading

0 comments on commit 2bc6df4

Please sign in to comment.