Dependency/Install-Dependency.ps1

#Requires -Version 5.0
using namespace System.Collections.Generic

<#
.SYNOPSIS
 
.EXAMPLE
 
.DESCRIPTION
 
.NOTES
 
#>

function Install-Dependency {
[CmdletBinding()]
Param(
    [Parameter()]
    [PSCustomObject]
    $DependencyConfig,

    [Parameter(ParameterSetName = "DependencyPath", Mandatory)]
    [Alias('DependencyPath')]
    [string[]]
    $DependencyPaths,

    [Parameter(ParameterSetName = "ScriptName", Mandatory)]
    [Alias('ScriptName')]
    [string[]]
    $ScriptNames,

    [Parameter()]
    [string]
    [ValidateSet('', 'application', 'build', 'deploy', 'test', 'script')]
    # The destination folder to install to (if required). The gitroot will be found and folders added to the named subfolder e.g. application will result in c:\gitroot\application\...
    $DestinationFolder,

    [parameter()]
    [switch]
    # By default we won't install if already installed. Force will first remove then install again
    $Force,

    [parameter()]
    [switch]
    # Automatically import after install
    $Import
)
try {
    # . "$PSScriptRoot\..\Install-DependencyNuget.ps1"
    # . "$PSScriptRoot\..\Install-DependencyPSModule.ps1"
    # . "$PSScriptRoot\..\Install-DependencyPSPackageProvider.ps1"
    # . "$PSScriptRoot\..\Install-DependencyWebDownload.ps1"
    # . "$PSScriptRoot\Get-Dependency.ps1"

    Set-StrictMode -Version 2
    $ErrorActionPreference = "Stop"

    #$Context = & "$PSScriptRoot\..\..\application\Get-VegaContext.ps1" -Environment 'None' 2> $null # we don't need the environment yet. Perhaps we can make context global in the future, but will need testing

    # get the dependencies asked for
    $dependencySplat = @{
        DestinationFolder = $DestinationFolder
    }
    if ($DependencyPaths) { $dependencySplat.Add('DependencyPaths', $DependencyPaths) }
    if ($ScriptNames) { $dependencySplat.Add('ScriptNames', $ScriptNames) }
    if ($DependencyConfig) { $dependencySplat.Add('DependencyConfig', $DependencyConfig) }
    $groupedDependencies = Get-Dependency @dependencySplat

    if ($ScriptNames) {
        Write-Host "Installing Dependencies for Scripts: $([string]::Join($ScriptNames, ','))"
    } elseif ($DependencyPaths) {
        Write-Host "Installing Dependencies for Dependency Paths: $([string]::Join($DependencyPaths, ','))"
    }

    # install them
    foreach ($typeGroup in $groupedDependencies) {
        if ($typeGroup.Name -eq 'PackageProvider') {
            foreach ($dependency in $typeGroup.Group) {
                $splat = @{
                    Name            = $Dependency.name
                    RequiredVersion = $Dependency.Version
                    Force           = $Force
                }

                Install-DependencyPSPackageProvider
            }
        } elseif ($typeGroup.Name -eq 'WebDownload') {
            foreach ($dependency in $typeGroup.Group) {
                $splat = @{
                    Name        = $Dependency.name
                    Version     = $Dependency.Version
                    Url         = $Dependency.Url
                    Destination = $Dependency.destination
                    Force       = $Force
                }

                Install-DependencyWebDownload @splat
            }
        } elseif ($typeGroup.Name -eq 'Module') {
            foreach ($dependency in $typeGroup.Group) {

                $splat = @{
                    Name            = $Dependency.name
                    RequiredVersion = $Dependency.Version
                    Force           = $Force
                    # ForceImport = [bool]$Dependency.PSObject.Properties['forceImport']
                }
                if ($Dependency.PSObject.Properties['preRelease']) {
                    $splat.Add('PreRelease', $Dependency.PreRelease)
                }

                if ($Dependency.PSObject.Properties['Repository']) {
                    $splat.Add('Repository', $Dependency.Repository)
                }

                Install-DependencyPSModule @splat
            }
        } elseif ($typeGroup.Name -eq 'Nuget') {
            # $context = & "$PSScriptRoot\..\..\application\Get-VegaContext.ps1" -Environment 'None'
            $splat = @{
                # TODO put nuget in the path so we don't need to absolute it
                NugetPath   = (Join-Path (Split-Path -Parent -Path $typeGroup.Group[0].Destination) 'Depend-WebDownload\NuGet\nuget.exe')
                #Name = $Dependency.name
                #Version = $Dependency.Version
                Destination = $typeGroup.Group[0].destination
            }

            # Install-DependencyNuget @splat
            $typeGroup.Group | Format-List | Out-String | Write-Verbose
            $nuGetConfigTemplate = @"
<!-- DO NOT CHANGE THIS: This is autogenerated by Install-Dependency so anything you do here will be undone. Use dependencies.global.json to control what gets installed by which script-->
<packages>$($typeGroup.Group | Foreach-Object { [string]::format("`n`t<package id=""{0}"" version=""{1}"" />",$_.Name,$_.version)})
</packages>
"@

            $nuGetConfigFolderName = "VegaNuget$(([IO.Path]::GetFileNameWithoutExtension([IO.Path]::GetRandomFileName())))"
            $nuGetConfigFolder = "$(Join-Path ($env:TMP) $nuGetConfigFolderName)"
            try {
                $null = New-Item -ItemType Directory $nuGetConfigFolder -Force
                $nuGetConfigPath = Join-Path $nuGetConfigFolder "packages.config"
                Write-Verbose "Generated File: $nuGetConfigPath `n----------------------------`n$nuGetConfigTemplate`n----------------------------"
                $null = New-Item -ItemType File -Path $nuGetConfigPath -Value $nuGetConfigTemplate -Force
                Install-DependencyNuget -ConfigPath $nuGetConfigPath @splat
            } finally {
                Remove-Item $nuGetConfigFolder -force -recurse -ErrorAction 'SilentlyContinue' # cleanup, although with whatif this will error so ignore it
            }
        } else {
            Write-Error "Type $($typeGroup.Name) not expected. No installer known"
        }
    }

    if ($Import) {
        & Import-Dependency @dependencySplat
    }
} catch {
    throw
}
}