Includes/PwSh.Fw.Build.Windows.Cab.psm1

<#
.SYNOPSIS
Write a Cabinet Definition File (ddf)
 
.DESCRIPTION
Output a fully-formated Cabinet Definition File based on build configuration.
It follow Microsoft specifications.
 
.EXAMPLE
Get-Project | Out-CabinetDefinitionFile -Destination ./build/
 
.NOTES
General notes
#>

function Out-CabinetDefinitionFile {
    [CmdletBinding()][OutputType([String])]Param (
        # The project's properties
        [Parameter(Mandatory = $true,ValueFromPipeLine = $true)][hashtable]$Metadata,
        # The source folder of your project. Files and directory structure will be kept as-is
        [Parameter(Mandatory = $true, ValueFromPipeLine = $false)][string]$Source,
        #Directory in which to put the resulting definition file
        [Parameter(Mandatory = $true,ValueFromPipeLine = $false)][string]$Destination,
        # Override output package filename.
        # It defaults to projectName-Version.cab
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$OutputFileName
    )
    Begin {
        if (!(Test-DirExist $Destination)) {
            $null = New-Item -Path $Destination -ItemType Directory
        }
        if ([string]::IsNullOrEmpty($OutputFileName)) {
            $shortName = $Metadata.Name -Replace " "
            $Filename = "$Destination/$shortName-$($Metadata.Version).ddf"
        } else {
            $Filename = $OutputFileName
        }
    }

    Process {
@"
; @url https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/makecab
; @url https://msdn.microsoft.com/en-us/library/bb417343.aspx#dir_file_syntax
; @url https://ss64.com/nt/makecab.html
; to build a cabinet archive using this definition file, you have to provide 3 variables on command line :
; makecab.exe /F "$Filename" /D SourceDir=$Source /D CabinetNameTemplate=$shortName-$($Metadata.Version).cab /D DiskDirectoryTemplate=$Destination
; or
; makecab.exe /F "$Filename"
.Set SourceDir=$Source
.Set CabinetNameTemplate=$shortName-$($Metadata.Version).cab
.Set DiskDirectoryTemplate=$Destination
.Set DiskLabelTemplate=$shortName
.Set Cabinet=on
.Set Compress=on
.Set UniqueFiles=off
"@
 | Out-File -FilePath "$Filename" -Encoding utf8 -Append:$false

        # get a list of directories containing files
        (Get-ChildItem $Source -Recurse -Directory).FullName | Sort-Object -Unique | ForEach-Object {
            # process files accordingly
            ".Set DestinationDir=$($_.Replace($Source, ''))" | Out-File -FilePath "$FileName" -Encoding utf8 -Append
            (Get-ChildItem "$Source/$_" -File).FullName.Replace($Source, '') | Out-File -FilePath "$FileName" -Encoding utf8 -Append
        }

        if ($PassThru) {
            return (Get-Content -Raw $Filename)
        } else {
            return (Resolve-Path -Path "$Filename").Path
        }
    }

    End {
    }
}

<#
.SYNOPSIS
Build the project to a cab archive
 
.DESCRIPTION
Build the project to a Microsoft cabinet file
 
.EXAMPLE
New-CabinetFile -Project (Get-Project)
 
.NOTES
General notes
#>

function New-CabinetFile {
    [CmdletBinding()]
    [OutputType([String])]
    Param (
        # Project to build
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][hashtable]$Project,
        # An optional custom Cabinet definition file. Leave empty to automatically build one
        [Alias('DDF')]
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$DefinitionFile,
        # Folder containing windows stuffs to include
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$WindowsFolder = './build/Windows',
        # The source folder of your project. Files and directory structure will be kept as-is
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Source = "./src",
        # Destination folder to create resulting cabinet
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Destination = "./releases",
        # Override output package filename.
        # It defaults to projectName-Version-Arch.cab
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$OutputFileName
    )
    Begin {
        Write-EnterFunction
        if (!(Test-DirExist $Destination)) {
            $null = New-Item -Path $Destination -ItemType Directory
        }
    }

    Process {
        if (!$DefinitionFile) {
            $DefinitionFile = $Project | Out-CabinetDefinitionFile -Source $Source -Destination $Destination -OutputFileName $OutputFileName
        }

        if (Get-Command makecab.exe) {
            $rc = Execute-Command -exe makecab.exe /F "$DefinitionFile"
        } else {
            Write-Error "makecab.exe not found."
        }
    }

    End {
        Write-LeaveFunction
    }
}