Can't Redirect Mercurial stdout/stderr Under Windows 2012 R2 Noninteractive Session

Jensen, Aaron ajensen at webmd.net
Sat Sep 20 04:07:11 UTC 2014


We have several automated build jobs that check changes into Mercurial. If they encounter unmerged heads on the outgoing server, the scripts will pull down those changes, merge them, then push everything back out (repeated until the push succeeds). In some cases, Mercurial would ask for input from the user, which caused our automated jobs to timeout. We can't use the --interactive flag because there are occasions we *didn't* want to choose `y` to Mercurial's questions. 

So, we wrote a wrapper script in PowerShell which starts a Mercurial as a background process and monitors it. If the script detects Merurial is asking a question, it will abort Mercurial, and fail the build with a friendly error message. This script also redirects Mercurial's stdout/stderr streams, reads them in, writes the errors to PowerShell's error stream, and converts Mercurial's output to objects, which consumers of our script use to perform additional processing.

Unfortunately, beginning with Windows 2012 R2 (we were using Windows 2008 R2 previously), the background Mercurial process started hanging when run by our build server (CruiseControl.NET running as an Administrator). It does not happen when I'm running at an interactive console. After several hours of research, it looks like redirecting Mercurial's stdout/stderr streams causes Mercurial to freeze and not output anything. Even running `hg help` hangs.

Here's how you can reproduce. Under CruiseControl.NET, or some other non-interactive process/service, run the following PowerShell code [1]. I'm pretty sure this is something in Mercurial because I switched the background process to `cmd.exe` with arguments of `@( '/c', 'echo fubar' )` and that process completes successfully.

Any ideas what would be causing this? How can I troubleshoot further?


[1]

    $startInfo = New-Object 'Diagnostics.ProcessStartInfo'
    $startInfo.UseShellExecute = $false
    $startInfo.FileName = 'hg.exe'
    $startInfo.Arguments = @( 'help' )
    # This filename/arguments don't hang
    # $startInfo.FileName = 'cmd.exe'
    # $startInfo.Arguments = @( '/c', 'echo fubar' )
    $startInfo.RedirectStandardOutput = $true
    $startInfo.RedirectStandardError = $true

    $process = New-Object 'Diagnostics.Process'
    $process.StartInfo = $startInfo

    $stdout = New-Object 'Collections.Generic.List[string]'
    $stderr = New-Object 'Collections.Generic.List[string]'

    $action = {
        if( $eventArgs.Data -ne $null )
        {
            $event.MessageData.Add( $eventArgs.Data )
        }
    }

    Register-ObjectEvent -InputObject $process -EventName "OutputDataReceived" -MessageData $stdout -Action $action | Out-Null
    Register-ObjectEvent -InputObject $process -EventName "ErrorDataReceived" -MessageData $stderr -Action $action | Out-Null

    $process.Start() 

    $process.BeginOutputReadLine()
    $process.BeginErrorReadLine()

    $process.WaitForExit()
            
    $stdout | Write-Output
    $stderr | Write-Error



More information about the Mercurial mailing list