functions/Get-EndjinGist.ps1

# <copyright file="Get-EndjinGist.ps1" company="Endjin Limited">
# Copyright (c) Endjin Limited. All rights reserved.
# </copyright>

<#
.SYNOPSIS
    Downloads gist content from a Git repository using vendir.
 
.DESCRIPTION
    The Get-EndjinGist function downloads gist content from a specified group and name
    using the vendir tool. It reads available gists from a YAML configuration file,
    generates a vendir configuration, and synchronizes the content to a local directory.
 
.PARAMETER Group
    The group name containing the gist. This must match a key in the Gist Map configuration file.
 
.PARAMETER Name
    The name of the specific gist to download within the specified group.
 
.PARAMETER DestinationBaseDir
    The destination path for the downloaded gist content. The remainder of the destination path is
    derived from the Gist 'Group' and 'Name'.
 
.PARAMETER GistMapPath
    The path to a 'Gist Map' configuration file. Defaults to the configuration file
    distributed with the module (gist-map.yml).
 
.EXAMPLE
    Get-EndjinGist -Group "azure" -Name "deploy-script"
 
    Downloads the 'deploy-script' gist from the 'azure' group to the default location.
 
.EXAMPLE
    Get-EndjinGist -Group "common" -Name "logging" -Verbose
 
    Downloads the 'logging' gist from the 'common' group with verbose output enabled.
 
.NOTES
    Requires the 'vendir' tool to be installed and available in the PATH.
    The function creates a temporary .endjin-gists.yml file which is cleaned up
    after successful execution (unless Verbose mode is enabled).
 
.LINK
    https://carvel.dev/vendir/
#>

function Get-EndjinGist {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory, Position=0)]
        [string] $Group,

        [Parameter(Mandatory, Position=1)]
        [string] $Name,

        [Parameter()]
        [string] $DestinationBaseDir = '.endjin',

        [Parameter()]
        [string] $GistMapPath = (Join-Path $PSScriptRoot '..' 'gist-map.yml')
    )

    begin {
        Set-StrictMode -Version Latest

        if (!(Get-Command 'vendir' -ErrorAction SilentlyContinue)) {
            throw "Please install 'vendir' to your PATH before using this tool."
        }

        $availableGists = Get-Content $GistMapPath | ConvertFrom-Yaml
        Write-Verbose "Available gists:`n$($availableGists | ConvertTo-Json -Depth 5)"

        if (!$availableGists.ContainsKey($Group)) {
            throw "Unknown gist group: $Group"
        }

        $vendirConfig = [ordered]@{
            apiVersion = 'vendir.k14s.io/v1alpha1'
            kind = 'Config'
            directories = @()
        }
    }
    
    process {
        $gistConfig = $availableGists[$Group] | Where-Object { $_.name -eq $Name }
        if (!$gistConfig) {
            throw "Unknown gist '$Name' in group '$Group'"
        }

        Write-Information "⚙️ Processing '$Name' from group '$Group'"
        $directoryConfig =  [ordered]@{
            path = "$DestinationBaseDir/$Group/$Name"
            contents = @(
                @{
                    path = '.'
                    git = [ordered]@{
                        url = $gistConfig.source
                        ref = $gistConfig.ref
                    }
                    includePaths = [array]($gistConfig.includePaths)
                }
            )
        }

        if ($gistConfig.ContainsKey('sourceDirectory')) {
            $directoryConfig.contents[0] += @{ newRootPath = $gistConfig.sourceDirectory }
        }

        $vendirConfig.directories += [array]$directoryConfig
    }
    
    end {
        $vendirFilename = '.endjin-gists.yml'
        $outputPath = Join-Path $PWD $vendirFilename
        
        ConvertTo-Yaml -Data $vendirConfig -OutFile $outputPath -Force
        Write-Verbose "Generated vendir.yml:`n$(Get-Content $outputPath | ConvertFrom-Yaml -Ordered | ConvertTo-Json -Depth 5)"

        Write-Information "⌛ Downloading gists..."
        $PSNativeCommandUseErrorActionPreference = $false
        $result = Invoke-Command { & vendir sync --file $vendirFilename 2>&1 }
        $result | Write-Verbose

        if ($LASTEXITCODE -ne 0) {
            if ($result -imatch 'Access is denied') {
                Write-Host -f Red @"
Operation failed due to potential file contention with VSCode, please add the following to your VSCode settings:
`n`"files.watcherExclude`": {
`t`"**/.vendir-tmp-*/**`": true
}`n
"@

            }
            else {
                throw "Operation failed with exit code $LASTEXITCODE.`n$result"
            }
        }

        if ($VerbosePreference -eq 'SilentlyContinue') {
            Remove-Item $outputPath
            Remove-Item (Join-Path (Split-Path -Parent $outputPath) 'vendir.lock.yml')
        }

        Write-Information "✅ Completed successfully."
    }
}