Includes/PwSh.Fw.Build.Windows.psm1


if (!($Script:PWSHFW_BUILDHELPERS_DIR)) {
    $Script:PWSHFW_BUILDHELPERS_DIR = (Resolve-Path $PSScriptRoot/../).Path
}

<#
.SYNOPSIS
Convert a generic hashtable into useful NSIS Settings metadata
 
.DESCRIPTION
Extract from an object useful properties to use as NSIS constants
 
.PARAMETER Metadata
object filled with various properties
 
.EXAMPLE
$project = gc ./project.yml -raw | convertfrom-yaml
$project | ConvertTo-NullSoftInstallerSettings
 
This example will convert a project definition file into a useable hashtable to inject into Out-NSISSetupFile
 
.NOTES
General notes
#>

function ConvertTo-NullSoftInstallerSettings {
    [CmdletBinding()][OutputType([hashtable])]Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][object]$Metadata
    )
    Begin {
    }

    Process {
        $NSISSettings = @{}
        if ($Metadata) {
            if ($Metadata.name) { $NSISSettings.Name = $Metadata.name }
            if ($Metadata.Version) { $NSISSettings.Version = $Metadata.Version }
            if ($Metadata.GUID) { $NSISSettings.GUID = $Metadata.GUID }
            if ($Metadata.Authors) { $NSISSettings.Author = $Metadata.Authors[0] }
            if ($Metadata.Author) { $NSISSettings.Author = $Metadata.Author }
            if ($Metadata.owner) { $NSISSettings.Author = $Metadata.owner }
            if ($Metadata.CompanyName) { $NSISSettings.CompanyName = $Metadata.CompanyName }
            if ($Metadata.Copyright) { $NSISSettings.Copyright = $Metadata.Copyright }
            if ($Metadata.Description) { $NSISSettings.Description = $Metadata.Description }
            if ($Metadata.ProcessorArchitecture) { $NSISSettings.Architecture = $Metadata.ProcessorArchitecture }
            if ($Metadata.Architecture) { $NSISSettings.Architecture = $Metadata.Architecture }
            if ($Metadata.Arch) { $NSISSettings.Architecture = $Metadata.Arch }
            if ($Metadata.ProjectUri) { $NSISSettings.ProjectUri = $Metadata.ProjectUri }
            if ($Metadata.ProjectUrl) { $NSISSettings.ProjectUri = $Metadata.ProjectUrl }
            if ($Metadata.LicenseUri) { $NSISSettings.LicenseUri = $Metadata.LicenseUri }
            if ($Metadata.LicenseUrl) { $NSISSettings.LicenseUri = $Metadata.LicenseUrl }
            if ($Metadata.IconUri) { $NSISSettings.IconUri = $Metadata.IconUri }
            if ($Metadata.IconUrl) { $NSISSettings.IconUri = $Metadata.IconUrl }
            # if we are in a prerelease, concat Version and Build to get a 4-dotted version number for NSIS
            if ($Metadata.Prerelease) { $NSISSettings.Version = "$($Metadata.Version).$($Metadata.Build)" }
        }

        return $NSISSettings
    }

    End {
    }
}

<#
.SYNOPSIS
Write a NSIS setup header file
 
.DESCRIPTION
Output a fully-formated NSIS setup header file based on build configuration.
 
.PARAMETER Metadata
The project's properties. Properties have to be filtered with ConvertTo-NullSoftInstallerSettings first
 
.PARAMETER Destination
Directory in wich to put the resulting header file. The filename will be named header.nsi
 
.PARAMETER PassThru
Use this switch to output the content of the resulting file instead of its path
 
.OUTPUTS
Full path to header file
 
.OUTPUTS
header file content
 
.EXAMPLE
$project = gc ./project.yml | ConvertFrom-Yaml | ConvertTo-PSCustomObject
$project | Out-NullSoftInstallerScriptHeaderFile -Destination ./build/windows/
 
This example use a project.yml file filled with "key: pair" values, convert it to an object, an use its properties to output a well-formated NSIS header file.
The output of this example is "./build/windows/header.nsi"
 
#>

