mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Replace fpm with dpkg-deb for DEB package generation (#26281)
This commit is contained in:
+25
-51
@@ -2234,43 +2234,6 @@ function Get-RedHatPackageManager {
|
||||
}
|
||||
}
|
||||
|
||||
function Install-GlobalGem {
|
||||
param(
|
||||
[Parameter()]
|
||||
[string]
|
||||
$Sudo = "",
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string]
|
||||
$GemName,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[string]
|
||||
$GemVersion
|
||||
)
|
||||
try {
|
||||
# We cannot guess if the user wants to run gem install as root on linux and windows,
|
||||
# but macOs usually requires sudo
|
||||
$gemsudo = ''
|
||||
if($environment.IsMacOS -or $env:TF_BUILD -or $env:GITHUB_ACTIONS) {
|
||||
$gemsudo = $sudo
|
||||
}
|
||||
|
||||
Start-NativeExecution ([ScriptBlock]::Create("$gemsudo gem install $GemName -v $GemVersion --no-document"))
|
||||
|
||||
} catch {
|
||||
Write-Warning "Installation of gem $GemName $GemVersion failed! Must resolve manually."
|
||||
$logs = Get-ChildItem "/var/lib/gems/*/extensions/x86_64-linux/*/$GemName-*/gem_make.out" | Select-Object -ExpandProperty FullName
|
||||
foreach ($log in $logs) {
|
||||
Write-Verbose "Contents of: $log" -Verbose
|
||||
Get-Content -Raw -Path $log -ErrorAction Ignore | ForEach-Object { Write-Verbose $_ -Verbose }
|
||||
Write-Verbose "END Contents of: $log" -Verbose
|
||||
}
|
||||
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
function Start-PSBootstrap {
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
@@ -2282,7 +2245,7 @@ function Start-PSBootstrap {
|
||||
[switch]$BuildLinuxArm,
|
||||
[switch]$Force,
|
||||
[Parameter(Mandatory = $true)]
|
||||
# Package: Install dependencies for packaging tools (fpm, rpmbuild, WiX)
|
||||
# Package: Install dependencies for packaging tools (rpmbuild, dpkg-deb, pkgbuild, WiX)
|
||||
# DotNet: Install the .NET SDK
|
||||
# Both: Package and DotNet scenarios
|
||||
# Tools: Install .NET global tools (e.g., dotnet-format)
|
||||
@@ -2321,7 +2284,9 @@ function Start-PSBootstrap {
|
||||
elseif ($environment.IsUbuntu18) { $Deps += "libicu60"}
|
||||
|
||||
# Packaging tools
|
||||
if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-dev", "groff", "libffi-dev", "rpm", "g++", "make" }
|
||||
# Note: ruby-dev, libffi-dev, g++, and make are no longer needed for DEB packaging
|
||||
# DEB packages now use native dpkg-deb (pre-installed)
|
||||
if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "groff", "rpm" }
|
||||
|
||||
# Install dependencies
|
||||
# change the fontend from apt-get to noninteractive
|
||||
@@ -2345,7 +2310,9 @@ function Start-PSBootstrap {
|
||||
$Deps += "libicu", "openssl-libs"
|
||||
|
||||
# Packaging tools
|
||||
if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpm-build", "groff", 'libffi-devel', "gcc-c++" }
|
||||
# Note: ruby-devel and libffi-devel are no longer needed
|
||||
# RPM packages use rpmbuild, DEB packages use dpkg-deb
|
||||
if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpm-build", "groff" }
|
||||
|
||||
$PackageManager = Get-RedHatPackageManager
|
||||
|
||||
@@ -2366,7 +2333,8 @@ function Start-PSBootstrap {
|
||||
$Deps += "wget"
|
||||
|
||||
# Packaging tools
|
||||
if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "ruby-devel", "rpmbuild", "groff", 'libffi-devel', "gcc" }
|
||||
# Note: ruby-devel and libffi-devel are no longer needed for packaging
|
||||
if ($Scenario -eq 'Both' -or $Scenario -eq 'Package') { $Deps += "rpmbuild", "groff" }
|
||||
|
||||
$PackageManager = "zypper --non-interactive install"
|
||||
$baseCommand = "$sudo $PackageManager"
|
||||
@@ -2405,17 +2373,7 @@ function Start-PSBootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
# Install [fpm](https://github.com/jordansissel/fpm)
|
||||
# Note: fpm is now only needed for DEB and macOS packages; RPM packages use rpmbuild directly
|
||||
if ($Scenario -in 'All', 'Both', 'Package') {
|
||||
# Install fpm on Debian-based systems, macOS, and Mariner (where DEB packages are built)
|
||||
if (($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) -or $environment.IsMacOS) {
|
||||
Install-GlobalGem -Sudo $sudo -GemName "dotenv" -GemVersion "2.8.1"
|
||||
Install-GlobalGem -Sudo $sudo -GemName "ffi" -GemVersion "1.16.3"
|
||||
Install-GlobalGem -Sudo $sudo -GemName "fpm" -GemVersion "1.15.1"
|
||||
Install-GlobalGem -Sudo $sudo -GemName "rexml" -GemVersion "3.2.5"
|
||||
}
|
||||
|
||||
# For RPM-based systems, ensure rpmbuild is available
|
||||
if ($environment.IsLinux -and ($environment.IsRedHatFamily -or $environment.IsSUSEFamily -or $environment.IsMariner)) {
|
||||
Write-Verbose -Verbose "Checking for rpmbuild..."
|
||||
@@ -2424,6 +2382,22 @@ function Start-PSBootstrap {
|
||||
Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y rpm-build")) -IgnoreExitcode
|
||||
}
|
||||
}
|
||||
|
||||
# For Debian-based systems and Mariner, ensure dpkg-deb is available
|
||||
if ($environment.IsLinux -and ($environment.IsDebianFamily -or $environment.IsMariner)) {
|
||||
Write-Verbose -Verbose "Checking for dpkg-deb..."
|
||||
if (!(Get-Command dpkg-deb -ErrorAction SilentlyContinue)) {
|
||||
Write-Warning "dpkg-deb not found. Installing dpkg package..."
|
||||
if ($environment.IsMariner) {
|
||||
# For Mariner (Azure Linux), install the extended repo first to access dpkg.
|
||||
Write-Verbose -Verbose "Installing azurelinux-repos-extended for Mariner..."
|
||||
Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y azurelinux-repos-extended")) -IgnoreExitcode
|
||||
Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo $PackageManager install -y dpkg")) -IgnoreExitcode
|
||||
} else {
|
||||
Start-NativeExecution -sb ([ScriptBlock]::Create("$sudo apt-get install -y dpkg")) -IgnoreExitcode
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,7 @@ Describe "Linux Package Name Validation" {
|
||||
It "Should have valid RPM package names" {
|
||||
$rpmPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.rpm -ErrorAction SilentlyContinue
|
||||
|
||||
if ($rpmPackages.Count -eq 0) {
|
||||
Set-ItResult -Skipped -Because "No RPM packages found in artifacts directory"
|
||||
return
|
||||
}
|
||||
$rpmPackages.Count | Should -BeGreaterThan 0 -Because "At least one RPM package should exist in the artifacts directory"
|
||||
|
||||
$invalidPackages = @()
|
||||
# Regex pattern for valid RPM package names.
|
||||
@@ -49,8 +46,42 @@ Describe "Linux Package Name Validation" {
|
||||
if ($invalidPackages.Count -gt 0) {
|
||||
throw ($invalidPackages | Out-String)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "DEB Package Names" {
|
||||
It "Should have valid DEB package names" {
|
||||
$debPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.deb -ErrorAction SilentlyContinue
|
||||
|
||||
$rpmPackages.Count | Should -BeGreaterThan 0
|
||||
$debPackages.Count | Should -BeGreaterThan 0 -Because "At least one DEB package should exist in the artifacts directory"
|
||||
|
||||
$invalidPackages = @()
|
||||
# Regex pattern for valid DEB package names.
|
||||
# Valid examples:
|
||||
# - powershell-preview_7.6.0-preview.6-1.deb_amd64.deb
|
||||
# - powershell-lts_7.4.13-1.deb_amd64.deb
|
||||
# - powershell_7.4.13-1.deb_amd64.deb
|
||||
# Breakdown:
|
||||
# ^powershell : Starts with 'powershell'
|
||||
# (-preview|-lts)? : Optionally '-preview' or '-lts'
|
||||
# _\d+\.\d+\.\d+ : Underscore followed by version number (e.g., _7.6.0)
|
||||
# (-[a-z]+\.\d+)? : Optional dash, letters, dot, and digits (e.g., -preview.6)
|
||||
# -1 : Literal '-1'
|
||||
# \.deb_ : Literal '.deb_'
|
||||
# (amd64|arm64) : Architecture
|
||||
# \.deb$ : File extension
|
||||
$debPackageNamePattern = '^powershell(-preview|-lts)?_\d+\.\d+\.\d+(-[a-z]+\.\d+)?-1\.deb_(amd64|arm64)\.deb$'
|
||||
|
||||
foreach ($package in $debPackages) {
|
||||
if ($package.Name -notmatch $debPackageNamePattern) {
|
||||
$invalidPackages += "$($package.Name) is not a valid DEB package name"
|
||||
Write-Warning "$($package.Name) is not a valid DEB package name"
|
||||
}
|
||||
}
|
||||
|
||||
if ($invalidPackages.Count -gt 0) {
|
||||
throw ($invalidPackages | Out-String)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +89,7 @@ Describe "Linux Package Name Validation" {
|
||||
It "Should have valid tar.gz package names" {
|
||||
$tarPackages = Get-ChildItem -Path $artifactsDir -Recurse -Filter *.tar.gz -ErrorAction SilentlyContinue
|
||||
|
||||
if ($tarPackages.Count -eq 0) {
|
||||
Set-ItResult -Skipped -Because "No tar.gz packages found in artifacts directory"
|
||||
return
|
||||
}
|
||||
$tarPackages.Count | Should -BeGreaterThan 0 -Because "At least one tar.gz package should exist in the artifacts directory"
|
||||
|
||||
$invalidPackages = @()
|
||||
foreach ($package in $tarPackages) {
|
||||
@@ -76,8 +104,6 @@ Describe "Linux Package Name Validation" {
|
||||
if ($invalidPackages.Count -gt 0) {
|
||||
throw ($invalidPackages | Out-String)
|
||||
}
|
||||
|
||||
$tarPackages.Count | Should -BeGreaterThan 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+253
-209
@@ -1199,8 +1199,6 @@ function New-UnixPackage {
|
||||
# Generate After Install and After Remove scripts
|
||||
$AfterScriptInfo = New-AfterScripts -Link $Link -Distribution $DebDistro -Destination $Destination
|
||||
|
||||
# Note: The fpm symlink workaround is no longer needed with native macOS packaging tools
|
||||
|
||||
# Generate gzip of man file
|
||||
$ManGzipInfo = New-ManGzip -IsPreview:$IsPreview -IsLTS:$LTS
|
||||
|
||||
@@ -1319,6 +1317,33 @@ function New-UnixPackage {
|
||||
throw
|
||||
}
|
||||
}
|
||||
} elseif ($Type -eq 'deb') {
|
||||
# Use native DEB package builder
|
||||
if ($PSCmdlet.ShouldProcess("Create DEB package natively")) {
|
||||
Write-Log "Creating DEB package natively..."
|
||||
try {
|
||||
$result = New-NativeDeb `
|
||||
-Name $Name `
|
||||
-Version $packageVersion `
|
||||
-Iteration $Iteration `
|
||||
-Description $Description `
|
||||
-Staging $Staging `
|
||||
-Destination $Destination `
|
||||
-ManGzipFile $ManGzipInfo.GzipFile `
|
||||
-ManDestination $ManGzipInfo.ManFile `
|
||||
-LinkInfo $Links `
|
||||
-Dependencies $Dependencies `
|
||||
-AfterInstallScript $AfterScriptInfo.AfterInstallScript `
|
||||
-AfterRemoveScript $AfterScriptInfo.AfterRemoveScript `
|
||||
-HostArchitecture $HostArchitecture `
|
||||
-CurrentLocation $CurrentLocation
|
||||
|
||||
$Output = @("Created package {:path=>""$($result.PackageName)""}")
|
||||
}
|
||||
catch {
|
||||
Write-Verbose -Message "!!!Handling error in native DEB creation!!!" -Verbose -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
} elseif ($Type -eq 'osxpkg') {
|
||||
# Use native macOS packaging tools
|
||||
if ($PSCmdlet.ShouldProcess("Create macOS package with pkgbuild/productbuild")) {
|
||||
@@ -1350,40 +1375,8 @@ function New-UnixPackage {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# Use fpm for DEB packages
|
||||
$Arguments = @()
|
||||
|
||||
$Arguments += Get-FpmArguments `
|
||||
-Name $Name `
|
||||
-Version $packageVersion `
|
||||
-Iteration $Iteration `
|
||||
-Description $Description `
|
||||
-Type $Type `
|
||||
-Dependencies $Dependencies `
|
||||
-AfterInstallScript $AfterScriptInfo.AfterInstallScript `
|
||||
-AfterRemoveScript $AfterScriptInfo.AfterRemoveScript `
|
||||
-Staging $Staging `
|
||||
-Destination $Destination `
|
||||
-ManGzipFile $ManGzipInfo.GzipFile `
|
||||
-ManDestination $ManGzipInfo.ManFile `
|
||||
-LinkInfo $Links `
|
||||
-AppsFolder $AppsFolder `
|
||||
-Distribution $DebDistro `
|
||||
-HostArchitecture $HostArchitecture `
|
||||
-ErrorAction Stop
|
||||
|
||||
if ($PSCmdlet.ShouldProcess("Create $type package")) {
|
||||
Write-Log "Creating package with fpm $Arguments..."
|
||||
try {
|
||||
$Output = Start-NativeExecution { fpm $Arguments }
|
||||
}
|
||||
catch {
|
||||
Write-Verbose -Message "!!!Handling error in FPM!!!" -Verbose -ErrorAction SilentlyContinue
|
||||
Write-Verbose -Message "$Output" -Verbose -ErrorAction SilentlyContinue
|
||||
Get-Error -InputObject $_
|
||||
throw
|
||||
}
|
||||
}
|
||||
# Nothing should reach here
|
||||
throw "Unknown package type: $Type"
|
||||
}
|
||||
} finally {
|
||||
if ($Environment.IsMacOS) {
|
||||
@@ -1416,8 +1409,7 @@ function New-UnixPackage {
|
||||
$createdPackage = Get-Item (Join-Path $CurrentLocation (($Output[-1] -split ":path=>")[-1] -replace '["{}]'))
|
||||
|
||||
# For macOS with native tools, the package is already in the correct format
|
||||
# For macOS with fpm (no longer used), we would need New-MacOsDistributionPackage
|
||||
# For other platforms, the package name from fpm/rpmbuild is sufficient
|
||||
# For other platforms, the package name from dpkg-deb/rpmbuild is sufficient
|
||||
|
||||
if (Test-Path $createdPackage)
|
||||
{
|
||||
@@ -1695,8 +1687,8 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination
|
||||
foreach ($link in $LinkInfo) {
|
||||
$linkDir = Split-Path -Parent $link.Destination
|
||||
$specContent += "mkdir -p `$RPM_BUILD_ROOT$linkDir`n"
|
||||
# For RPM, we copy the symlink itself (which fpm does by including it in the source)
|
||||
# The symlink at $link.Source points to the actual target, so we'll copy it
|
||||
# For RPM, we copy the symlink itself.
|
||||
# The symlink at $link.Source points to the actual target, so we'll copy it.
|
||||
# The -P flag preserves symlinks rather than copying their targets, which is critical for this operation.
|
||||
$specContent += "cp -P $($link.Source) `$RPM_BUILD_ROOT$($link.Destination)`n"
|
||||
}
|
||||
@@ -1733,6 +1725,217 @@ cp $ManGzipFile `$RPM_BUILD_ROOT$ManDestination
|
||||
return $specContent
|
||||
}
|
||||
|
||||
function New-NativeDeb
|
||||
{
|
||||
param(
|
||||
[Parameter(Mandatory, HelpMessage='Package Name')]
|
||||
[String]$Name,
|
||||
|
||||
[Parameter(Mandatory, HelpMessage='Package Version')]
|
||||
[String]$Version,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[String]$Iteration,
|
||||
|
||||
[Parameter(Mandatory, HelpMessage='Package description')]
|
||||
[String]$Description,
|
||||
|
||||
[Parameter(Mandatory, HelpMessage='Staging folder for installation files')]
|
||||
[String]$Staging,
|
||||
|
||||
[Parameter(Mandatory, HelpMessage='Install path on target machine')]
|
||||
[String]$Destination,
|
||||
|
||||
[Parameter(Mandatory, HelpMessage='The built and gzipped man file.')]
|
||||
[String]$ManGzipFile,
|
||||
|
||||
[Parameter(Mandatory, HelpMessage='The destination of the man file')]
|
||||
[String]$ManDestination,
|
||||
|
||||
[Parameter(Mandatory, HelpMessage='Symlink to powershell executable')]
|
||||
[LinkInfo[]]$LinkInfo,
|
||||
|
||||
[Parameter(HelpMessage='Packages required to install this package.')]
|
||||
[String[]]$Dependencies,
|
||||
|
||||
[Parameter(HelpMessage='Script to run after the package installation.')]
|
||||
[String]$AfterInstallScript,
|
||||
|
||||
[Parameter(HelpMessage='Script to run after the package removal.')]
|
||||
[String]$AfterRemoveScript,
|
||||
|
||||
[string]$HostArchitecture,
|
||||
|
||||
[string]$CurrentLocation
|
||||
)
|
||||
|
||||
Write-Log "Creating native DEB package..."
|
||||
|
||||
# Create temporary build directory
|
||||
$debBuildRoot = Join-Path $env:HOME "debbuild-$(Get-Random)"
|
||||
$debianDir = Join-Path $debBuildRoot "DEBIAN"
|
||||
$dataDir = Join-Path $debBuildRoot "data"
|
||||
|
||||
try {
|
||||
New-Item -ItemType Directory -Path $debianDir -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $dataDir -Force | Out-Null
|
||||
|
||||
# Calculate installed size (in KB)
|
||||
$installedSize = 0
|
||||
Get-ChildItem -Path $Staging -Recurse -File | ForEach-Object { $installedSize += $_.Length }
|
||||
$installedSize += (Get-Item $ManGzipFile).Length
|
||||
$installedSizeKB = [Math]::Ceiling($installedSize / 1024)
|
||||
|
||||
# Create control file with all fields in proper order
|
||||
# Description must be single line (first line) followed by extended description with leading space
|
||||
$descriptionLines = $Description -split "`n"
|
||||
$shortDescription = $descriptionLines[0]
|
||||
$extendedDescription = if ($descriptionLines.Count -gt 1) {
|
||||
($descriptionLines[1..($descriptionLines.Count-1)] | ForEach-Object { " $_" }) -join "`n"
|
||||
}
|
||||
|
||||
$controlContent = @"
|
||||
Package: $Name
|
||||
Version: $Version-$Iteration
|
||||
Architecture: $HostArchitecture
|
||||
Maintainer: PowerShell Team <PowerShellTeam@hotmail.com>
|
||||
Installed-Size: $installedSizeKB
|
||||
Priority: optional
|
||||
Section: shells
|
||||
Homepage: https://microsoft.com/powershell
|
||||
Depends: $(if ($Dependencies) { $Dependencies -join ', ' })
|
||||
Description: $shortDescription
|
||||
$(if ($extendedDescription) { $extendedDescription + "`n" })
|
||||
"@
|
||||
|
||||
$controlFile = Join-Path $debianDir "control"
|
||||
$controlContent | Out-File -FilePath $controlFile -Encoding ascii -NoNewline
|
||||
|
||||
Write-Verbose "Control file created: $controlFile" -Verbose
|
||||
Write-LogGroup -Title "DEB Control File Content" -Message $controlContent
|
||||
|
||||
# Copy postinst script if provided
|
||||
if ($AfterInstallScript -and (Test-Path $AfterInstallScript)) {
|
||||
$postinstFile = Join-Path $debianDir "postinst"
|
||||
Copy-Item -Path $AfterInstallScript -Destination $postinstFile -Force
|
||||
Start-NativeExecution { chmod 755 $postinstFile }
|
||||
Write-Verbose "Postinst script copied to: $postinstFile" -Verbose
|
||||
}
|
||||
|
||||
# Copy postrm script if provided
|
||||
if ($AfterRemoveScript -and (Test-Path $AfterRemoveScript)) {
|
||||
$postrmFile = Join-Path $debianDir "postrm"
|
||||
Copy-Item -Path $AfterRemoveScript -Destination $postrmFile -Force
|
||||
Start-NativeExecution { chmod 755 $postrmFile }
|
||||
Write-Verbose "Postrm script copied to: $postrmFile" -Verbose
|
||||
}
|
||||
|
||||
# Copy staging files to data directory
|
||||
$targetPath = Join-Path $dataDir $Destination.TrimStart('/')
|
||||
New-Item -ItemType Directory -Path $targetPath -Force | Out-Null
|
||||
Copy-Item -Path "$Staging/*" -Destination $targetPath -Recurse -Force
|
||||
Write-Verbose "Copied staging files to: $targetPath" -Verbose
|
||||
|
||||
# Copy man page
|
||||
$manDestPath = Join-Path $dataDir $ManDestination.TrimStart('/')
|
||||
$manDestDir = Split-Path $manDestPath -Parent
|
||||
New-Item -ItemType Directory -Path $manDestDir -Force | Out-Null
|
||||
Copy-Item -Path $ManGzipFile -Destination $manDestPath -Force
|
||||
Write-Verbose "Copied man page to: $manDestPath" -Verbose
|
||||
|
||||
# Copy symlinks from temporary locations
|
||||
foreach ($link in $LinkInfo) {
|
||||
$linkPath = Join-Path $dataDir $link.Destination.TrimStart('/')
|
||||
$linkDir = Split-Path $linkPath -Parent
|
||||
New-Item -ItemType Directory -Path $linkDir -Force | Out-Null
|
||||
|
||||
# Copy the temporary symlink file that was created by New-LinkInfo
|
||||
# The Source contains a temporary symlink that points to the correct target
|
||||
if (Test-Path $link.Source) {
|
||||
# Use cp to preserve the symlink
|
||||
Start-NativeExecution { cp -P $link.Source $linkPath }
|
||||
Write-Verbose "Copied symlink: $linkPath (from $($link.Source))" -Verbose
|
||||
} else {
|
||||
Write-Warning "Symlink source not found: $($link.Source)"
|
||||
}
|
||||
}
|
||||
|
||||
# Set proper permissions
|
||||
Write-Verbose "Setting file permissions..." -Verbose
|
||||
# 755 = rwxr-xr-x (owner can read/write/execute, group and others can read/execute)
|
||||
Get-ChildItem $dataDir -Directory -Recurse | ForEach-Object {
|
||||
Start-NativeExecution { chmod 755 $_.FullName }
|
||||
}
|
||||
# 644 = rw-r--r-- (owner can read/write, group and others can read only)
|
||||
# Exclude symlinks to avoid "cannot operate on dangling symlink" error
|
||||
Get-ChildItem $dataDir -File -Recurse |
|
||||
Where-Object { -not $_.Target } |
|
||||
ForEach-Object {
|
||||
Start-NativeExecution { chmod 644 $_.FullName }
|
||||
}
|
||||
|
||||
# Set executable permission for pwsh if it exists
|
||||
# 755 = rwxr-xr-x (executable permission)
|
||||
$pwshPath = "$targetPath/pwsh"
|
||||
if (Test-Path $pwshPath) {
|
||||
Start-NativeExecution { chmod 755 $pwshPath }
|
||||
}
|
||||
|
||||
# Calculate md5sums for all files in data directory (excluding symlinks)
|
||||
$md5sumsFile = Join-Path $debianDir "md5sums"
|
||||
$md5Content = ""
|
||||
Get-ChildItem -Path $dataDir -Recurse -File |
|
||||
Where-Object { -not $_.Target } |
|
||||
ForEach-Object {
|
||||
$relativePath = $_.FullName.Substring($dataDir.Length + 1)
|
||||
$md5Hash = (Get-FileHash -Path $_.FullName -Algorithm MD5).Hash.ToLower()
|
||||
$md5Content += "$md5Hash $relativePath`n"
|
||||
}
|
||||
$md5Content | Out-File -FilePath $md5sumsFile -Encoding ascii -NoNewline
|
||||
Write-Verbose "MD5 sums file created: $md5sumsFile" -Verbose
|
||||
|
||||
# Build the package using dpkg-deb
|
||||
$debFileName = "${Name}_${Version}-${Iteration}_${HostArchitecture}.deb"
|
||||
$debFilePath = Join-Path $CurrentLocation $debFileName
|
||||
|
||||
Write-Verbose "Building DEB package: $debFileName" -Verbose
|
||||
|
||||
# Copy DEBIAN directory and data files to build root
|
||||
$buildDir = Join-Path $debBuildRoot "build"
|
||||
New-Item -ItemType Directory -Path $buildDir -Force | Out-Null
|
||||
|
||||
Write-Verbose "debianDir: $debianDir" -Verbose
|
||||
Write-Verbose "dataDir: $dataDir" -Verbose
|
||||
Write-Verbose "buildDir: $buildDir" -Verbose
|
||||
|
||||
# Use cp to preserve symlinks
|
||||
Start-NativeExecution { cp -a $debianDir "$buildDir/DEBIAN" }
|
||||
Start-NativeExecution { cp -a $dataDir/* $buildDir }
|
||||
|
||||
# Build package with dpkg-deb
|
||||
Start-NativeExecution -VerboseOutputOnError {
|
||||
dpkg-deb --build $buildDir $debFilePath
|
||||
}
|
||||
|
||||
if (Test-Path $debFilePath) {
|
||||
Write-Log "Successfully created DEB package: $debFileName"
|
||||
return @{
|
||||
PackagePath = $debFilePath
|
||||
PackageName = $debFileName
|
||||
}
|
||||
} else {
|
||||
throw "DEB package file not found after build: $debFilePath"
|
||||
}
|
||||
}
|
||||
finally {
|
||||
# Cleanup temporary directory
|
||||
if (Test-Path $debBuildRoot) {
|
||||
Write-Verbose "Cleaning up temporary build directory: $debBuildRoot" -Verbose
|
||||
Remove-Item -Path $debBuildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function New-MacOSPackage
|
||||
{
|
||||
[CmdletBinding(SupportsShouldProcess=$true)]
|
||||
@@ -1884,146 +2087,6 @@ function New-MacOSPackage
|
||||
}
|
||||
}
|
||||
|
||||
function Get-FpmArguments
|
||||
{
|
||||
param(
|
||||
[Parameter(Mandatory,HelpMessage='Package Name')]
|
||||
[String]$Name,
|
||||
|
||||
[Parameter(Mandatory,HelpMessage='Package Version')]
|
||||
[String]$Version,
|
||||
|
||||
[Parameter(Mandatory)]
|
||||
[String]$Iteration,
|
||||
|
||||
[Parameter(Mandatory,HelpMessage='Package description')]
|
||||
[String]$Description,
|
||||
|
||||
# From start-PSPackage without modification, already validated
|
||||
# Values: deb, rpm, osxpkg
|
||||
[Parameter(Mandatory,HelpMessage='Installer Type')]
|
||||
[String]$Type,
|
||||
|
||||
[Parameter(Mandatory,HelpMessage='Staging folder for installation files')]
|
||||
[String]$Staging,
|
||||
|
||||
[Parameter(Mandatory,HelpMessage='Install path on target machine')]
|
||||
[String]$Destination,
|
||||
|
||||
[Parameter(Mandatory,HelpMessage='The built and gzipped man file.')]
|
||||
[String]$ManGzipFile,
|
||||
|
||||
[Parameter(Mandatory,HelpMessage='The destination of the man file')]
|
||||
[String]$ManDestination,
|
||||
|
||||
[Parameter(Mandatory,HelpMessage='Symlink to powershell executable')]
|
||||
[LinkInfo[]]$LinkInfo,
|
||||
|
||||
[Parameter(HelpMessage='Packages required to install this package. Not applicable for MacOS.')]
|
||||
[ValidateScript({
|
||||
if (!$Environment.IsMacOS -and $_.Count -eq 0)
|
||||
{
|
||||
throw "Must not be null or empty on this environment."
|
||||
}
|
||||
return $true
|
||||
})]
|
||||
[String[]]$Dependencies,
|
||||
|
||||
[Parameter(HelpMessage='Script to run after the package installation.')]
|
||||
[AllowNull()]
|
||||
[ValidateScript({
|
||||
if (!$Environment.IsMacOS -and !$_)
|
||||
{
|
||||
throw "Must not be null on this environment."
|
||||
}
|
||||
return $true
|
||||
})]
|
||||
[String]$AfterInstallScript,
|
||||
|
||||
[Parameter(HelpMessage='Script to run after the package removal.')]
|
||||
[AllowNull()]
|
||||
[ValidateScript({
|
||||
if (!$Environment.IsMacOS -and !$_)
|
||||
{
|
||||
throw "Must not be null on this environment."
|
||||
}
|
||||
return $true
|
||||
})]
|
||||
[String]$AfterRemoveScript,
|
||||
|
||||
[Parameter(HelpMessage='AppsFolder used to add macOS launcher')]
|
||||
[AllowNull()]
|
||||
[ValidateScript({
|
||||
if ($Environment.IsMacOS -and !$_)
|
||||
{
|
||||
throw "Must not be null on this environment."
|
||||
}
|
||||
return $true
|
||||
})]
|
||||
[String]$AppsFolder,
|
||||
[String]$Distribution = 'rhel.7',
|
||||
[string]$HostArchitecture
|
||||
)
|
||||
|
||||
$Arguments = @(
|
||||
"--force", "--verbose",
|
||||
"--name", $Name,
|
||||
"--version", $Version,
|
||||
"--iteration", $Iteration,
|
||||
"--maintainer", "PowerShell Team <PowerShellTeam@hotmail.com>",
|
||||
"--vendor", "Microsoft Corporation",
|
||||
"--url", "https://microsoft.com/powershell",
|
||||
"--description", $Description,
|
||||
"--architecture", $HostArchitecture,
|
||||
"--category", "shells",
|
||||
"-t", $Type,
|
||||
"-s", "dir"
|
||||
)
|
||||
if ($Distribution -in $script:RedHatDistributions) {
|
||||
$Arguments += @("--rpm-digest", "sha256")
|
||||
$Arguments += @("--rpm-dist", $Distribution)
|
||||
$Arguments += @("--rpm-os", "linux")
|
||||
$Arguments += @("--license", "MIT")
|
||||
$Arguments += @("--rpm-rpmbuild-define", "_build_id_links none")
|
||||
} else {
|
||||
$Arguments += @("--license", "MIT License")
|
||||
}
|
||||
|
||||
if ($Environment.IsMacOS) {
|
||||
$Arguments += @("--osxpkg-identifier-prefix", "com.microsoft")
|
||||
}
|
||||
|
||||
foreach ($Dependency in $Dependencies) {
|
||||
$Arguments += @("--depends", $Dependency)
|
||||
}
|
||||
|
||||
if ($AfterInstallScript) {
|
||||
$Arguments += @("--after-install", $AfterInstallScript)
|
||||
}
|
||||
|
||||
if ($AfterRemoveScript) {
|
||||
$Arguments += @("--after-remove", $AfterRemoveScript)
|
||||
}
|
||||
|
||||
$Arguments += @(
|
||||
"$Staging/=$Destination/",
|
||||
"$ManGzipFile=$ManDestination"
|
||||
)
|
||||
|
||||
foreach($link in $LinkInfo)
|
||||
{
|
||||
$linkArgument = "$($link.Source)=$($link.Destination)"
|
||||
$Arguments += $linkArgument
|
||||
}
|
||||
|
||||
if ($AppsFolder)
|
||||
{
|
||||
$Arguments += "$AppsFolder=/"
|
||||
}
|
||||
|
||||
return $Arguments
|
||||
}
|
||||
|
||||
function Get-PackageDependencies
|
||||
{
|
||||
[CmdletBinding()]
|
||||
@@ -2096,44 +2159,25 @@ function Get-PackageDependencies
|
||||
|
||||
function Test-Dependencies
|
||||
{
|
||||
# Note: RPM packages no longer require fpm; they use rpmbuild directly
|
||||
# macOS packages use pkgbuild and productbuild from Xcode Command Line Tools
|
||||
# DEB packages still use fpm
|
||||
# RPM packages use rpmbuild directly.
|
||||
# DEB packages use dpkg-deb directly.
|
||||
# macOS packages use pkgbuild and productbuild from Xcode Command Line Tools.
|
||||
$Dependencies = @()
|
||||
|
||||
# Only check for fpm on Debian-based systems
|
||||
if ($Environment.IsDebianFamily) {
|
||||
$Dependencies += "fpm"
|
||||
|
||||
# Check for 'rpmbuild' and 'dpkg-deb' on Azure Linux.
|
||||
if ($Environment.IsMariner) {
|
||||
$Dependencies += "dpkg-deb"
|
||||
$Dependencies += "rpmbuild"
|
||||
}
|
||||
|
||||
|
||||
# Check for macOS packaging tools
|
||||
if ($Environment.IsMacOS) {
|
||||
$Dependencies += "pkgbuild"
|
||||
$Dependencies += "productbuild"
|
||||
}
|
||||
|
||||
|
||||
foreach ($Dependency in $Dependencies) {
|
||||
if (!(precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) {
|
||||
# For Debian systems, try adding ruby gems to the path
|
||||
if ($Environment.IsDebianFamily) {
|
||||
# These tools are not added to the path automatically on OpenSUSE 13.2
|
||||
# try adding them to the path and re-tesing first
|
||||
[string] $gemsPath = $null
|
||||
[string] $depenencyPath = $null
|
||||
$gemsPath = Get-ChildItem -Path /usr/lib64/ruby/gems | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty FullName
|
||||
if ($gemsPath) {
|
||||
$depenencyPath = Get-ChildItem -Path (Join-Path -Path $gemsPath -ChildPath "gems" -AdditionalChildPath $Dependency) -Recurse | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty DirectoryName
|
||||
$originalPath = $env:PATH
|
||||
$env:PATH = $ENV:PATH +":" + $depenencyPath
|
||||
if ((precheck $Dependency "Package dependency '$Dependency' not found. Run Start-PSBootstrap -Scenario Package")) {
|
||||
continue
|
||||
}
|
||||
else {
|
||||
$env:PATH = $originalPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw "Dependency precheck failed!"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user