<# .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 }