Public/New-FirebirdEnvironment.ps1
|
function New-FirebirdEnvironment { <# .SYNOPSIS Downloads and extracts Firebird binaries for a given version and platform. .DESCRIPTION Installs Firebird to a specified or temporary directory and returns environment details. Supports both official releases (by version) and snapshot builds (by branch). .PARAMETER Version Firebird version to install. Minimum supported version is 3.0.9. .PARAMETER Branch Snapshot branch to install from (e.g. 'master' for Firebird 6.x development builds, 'v5.0-release' for Firebird 5.x next-patch builds, 'v4.0' for Firebird 4.x next-patch builds). Mutually exclusive with -Version. .PARAMETER Path Directory to extract the binaries to. Uses a temporary folder if not provided. .PARAMETER RuntimeIdentifier Runtime identifier for the platform. Uses current platform if not specified. .PARAMETER Force Overwrites the output directory if it already exists. .EXAMPLE New-FirebirdEnvironment -Version 5.0.2 -Path '/tmp/firebird-5.0.2' -Force Installs Firebird 5.0.2 to the specified path, overwriting if it exists. .EXAMPLE New-FirebirdEnvironment -Version 5.0.2 Installs Firebird 5.0.2 to a temporary directory. .EXAMPLE New-FirebirdEnvironment -Branch 'master' Installs the latest Firebird snapshot from the master branch to a temporary directory. .OUTPUTS FirebirdEnvironment object with Path and Version properties. #> [CmdletBinding(SupportsShouldProcess = $true, DefaultParameterSetName = 'ByVersion')] [OutputType([FirebirdEnvironment])] Param( [Parameter(Mandatory, ParameterSetName = 'ByVersion')] [semver]$Version, [Parameter(Mandatory, ParameterSetName = 'ByBranch')] [ValidateSet('master', 'v5.0-release', 'v4.0')] [string]$Branch, [string]$Path, [ValidateSet('win-x86', 'win-x64', 'win-arm64', 'linux-x64', 'linux-arm64')] [string]$RuntimeIdentifier, [switch]$Force ) if (-not $IsWindows -and -not $IsLinux) { throw "Unsupported platform: $([System.Runtime.InteropServices.RuntimeInformation]::OSDescription). Only Windows and Linux are supported." } if ($IsLinux -and (-not (Get-Command 'apt-get' -ErrorAction SilentlyContinue))) { throw 'apt-get command not found. Ensure you are running this on a Debian-based Linux distribution.' } $rid = if ($RuntimeIdentifier) { $RuntimeIdentifier } else { [System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier } $supportedRIDs = @('win-x86', 'win-x64', 'win-arm64', 'linux-x64', 'linux-arm64') if ($supportedRIDs -notcontains $rid) { throw "Unsupported RuntimeIdentifier: $rid. Supported: $($supportedRIDs -join ', ')" } Write-VerboseMark -Message "RuntimeIdentifier is '$rid'." # Resolve release info based on parameter set if ($PSCmdlet.ParameterSetName -eq 'ByBranch') { Write-VerboseMark -Message "Requested Firebird snapshot branch '$Branch'" $snapshotInfo = Find-FirebirdSnapshotRelease -Branch $Branch -RuntimeIdentifier $rid # Extract version from the snapshot filename (e.g. 'Firebird-6.0.0.1884-...' -> '6.0.0') if ($snapshotInfo.FileName -match 'Firebird-(\d+\.\d+\.\d+)') { $Version = [semver]$Matches[1] } else { throw "Cannot determine version from snapshot filename: $($snapshotInfo.FileName)" } Write-VerboseMark -Message "Resolved snapshot version: $Version" } else { Write-VerboseMark -Message "Requested Firebird version '$($Version)'" } $minVersion = [semver]'3.0.9' if ($Version -lt $minVersion) { throw 'Firebird minimal supported version is 3.0.9.' } $tempRoot = [System.IO.Path]::GetTempPath() if (-not $Path) { $pathSuffix = if ($PSCmdlet.ParameterSetName -eq 'ByBranch') { "firebird-snapshot-$Branch" } else { "firebird-$($Version)" } $Path = Join-Path $tempRoot $pathSuffix Write-VerboseMark -Message "No Path specified. Using temporary folder: $Path" } if (Test-Path $Path) { if (-not $Force) { Write-VerboseMark -Message "Path '$Path' already exists and -Force not specified." # Check if the existing path is a valid Firebird environment $existingEnvironment = Get-FirebirdEnvironment -Path $Path # Check if the existing environment version matches the requested version (discard Revision/Build number) $v = $existingEnvironment.Version $existingVersion = [semver]::new($v.Major, $v.Minor, $v.Build) if ($existingVersion -ne $Version) { throw "Path '$Path' already exists with version '$($existingVersion)'. Cannot install version '$Version'. Use -Force to overwrite." } # If the existing environment matches the requested version, return it return $existingEnvironment } if ($PSCmdlet.ShouldProcess($Path, 'Clear existing output directory')) { Remove-Item $Path -Recurse -Force } } if ($PSCmdlet.ShouldProcess($Path, 'Create output directory')) { New-Item -ItemType Directory $Path -Force > $null } if ($PSCmdlet.ParameterSetName -eq 'ByBranch') { # Snapshot release info was already resolved above $releaseInfo = $snapshotInfo } else { $releaseInfo = Get-FirebirdReleaseUrl -Version $Version -RuntimeIdentifier $rid } $downloadUrl = $releaseInfo.Url Write-VerboseMark -Message "Release URL is '$($downloadUrl)'" $archiveFile = $releaseInfo.FileName $fullArchiveFile = Join-Path $tempRoot $archiveFile if ($PSCmdlet.ShouldProcess($archiveFile, 'Downloading Firebird archive')) { Write-VerboseMark -Message "Downloading Firebird archive '$archiveFile'..." Invoke-WebRequest $downloadUrl -OutFile $fullArchiveFile -Verbose:$false } if ($PSCmdlet.ShouldProcess($archiveFile, 'Extracting archive')) { Write-VerboseMark -Message "Extracting archive '$archiveFile'..." if ($IsWindows) { Write-VerboseMark -Message 'Extracting Windows archive...' Expand-Archive -Path $fullArchiveFile -DestinationPath $Path } elseif ($IsLinux) { Write-VerboseMark -Message 'Extracting Linux archive...' Invoke-ExternalCommand { & tar --extract --file=$fullArchiveFile --gunzip --directory=$Path --strip-components=1 } -ErrorMessage "Failed to extract '$fullArchiveFile' archive. Cannot continue." if (-not ($rid.Contains('linux-arm64') -and ($Version.Major -lt 5))) { # For Firebird 5.x+ and non-ARM64, extract the nested buildroot archive. Write-VerboseMark -Message 'Extracting buildroot archive...' Invoke-ExternalCommand { & tar --extract --file="$Path/buildroot.tar.gz" --gunzip --directory=$Path --strip-components=3 ./opt } -ErrorMessage "Failed to extract '$fullArchiveFile' archive. Cannot continue." } } } if ($PSCmdlet.ShouldProcess($fullArchiveFile, 'Removing archive')) { Write-VerboseMark -Message "Removing archive '$fullArchiveFile'..." Remove-Item -Path @( # On Linux, also remove the buildroot archive "$Path/buildroot.tar.gz", # Common $fullArchiveFile ) -Recurse -Force -ErrorAction Ignore } # Windows-only: Set the IpcName in firebird.conf if ($IsWindows) { $ipcName = "FIREBIRD-$($Version -replace '\.','_')" $firebirdConfPath = Join-Path $Path 'firebird.conf' if ($PSCmdlet.ShouldProcess($firebirdConfPath, "Setting IpcName to '$ipcName' in firebird.conf")) { Write-VerboseMark -Message "Setting IpcName to '$ipcName' in firebird.conf..." $content = Get-Content $firebirdConfPath $content = $content -replace '#IpcName = FIREBIRD', "IpcName = $ipcName" Set-Content -Path $firebirdConfPath -Value $content -Encoding Ascii } } else { Write-VerboseMark -Message 'Skipping IpcName configuration (not Windows).' } # Linux-only: Download additional packages and extract it to the `lib` directory. if ($IsLinux) { Write-VerboseMark -Message 'Downloading additional Linux packages...' $libPath = Join-Path $Path 'lib' Invoke-AptDownloadAndExtract -PackageName 'libtommath1' ` -SourcePattern './usr/lib/*/*' ` -TargetFolder $libPath # For FB3, we also need to download libncurses5 if ($Version -ge [semver]3) { Write-VerboseMark -Message 'Downloading libncurses5 and libtinfo5 for Firebird 3+...' Invoke-AptDownloadAndExtract -PackageName 'libncurses5' ` -SourcePattern './lib/*/*' ` -TargetFolder $libPath Invoke-AptDownloadAndExtract -PackageName 'libtinfo5' ` -SourcePattern './lib/*/*' ` -TargetFolder $libPath } # Fix libtommath for FB3 and FB4 -- https://github.com/FirebirdSQL/firebird/issues/5716#issuecomment-826239174 if ($Version -lt [semver]5) { Write-VerboseMark -Message 'Applying libtommath symlink fix for Firebird < 5...' if ($PSCmdlet.ShouldProcess("$libPath/libtommath.so.1", 'Creating symlink for libtommath.so.0...')) { Write-VerboseMark -Message 'Creating symlink for libtommath.so.0...' ln -sf "$libPath/libtommath.so.1" "$libPath/libtommath.so.0" } } } # Remove the sample database from databases.conf $databasesConfPath = Join-Path $Path 'databases.conf' if (-not (Test-Path $databasesConfPath)) { $folderItems = Get-ChildItem -Path $Path throw "databases.conf not found at '$Path'. Folder content is: $folderItems" } if ($PSCmdlet.ShouldProcess($databasesConfPath, 'Removing sample database')) { Write-VerboseMark -Message "Removing sample database from '$databasesConfPath'..." $content = Get-Content $databasesConfPath $content | Where-Object { $_ -notmatch '^employee' } | Set-Content $databasesConfPath } # Clean up the output directory if ($PSCmdlet.ShouldProcess($Path, 'Cleaning up output directory')) { Write-VerboseMark -Message 'Cleaning up output directory...' Remove-Item -Path @( # Windows-specific "$Path/system32", "$Path/*.bat", # Linux-specific "$Path/buildroot.tar.gz", # Common files "$Path/doc", "$Path/examples", "$Path/help", "$Path/include", "$Path/misc", $fullArchiveFile ) -Recurse -Force -ErrorAction Ignore } # Return the environment information as a FirebirdEnvironment class instance. Get-FirebirdEnvironment -Path $Path } |