Includes/PwSh.Fw.Build.Debian.psm1

<#
.SYNOPSIS
Convert a generic hashtable into useful ControlFields metadata
 
.DESCRIPTION
Extract from an object useful properties to use as DEBIAN/control fields
 
.PARAMETER Metadata
object filled with various properties
 
.EXAMPLE
$project = gc ./project.yml -raw | convertfrom-yaml
$project | ConvertTo-DebianCONTROLFileSettings
 
This example will convert a project definition file into a useable hashtable to inject into Out-DebianCONTROLFile
 
.NOTES
General notes
 
.LINK
https://www.debian.org/doc/debian-policy/ch-relationships.html
#>

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

    Process {
        $ControlFields = @{}
        if ($Metadata) {
            if ($Metadata.Name) { $ControlFields.Package = $Metadata.Name }
            if ($Metadata.Package) { $ControlFields.Package = $Metadata.Package }
            if ($Metadata.Version) { $ControlFields.Version = [string]$Metadata.Version }
            if ($Metadata.Section) { $ControlFields.Section = $Metadata.Section }
            if ($Metadata.Priority) { $ControlFields.Priority = $Metadata.Priority }
            if ($Metadata.ProcessorArchitecture) { $ControlFields.Architecture = $Metadata.ProcessorArchitecture }
            if ($Metadata.Arch) { $ControlFields.Architecture = $Metadata.Arch }
            if ($Metadata.Architecture) { $ControlFields.Architecture = $Metadata.Architecture }
            if ($Metadata.Essential) { $ControlFields.Essential = $Metadata.Essential }
            if ($Metadata.Depends) { $ControlFields.Depends = $Metadata.Depends -join "," }
            if ($Metadata.'Pre-Depends') { $ControlFields.'Pre-Depends' = $Metadata.'Pre-Depends' }
            if ($Metadata.Recommends) { $ControlFields.Recommends = $Metadata.Recommends }
            if ($Metadata.Suggests) { $ControlFields.Suggests = $Metadata.Suggests }
            if ($Metadata.Breaks) { $ControlFields.Breaks = $Metadata.Breaks }
            if ($Metadata.Conflicts) { $ControlFields.Conflicts = $Metadata.Conflicts }
            if ($Metadata.Provides) { $ControlFields.Provides = $Metadata.Provides }
            if ($Metadata.Replaces) { $ControlFields.Replaces = $Metadata.Replaces }
            if ($Metadata.Enhances) { $ControlFields.Enhances = $Metadata.Enhances }
            if ($Metadata.Size) { $ControlFields.'Installed-Size' = $Metadata.Size }
            if ($Metadata.'Installed-Size') { $ControlFields.'Installed-Size' = $Metadata.'Installed-Size' }
            if ($Metadata.Authors) { $ControlFields.Maintainer = $Metadata.Authors[0] }
            if ($Metadata.Author) { $ControlFields.Maintainer = $Metadata.Author }
            if ($Metadata.owner) { $ControlFields.Maintainer = $Metadata.owner }
            if ($Metadata.Maintainer) { $ControlFields.Maintainer = $Metadata.Maintainer }
            if ($Metadata.Description) { $ControlFields.Description = $Metadata.Description }
            if ($Metadata.ProjectUri) { $ControlFields.Homepage = $Metadata.ProjectUri }
            if ($Metadata.ProjectUrl) { $ControlFields.Homepage = $Metadata.ProjectUrl }
        }

        return $ControlFields
    }

    End {
    }
}

<#
.SYNOPSIS
Write a debian control file
 
.DESCRIPTION
Output a fully-formated control file based on build configuration.
 
.PARAMETER Metadata
The project's properties. Properties have to be filtered with ConvertTo-DebianCONTROLFileSettings first
 
.PARAMETER Destination
Directory in wich to put the resulting control file
 
.PARAMETER PassThru
Use this switch to output the conrol content instead of its path
 
.OUTPUTS
Full path to control file
 
.OUTPUTS
control file content
 
.EXAMPLE
$project = gc ./project.yml | ConvertFrom-Yaml | ConvertTo-PSCustomObject
$project | Out-DebianCONTROLFile -Destination /tmp/DEBIAN/
 
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 debian control file.
The output of this example is "/tmp/DEBIAN/control"
 
.NOTES
    2020.03 - new version
 
.LINK
https://www.debian.org/doc/debian-policy/ch-controlfields.html
 
#>


function Out-DebianCONTROLFile {
    [CmdletBinding()][OutputType([String])]Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][object]$Metadata,
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Destination,
        [switch]$PassThru
    )
    Begin {
        Write-EnterFunction
        if ($Destination) {
            if (!(dirExist($Destination))) { $null = New-Item $Destination -Force -ItemType Directory}
        }
    }

    Process {
        $ControlFields = ConvertTo-DebianCONTROLFileSettings -Metadata $Metadata

        if ($Destination) { $ControlFields | ConvertTo-Yaml | Out-File -Path "$Destination/control" -Encoding utf8 }

        if ($PassThru) {
            return $ControlFields
        } else {
            return (Resolve-Path -Path "$Destination/control").Path
        }
    }

    End {
        Write-LeaveFunction
    }
}

<#
.SYNOPSIS
Build the project to a debian package
 
.DESCRIPTION
Build the project to a full featured Debian package.
 
.PARAMETER Project
The project
 
.PARAMETER DebianFolder
An optional DEBIAN folder where debian package scripts are stored. Scripts can be 'pre', 'post', whatever described at @url https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html
 
.PARAMETER Source
The source folder of your project. Files and directory structure will be kept as-is
 
.PARAMETER Destination
Destination folder to create resulting package
 
.EXAMPLE
New-DebianBuild -Project (Get-Project)
 
.NOTES
The resulting package will be named after project's data :
`$name-$version-$arch.deb`
 
#>

function New-DebianBuild {
    [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low', DefaultParameterSetName = 'PROJECT')]
    [OutputType([Boolean], [String])]
    Param (
        [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][hashtable]$Project,
        [Alias('Configuration')]
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$DebianFolder,
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Source = "./src",
        [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Destination = "./releases",
        [switch]$Force
    )
    Begin {
        Write-EnterFunction
        if (!(Test-DirExist $Destination)) {
            $null = New-Item -Path $Destination -ItemType Directory -Confirm:$false -Force:$Force
        }
    }

    Process {
        if ($DebianFolder) {
            Copy-Item $DebianFolder -Recurse $Source
        }
        $Filename = "$($project.name)-$($project.Version)$($project.PreRelease)-$($project.arch).deb"
        $project.size = (Get-ChildItem $Source -Recurse | Measure-Object -Property Length -sum).Sum | Convert-Size -From bytes -To KB
        $null = $project | Out-DebianCONTROLFile -Destination $Source/DEBIAN
        $null = Get-Command -Name fakeroot || efatal "fakeroot command not found in system. Try to install the fakeroot package."
        if ($PSCmdlet.ShouldProcess("$Destination/$Filename", "Create debian package")) {
            $rc = eexec -exe fakeroot -args "dpkg -b $Source $Destination/$Filename"
            if ($rc -eq $true) {
                $value = (Resolve-Path "$Destination/$Filename").Path
            } else {
                $value = $false
            }
        } else {
            $value = "$Destination/$Filename"
        }

        return $value
    }

    End {
        Write-LeaveFunction
    }
}