function Out-NullSoftInstallerScriptHeaderFile {
    [CmdletBinding()]Param (
        [Parameter(Mandatory = $true,ValueFromPipeLine = $true)][hashtable]$Metadata,
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Destination,
        [switch]$PassThru
    )
    Begin {
        if (!(Test-DirExist $Destination)) {
            $null = New-Item -Path $Destination -ItemType Directory
        }
        $Filename = "$Destination/header.nsi"
    }

    Process {

        $NSISSettings = ConvertTo-NullSoftInstallerSettings -Metadata $Metadata

        "" | Set-Content $Filename -Encoding utf8
        foreach ($k in $NSISSettings.Keys) {
            "!define $($k.ToUpper()) '$($NSISSettings.$k)'" | Out-File -FilePath $Filename -Encoding utf8 -Append
        }

        if ($PassThru) {
            return $NSISSettings
        } else {
            return (Resolve-Path -Path "$Filename").Path
        }
    }

    End {
    }
}

function Test-NSISBuild {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(Mandatory = $true,ValueFromPipeLine = $true)][hashtable]$Project
    )
    Begin {
        # Write-EnterFunction
    }

    Process {
        $rc = $true
        foreach ($f in @('LICENSE', "$($Project.Root)/images/favicon.ico")) {
            if (Test-Path $Path/$f -PathType Leaf) {
                Write-Host -ForegroundColor Green "[+] $((Resolve-Path $Path/$f).Path) exist"
            } else {
                Write-Host -ForegroundColor Red "[-] $Path/$f does not exist"
                $rc = $false
            }
        }

        return $rc
    }

    End {
        # Write-LeaveFunction
    }
}

function New-NSISBuild {
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low', DefaultParameterSetName = 'PROJECT')]
    [OutputType([Boolean], [String])]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true, ParameterSetName = 'PROJECT')][hashtable]$Project,
        [Alias('Header')]
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false, ParameterSetName = 'CUSTOM')][string]$HeaderNSI,
        [Alias('Configuration')]
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false, ParameterSetName = 'CUSTOM')][string]$SetupNSI = (Resolve-Path "$($Script:PWSHFW_BUILDHELPERS_DIR)/Assets/setup.nsi").Path,
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Source = "./src",
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Destination = "./releases"
    )
    Begin {
        Write-EnterFunction
        if (!(Test-DirExist $Destination)) {
            $null = New-Item -Path $Destination -ItemType Directory
        }
    }

    Process {
        # Write-Host "Project = $Project"
        # Write-Host "HeaderNSI = $HeaderNSI"
        # Write-Host "SetupNSI = $SetupNSI"
        # Write-Host "PWSHFW_BUILDHELPERS_DIR = $PWSHFW_BUILDHELPERS_DIR"
        # Write-Host "PWSHFW_BUILDHELPERS_DIR = $Script:PWSHFW_BUILDHELPERS_DIR"
        if (!($HeaderNSI)) {
            $HeaderNSI = $Project | Out-NullSoftInstallerScriptHeaderFile -Destination $Project.Root
        }
        $Filename = "$($Project.Name)-$($Project.Version)$($Project.PreRelease)"
        if ($Project.Architecture) { $Filename += "-$($Project.Architecture)" }
        $Filename += ".exe"
        # discover where is nsis.exe
        if (fileExist($(${env:ProgramFiles(x86)} + "\NSIS\makensis.exe"))) { $MAKENSIS = "$(${env:ProgramFiles(x86)})\NSIS\makensis.exe" }
        if (fileExist($(${env:ProgramFiles} + "\NSIS\makensis.exe"))) { $MAKENSIS = "$($env:ProgramFiles)\NSIS\makensis.exe)" }
        if (!$MAKENSIS) {
            eerror("makensis.exe not found. Please install it first. Visit https://nsis.sourceforge.io/Main_Page")
            return $false
        }
        # compute debug level
        [uint16]$debugLevel = 0
        if (($INFO) -or ($InformationPreference -eq 'Continue')) { $debugLevel = 1 }
        if (($VERBOSE) -or ($VerbosePreference -eq 'Continue')) { $debugLevel = 2 }
        if (($DEBUG) -or ($DebugPreference -eq 'Continue')) { $debugLevel = 3 }
        if (($DEVEL) -or ($DevelPreference -eq 'Continue')) { $debugLevel = 4 }

        if ($PSCmdlet.ShouldProcess("$Destination/$Filename", "Create NSIS setup file")) {
            $rc = eexec -exe "$MAKENSIS" "/V$debugLevel /INPUTCHARSET UTF8 /OUTPUTCHARSET UTF8 /D'SOURCE=$Source' /D'ROOT=$($Project.Root)' '$HeaderNSI' /X'OutFile $Destination/$Filename' '$SetupNSI'"
            if ($rc) {
                return (Resolve-Path "$Destination/$Filename").Path
            } else {
                return $false
            }
        } else {
            return "$Destination/$Filename"
        }
    }

    End {
        Write-LeaveFunction
    }
}