<#
.Synopsis
freeze_stream.ps1 freezes currently selected stream by converting
all import lines from /... to /...@4321 - where that is the latest
changelist for the import line.
.Description
This is intended as a custom tool for P4V.
It can be easily installed for P4V using Install-P4VUtils.ps1
.Parameter p4port
The P4PORT to use
.Parameter p4user
The P4USER to use
.Parameter stream
The name of the stream spec to update
.Parameter freeze date/time
Date/time (in p4 format without spaces: yyyyy/mm/dd:hh:mm:ss)
.Example
As custom tool in P4V:
Application: powershell
Arguments: -f c:\path\to\freeze_stream.ps1 $p $u %t $D
Where c:\path\to is the name of directory containing the script
Check option “Run tool in terminal window”
If not debugging, check option “Close window upon completion”
#>
# Doesn't work in older versions of Powershell
# [CmdletBinding()]
param ( [string]$p4port,
[string]$p4user,
[string]$stream,
[string]$freeze_action,
[string]$freeze_datetime)
Function Log([string]$message) {
# Logs output to file and to console
$datetime = Get-Date -format "yyyy\/MM\/dd HH\:mm\:ss"
"$datetime $message" | write-output
}
Function Append-To-File([string]$filename, $message) {
$OFS = $null
if (test-path variable:global:OFS) {
$OFS = $global:OFS
}
try {
$global:OFS = "`r`n"
$message | add-content -path $filename
}
catch {}
if ($OFS) {
$global:OFS = $OFS
}
}
try {
if ($p4port -eq $null -or $p4port -eq "") {
throw "ERROR: please specify parameter p4port"
}
if ($p4user -eq $null -or $p4user -eq "") {
throw "ERROR: please specify parameter p4user"
}
if ($stream -eq $null -or $path -eq "") {
throw "ERROR: please specify parameter stream"
}
Log "Args p4port:'$p4port' p4user:'$p4user' stream:'$stream' action:$freeze_action freeze_dt:'$freeze_datetime'"
$freeze_action = $freeze_action.ToLower()
if (($freeze_action -ne "freeze") -and ($freeze_action -ne "unfreeze")) {
throw "ERROR: please specify parameter freeze_action: [freeze/unfreeze]"
}
$dofreeze = $true
if ($freeze_action -eq "unfreeze") {
$dofreeze = $false
}
Log "Args p4port:'$p4port' p4user:'$p4user' stream:'$stream' action:$freeze_action freeze_dt:'$freeze_datetime'"
$p4baseargs = "-p", $p4port
if ($p4user -ne "default") {
$p4baseargs += "-u", $p4user
}
$p4args = $p4baseargs + "stream", "-o", "$stream"
Log "p4 $p4args"
$stream_spec = & p4 @p4args
$new_stream = @()
$paths = @()
$inPath = $false
foreach ($line in $stream_spec) {
if ($line -match "^#.*") {
continue
}
if ($line -match "^Paths:") {
$inPath = $true
}
if ($inPath) {
if ($line -match "^$") {
$inPath = $false
} else {
$paths += $line
}
} else {
$new_stream += $line
}
}
Log $paths -join "`n"
Log "end"
Log $new_stream -join "`n"
$imports = $paths | select-string "^\s+import"
Log $imports
$import_map = [ordered]@{}
foreach ($line in $imports) {
# Allow for quoted paths (which contain spaces)
switch -regex ($line) {
"^\s+import\s+(\S+)\s+(\S+)$" {
Log "m: $($matches[1]) - $($matches[2])"
$import_map[$matches[1]] = $matches[2]
}
"^\s+import\s+`"(.+?)`"\s+(\S+)$" {
Log "m: $($matches[1]) - $($matches[2])"
$import_map[$matches[1]] = $matches[2]
}
"^\s+import\s+(\S+)\s+`"(.+?)`"$" {
Log "m: $($matches[1]) - $($matches[2])"
$import_map[$matches[1]] = $matches[2]
}
"^\s+import\s+`"(.+?)`"\s+`"(.+?)`"$" {
Log "m: $($matches[1]) - $($matches[2])"
$import_map[$matches[1]] = $matches[2]
}
}
}
$newimp = [ordered]@{}
if ($dofreeze) {
# Look for lines ending with "...", or at least not ending "@1234"
$search_datetime = ""
if ($freeze_datetime -and $freeze_datetime -ne "") {
$search_datetime = "`@$freeze_datetime"
}
$import_map.keys | ForEach-Object{
Log "$_ : $($import_map[$_])"
$change = ""
if (($import_map[$_].endswith("/...")) -or ($import_map[$_] -NotMatch "\@\d+$")) {
$p4args = $p4baseargs + "changes", "-m1", "-ssubmitted", "$($import_map[$_])$search_datetime"
Log "p4 $p4args"
$result = & p4 @p4args
Log "result: $result"
if ($result -and $result -ne "") {
$change = $result | %{$_.split()[1]}
Log "change: $change"
$change = "@$change"
}
}
$newimp[$_] = "$($import_map[$_])$change"
}
} else { # unfreeze
$import_map.keys | ForEach-Object{
Log "$_ : $($import_map[$_])"
$change = ""
$new_item = $import_map[$_] -Replace "\@\d+$", ""
$newimp[$_] = "$new_item"
}
}
Log "Old: $($import_map.values)"
Log "New: $($newimp.values)"
$new_stream = $new_stream -replace " unlocked ", " locked "
$tempfile = [System.IO.Path]::GetTempFileName()
Log "$tempfile"
Append-To-File "$tempfile" $new_stream
# We can add quotes around because they will be stripped automatically
# if no spaces
Append-To-File "$tempfile" ""
$paths_without_imports = $paths | select-string "^\s+import" -notmatch
Append-To-File "$tempfile" $paths_without_imports
$newimp.keys | ForEach-Object{
Append-To-File "$tempfile" " import `"$_`" `"$($newimp[$_])`""
}
$p4args = $p4baseargs + "stream", "-i"
$result = get-content $tempfile | p4 @p4args
exit 0
}
Catch
{
write-error $_.Exception
exit 1
}