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 = "./build/DEBIAN", [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 (Test-DirExist $DebianFolder) { Copy-Item $DebianFolder -Recurse $Source -Force:$Force } $project.size = (Get-ChildItem $Source -Recurse | Measure-Object -Property Length -sum).Sum | Convert-Size -From bytes -To KB $ControlFields = $project | Out-DebianCONTROLFile -Destination $Source/DEBIAN -PassThru $Filename = "$($project.name)-$($ControlFields.Version)$($project.PreRelease)-$($ControlFields.architecture).deb" $null = Get-Command -Name fakeroot || Write-Fatal "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" Write-Devel "rc = $rc" if ($rc -eq $true) { $value = (Resolve-Path "$Destination/$Filename").Path } else { $value = $false } } else { $value = "$Destination/$Filename" } Write-Devel "value = $value" return $value } End { Write-LeaveFunction } } <# .SYNOPSIS Create a linux desktop shortcut .DESCRIPTION Create a linux desktop shortcut. Use it before the building process to create static desktop entry file. Use it in the building process to create dynamic desktop entry file .PARAMETER Project Metadata of the project .PARAMETER Destination Destination folder .PARAMETER Filename Destination filename .PARAMETER Exec Fill shortcut's Exec key .PARAMETER Icon Attach Icon to shortcut. File must be present on target system. Icon must be an absolute pathname on the target. .PARAMETER Terminal Set to True if the shortcut must launch in a terminal .PARAMETER Force Force things .EXAMPLE New-DesktopFile -Project $project -Destination /usr/share/applications -filename project.desktop .NOTES help @url https://developer.gnome.org/integration-guide/stable/desktop-files.html.en Desktop Entry Specifications https://specifications.freedesktop.org/desktop-entry-spec/latest/index.html #> function New-DesktopFile { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Low')] [OutputType([String])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][hashtable]$Project, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Destination = "./usr/share/applications", [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Filename, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Exec, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Icon, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][switch]$Terminal, [switch]$Force ) Begin { Write-EnterFunction } Process { if ($PSCmdlet.ShouldProcess("$Destination/$Filename", "Create linux desktop shortcut")) { if (!(Test-DirExist $Destination)) { $null = New-Item -Path "$Destination/$Filename" -ItemType Directory -Force:$Force } if ([string]::IsNullOrEmpty($Filename)) { $Filename = "$($Project.Name).desktop" } if ([string]::IsNullOrEmpty($Project.DisplayName)) { ewarn "DisplayName is not defined. Using Name instead. Please consider defining a DisplayName in project's yaml file." $Name = $Project.Name } else { $Name = $Project.DisplayName } @" [Desktop Entry] Type=Application Encoding=UTF-8 Name=$Name Comment=$($Project.Description) Exec=$Exec Icon=$Icon Terminal=$Terminal "@ | Set-Content "$Destination/$Filename" -Encoding utf8NoBOM -Force:$Force return (Resolve-Path "$Destination/$Filename").Path } else { return "$Destination/$Filename" } } End { Write-LeaveFunction } } <# .SYNOPSIS Convert an image to different sizes to fit on linux desktop managers .DESCRIPTION Convert an image to multiple sizes at once for linux desktop .PARAMETER Image Full path to an image file .PARAMETER Destination Destination folder .PARAMETER Filename Optional. New filename of the image .PARAMETER OutputStyle Select output style structure : - Flat : output images right under $Destination with files renamed after the size -> %filename-%size.%ext - Scattered : create a subdirectory for each size under $Destination -> %size/%filename.%ext Defaults to 'Scattered' .EXAMPLE ConvertTo-LinuxIcons -Image /path/to/favicon.png -Destination /usr/share/icons/hicolor .NOTES This function do not convert image into another format. It just convert size. #> function ConvertTo-LinuxIcons { [CmdletBinding()] [OutputType([Boolean])] Param ( [Parameter(Mandatory = $true, ValueFromPipeLine = $true)][string]$Image, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Destination, [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$Filename, [ValidateSet('Flat', 'Scattered')] [Parameter(Mandatory = $false, ValueFromPipeLine = $false)][string]$OutputStyle = 'Scattered' ) Begin { Write-EnterFunction } Process { if (!(Test-FileExist $Image)) { eerror "Image '$Image' not found." return $false } $basename = (Get-Item $Image).BaseName $ext = (Get-Item $Image).Extension if ([string]::IsNullOrEmpty($Filename)) { $Filename = $basename } if ([string]::IsNullOrEmpty($Destination)) { $Destination = (Get-Item $Image).DirectoryName } $IconSize= @('16x16', '32x32', '48x48', '64x64', '128x128', '256x256', '512x512') foreach($s in $IconSize) { switch ($OutputStyle) { 'Flat' { $null = New-Item -Path $Destination -Force -ItemType Directory -ErrorAction SilentlyContinue Execute-Command -exe "convert" -args "$Image -resize $s $Destination/$Filename-$s$ext" } 'Scattered' { $null = New-Item -Path $Destination/$s -Force -ItemType Directory -ErrorAction SilentlyContinue Execute-Command -exe "convert" -args "$Image -resize $s $Destination/$s/$Filename$ext" } } } return $true } End { Write-LeaveFunction } } |