lib/command-file.psm1
#Requires -PSEdition Core -Version 7.2 <# .SYNOPSIS GitHub Actions - Internal - Add File Command .DESCRIPTION Add file command for the current step. .PARAMETER FileCommandPath File command path. .PARAMETER Name Name. .PARAMETER Value Value. .OUTPUTS [Void] #> Function Add-FileCommand { [OutputType([Void])] Param ( [Parameter(Mandatory = $True, Position = 0)][Alias('CommandPath')][String]$FileCommandPath, [Parameter(Mandatory = $True, Position = 1)][String]$Name, [Parameter(Mandatory = $True, Position = 2)][AllowEmptyString()][AllowNull()][String]$Value ) If ($Value -imatch '^.*$') { [String]$Content = "$Name=$Value" } Else { Do { [String]$Token = (New-Guid).Guid.ToLower() -ireplace '-', '' } While ( $Name -imatch $Token -or $Value -imatch $Token ) [String]$Content = "$Name<<$Token`n$($Value -ireplace '\r?\n', "`n")`n$Token" } Add-Content -LiteralPath $FileCommandPath -Value $Content -Confirm:$False -Encoding 'UTF8NoBOM' } <# .SYNOPSIS GitHub Actions - Clear File Command .DESCRIPTION Clear the file command that set in the current step. .PARAMETER FileCommand File command. .OUTPUTS [Void] #> Function Clear-FileCommand { [CmdletBinding(HelpUri = 'https://github.com/hugoalh-studio/ghactions-toolkit-powershell/wiki/api_function_cleargithubactionsfilecommand')] [OutputType([Void])] Param ( [Parameter(Mandatory = $True, Position = 0)][Alias('Command', 'Commands', 'FileCommands')][String[]]$FileCommand ) ForEach ($FC In $FileCommand) { Try { Set-Content -LiteralPath (Resolve-FileCommandPath -FileCommand $FC) -Value '' -Confirm:$False -Encoding 'UTF8NoBOM' } Catch { Write-Error -Message "Unable to clear the GitHub Actions file command: $_" -Category (($_)?.CategoryInfo.Category ?? 'OperationStopped') } } } Set-Alias -Name 'Remove-FileCommand' -Value 'Clear-FileCommand' -Option 'ReadOnly' -Scope 'Local' <# .SYNOPSIS GitHub Actions - Internal - Get File Command .DESCRIPTION Get file command that set in the current step. .PARAMETER FileCommandPath File command path. .OUTPUTS [PSCustomObject[]] #> Function Get-FileCommand { [OutputType([PSCustomObject[]])] Param ( [Parameter(Mandatory = $True, Position = 0)][Alias('CommandPath')][String]$FileCommandPath ) [String[]]$FileCommandRaw = Get-Content -LiteralPath $FileCommandPath -Encoding 'UTF8NoBOM' [PSCustomObject[]]$Result = @() For ([UInt64]$Index = 0; $Index -lt $FileCommandRaw.Count; $Index += 1) { [String]$CurrentLine = $FileCommandRaw[$Index] If ($CurrentLine.Length -eq 0) { Continue } If ($CurrentLine -imatch '^.+<<.+?$') { [String[]]$CurrentLineSplit = $CurrentLine -isplit '<<' [String]$Name = $CurrentLineSplit | Select-Object -SkipLast 1 | Join-String -Separator '<<' [String]$Delimiter = $CurrentLineSplit | Select-Object -Last 1 [String[]]$Value = @() [UInt64]$IndexOffset = $Index While ($True) { $IndexOffset += 1 If ($IndexOffset -ge $FileCommandRaw.Count) { Throw "``$CurrentLine`` is missing pair delimiter in the file command content!" } [String]$CurrentLineOffset = $FileCommandRaw[$IndexOffset] If ($CurrentLineOffset -ceq $Delimiter) { Break } $Value += $CurrentLineOffset } $Result += [PSCustomObject]@{ Name = $Name Value = $Value | Join-String -Separator "`n" Raw = @($CurrentLine) + $Value + @($Delimiter) } $Index = $IndexOffset Continue } If ($CurrentLine -imatch '^.+?=.+$') { [String[]]$CurrentLineSplit = $CurrentLine -isplit '=' [String]$Name = $CurrentLineSplit | Select-Object -Index @(0) [String]$Value = $CurrentLineSplit | Select-Object -SkipIndex @(0) | Join-String -Separator '=' $Result += [PSCustomObject]@{ Name = $Name Value = $Value Raw = @($CurrentLine) } Continue } Throw "``$CurrentLine`` is not a valid file command content!" } $Result | Write-Output } <# .SYNOPSIS GitHub Actions - Internal - Remove File Command .DESCRIPTION Remove file command that set in the current step. .PARAMETER FileCommandPath File command path. .PARAMETER Raw Raw. .OUTPUTS [Void] #> Function Remove-FileCommand { [OutputType([Void])] Param ( [Parameter(Mandatory = $True, Position = 0)][Alias('CommandPath')][String]$FileCommandPath, [Parameter(Mandatory = $True, Position = 1)][String[]]$Raw ) [String]$FileCommandRaw = Get-Content -LiteralPath $FileCommandPath -Raw -Encoding 'UTF8NoBOM' [String]$RawReplace = $Raw | ForEach-Object -Process { [RegEx]::Escape($_) } | Join-String -Separator '\r?\n' -OutputPrefix '(?:^|\r?\n)' -OutputSuffix '(?:$|\r?\n)' Set-Content -LiteralPath $FileCommandPath -Value ($FileCommandRaw -ireplace $RawReplace, "`n") -Confirm:$False -Encoding 'UTF8NoBOM' } <# .SYNOPSIS GitHub Actions - Internal - Resolve File Command Path .DESCRIPTION Resolve file command path. .PARAMETER FileCommand File command. .OUTPUTS [String] File command path. #> Function Resolve-FileCommandPath { [OutputType([String])] Param ( [Parameter(Mandatory = $True, Position = 0)][ValidatePattern('^(?:[\da-z][\da-z_-]*)?[\da-z]$', ErrorMessage = '`{0}` is not a valid GitHub Actions file command!')][Alias('Command')][String]$FileCommand ) [String]$FileCommandToUpper = $FileCommand.ToUpper() [AllowEmptyString()][AllowNull()][String]$FileCommandPath = [System.Environment]::GetEnvironmentVariable($FileCommandToUpper) If ([String]::IsNullOrEmpty($FileCommandPath)) { Throw "Environment path ``$FileCommandToUpper`` is not defined!" } If (![System.IO.Path]::IsPathFullyQualified($FileCommandPath)) { Throw "``$FileCommandPath`` (environment path ``$FileCommandToUpper``) is not a valid absolute path!" } If (!(Test-Path -LiteralPath $FileCommandPath -PathType 'Leaf')) { Throw "Environment path ``$FileCommandToUpper`` is not exist!" } Return $FileCommandPath } <# .SYNOPSIS GitHub Actions - Write File Command .DESCRIPTION Write file command for the current step. .PARAMETER FileCommand File command. .PARAMETER Name Name. .PARAMETER Value Value. .PARAMETER Optimize Whether to have an optimize operation by replace exist command instead of add command directly. .OUTPUTS [Void] #> Function Write-FileCommand { [CmdletBinding(HelpUri = 'https://github.com/hugoalh-studio/ghactions-toolkit-powershell/wiki/api_function_writegithubactionsfilecommand')] [OutputType([Void])] Param ( [Parameter(Mandatory = $True, Position = 0)][Alias('Command')][String]$FileCommand, [Parameter(Mandatory = $True, Position = 1, ValueFromPipelineByPropertyName = $True)][ValidatePattern('^(?:[\da-z][\da-z_-]*)?[\da-z]$', ErrorMessage = 'Value is not a valid GitHub Actions file command property name!')][String]$Name, [Parameter(Mandatory = $True, Position = 2, ValueFromPipelineByPropertyName = $True)][AllowEmptyString()][AllowNull()][String]$Value, [Switch]$Optimize ) Begin { [Boolean]$ShouldProceed = $True Try { [String]$FileCommandPath = Resolve-FileCommandPath -FileCommand $FileCommand } Catch { $ShouldProceed = $False Write-Error -Message "Unable to write the GitHub Actions file command: $_" -Category 'ResourceUnavailable' } If ($Optimize.IsPresent) { Try { [PSCustomObject[]]$FileCommandContent = Get-FileCommand -FileCommandPath $FileCommandPath } Catch { Write-Warning -Message "Unable to get the GitHub Actions file command: $_" } } } Process { If (!$ShouldProceed) { Return } Try { If ($Optimize.IsPresent -and $Null -ine $FileCommandContent -and $FileCommandContent.Name -icontains $Name) { Try { Remove-FileCommand -FileCommandPath $FileCommandPath -Raw ( $FileCommandContent | Where-Object -FilterScript { $_.Name -ieq $Name } ).Raw $FileCommandContent = $FileCommandContent | Where-Object -FilterScript { $_.Name -ine $Name } } Catch { Write-Warning -Message "Unable to remove the GitHub Actions file command: $_" } } Add-FileCommand -FileCommandPath $FileCommandPath -Name $Name -Value $Value } Catch { Write-Error -Message "Unable to write the GitHub Actions file command: $_" -Category (($_)?.CategoryInfo.Category ?? 'OperationStopped') } } } Export-ModuleMember -Function @( 'Clear-FileCommand', 'Write-FileCommand' ) -Alias @( 'Remove-FileCommand' ) |