একই স্থানীয় সংগ্রহস্থলে কাজ করা একাধিক গিট ক্লায়েন্টরা সেই লকের জন্য প্রতিযোগিতা করে। একজন ভাল নাগরিক হওয়ার জন্য অন্য পক্ষের দ্বারা লকটি প্রকাশ না হওয়া পর্যন্ত প্রতিটি ক্লায়েন্টের অপেক্ষা করা উচিত। আমাদের জন্য, সোর্স ট্রি বা এমএসভিএস মনে হয় আমরা বড় কমিট স্ক্রিপ্ট চলাকালীন পটভূমিতে কিছু রক্ষণাবেক্ষণ করছে।
পুনরায় চেষ্টা করতে সম্ভবত 'গিট' নিজেই একটি '--retriesWhenLock 5' যুক্তি সমর্থন করে argument অথবা ম্যানুয়ালি চালানোর সময় এটিতে ডিফল্টও।
এখানে "গিটর" নামের গিটের চারপাশে একটি পাওয়ারশেল র্যাপার রয়েছে যা সূচক না হওয়া পর্যন্ত পুনরায় চেষ্টা করে lock এটি কখনই সূচকটি সরিয়ে দেয় না। ব্যবহারকারীকে হস্তক্ষেপ করা উচিত বলে ধরে নিয়ে। এটি একটি বৃহত্তর কমিট স্ক্রিপ্ট থেকে বের করা হয়েছিল। এটিতে কেবল সহজ যুক্তি দিয়ে ন্যূনতম পরীক্ষা করা হয়।
- সি: \ বিনে স্ক্রিপ্ট অনুলিপি করুন এবং সি: \ বিনকে $ পাথের সাথে যুক্ত করুন।
- পিএস 1> গিটার - সহায়তা থেকে
- ডস%> পাওয়ারশেল গিটর - সহায়তা থেকে
gitr.ps1
#requires -version 2
<#
.SYNOPSIS
gitr
.DESCRIPTION
Run "git" as an external process with retry and capturing stdout stderr.
.NOTES
2017/05/16 crokusek: Initial version
#>
#---------------------------------------------------------[Initializations]--------------------------------------------------------
#Set Error Action
$ErrorActionPreference = "Stop";
#----------------------------------------------------------[Declarations]----------------------------------------------------------
$scriptDir = Split-Path $script:MyInvocation.MyCommand.Path
#Set-Location $scriptDir
## Disabled logging
# Log File
# $logFile = "$($scriptDir)\getr.log"
# If (Test-Path $logFile) { Clear-Content $logFile }
#-----------------------------------------------------------[Functions]------------------------------------------------------------
Function Log([string]$msg, [bool]$echo = $true)
{
$timestamp = "$(get-date -Format 'yyyy/MM/dd HH:mm:ss'): "
$fullmsg = $msg -replace '(?ms)^', $timestamp # the (?ms) enables multiline mode
## Disabled Logging
# Add-content $LogFile -value $fullmsg
if ($echo)
{
Write-Host $msg
}
}
Function ExecSimple([string]$command, [bool]$echo=$true, [bool]$stopOnNonZeroExitCode=$true)
{
$command, $args = $command -split " "
return Exec $command $args $echo $stopOnNonZeroExitCode
}
Function Exec([string]$exe, [string[]]$arguments, [bool]$echo=$true, [bool]$stopOnNonZeroExitCode=$true)
{
# Passing $args (list) as a single parameter is the most flexible, it supports spaces and double quotes
$orgErrorActionPreference = $ErrorActionPreference
Try
{
$error.clear() # this apparently catches all the stderr pipe lines
if ($false -and $exe -eq 'git') # todo make this a generic flag
{
$exe = "$($exe) 2>&1"
}
$output = ""
$argflattened = $arguments -join ' '
Log "`n% $($exe) $($arguments)`n"
# This way some advantages over Invoke-Expressions or Start-Process for some cases:
# - merges stdout/stderr line by line properly,
# - echoes the output live as it is streamed to the current window,
# - waits for completion
# - works when calling both console and windows executables.
#
$ErrorActionPreference = "Continue" # required in order to catch more than 1 stderr line in the exception
if ($echo)
{
# Using "cmd.exe" allows the stderr -> stdout redirection to work properly. Otherwise the 2>&1 runs after PS for
# some reason. When a command such as "git" writes to stderr, powershell was terminating on the first stderr
# line (and stops capturing additional lines).
#
# but unfortuantely cmd has some bizarre de-quoting rules that weren't working for all cases.
#& cmd /c "`"" $exe $arguments "`"" | Tee-Object -variable output | Write-Host | out-null
# This is simplest but has some issues with stderr/stdout (stderr caught as exception below)
#
& $exe $arguments 2>&1 | tee -variable output | Write-Host | out-null
}
else
{
& $exe $arguments 2>&1 | tee -variable output | out-null
}
$output = $output -join "`r`n"
if ($stopOnNonZeroExitCode -and !$LASTEXITCODE -eq 0)
{
throw [System.Exception] "Exit code ($($LASTEXITCODE)) was non-zero. Output:`n$($output)"
}
}
catch [System.Management.Automation.RemoteException]
{
$output = $_.Exception.ToString().Replace("System.Management.Automation.RemoteException:", "").Trim()
if ($output.Contains("fatal"))
{
throw
}
if ($echo)
{
Log $output
}
}
finally
{
$ErrorActionPreference = $orgErrorActionPreference;
}
if (-not $output -eq "")
{
Log $output $false # don't echo to screen as the pipe above did
}
return $output
}
Function ExecWithRetry([string]$exe, [string[]]$arguments, [bool]$echo=$true, [bool]$stopOnNonZeroExitCode=$true,
[int]$maxRetries = 5, [int]$msDelay = 3000, [AllowNull()][string]$exceptionMustContain = $null)
{
for ($i = 0; $i -lt $maxRetries; $i++)
{
try
{
Exec $exe $arguments $echo $stopOnNonZeroExitCode
return
}
catch
{
if (-not [string]::IsNullOrEmpty($exceptionMustContain) -and $_.Exception.ToString().Contains($exceptionMustContain))
{
Log "Last Error from $($exe) is retryable ($($i + 1) of $($maxRetries))" $true
Start-Sleep -Milliseconds ($msDelay);
continue
}
throw
}
}
throw [System.Exception] "Unable to successfully exec '$($exe)' within $($maxRetries) attempts."
}
Function GitWithRetry([string[]]$arguments, [bool]$echo=$true)
{
ExecWithRetry "git" $arguments $echo -exceptionMustContain "Another git process seems to be running"
}
#-----------------------------------------------------------[Main]------------------------------------------------------------
function Main([string[]]$arguments)
{
GitWithRetry @($arguments)
}
#-------------------------------------- Startup ------------------------------------
try
{
Main $args
Exit 0
}
catch
{
#Log "*** A fatal error occured: $($_.Exception)"
#Read-Host -Prompt "`nA fatal error occurred, press enter to close."
exit 1
}