2011-07-06 2 views
2

私は、Mercurialコマンドラインクライアントと話すクラスライブラリを変更しようとしています。1.9クライアントの新機能は、サーバをスピンアップして標準の入出力パイプを介してそれを話す能力です。これは本当に有望です。Mercurialコマンドラインクライアントを使用する際の重大な頭痛の1つは、Pythonで書かれているので、バージョンを尋ねるだけでも、クライアントをスピンアップするオーバーヘッドが少しあります。入力ストリームを連続的にフラッシュするために.NET Processオブジェクトを取得しますか?

しかし、1つの問題があります。今までは、標準出力/エラーを読み込んでコマンドラインクライアントから出力を取得しました。プロセスが終了すると、ストリームがフラッシュされ、ストリームの終わりを読み取ることができます。

しかし、この新しいモードでは、プロセスは多くのテキストを標準エラー出力にダンプし、次のコマンドを待っています。オーバーヘッドを減らすのに最適ですが、.NETがそれらのストリームをバッファリングするので、厄介です。私は別のコマンド に発行

  • を終了するプロセスを頼む

    1. :プロセスが終了しないので、言い換えれば

      は、私がするまでその出力の最後の部分を得ることはありません

      1. に私のための方法は、私がバッファ内にあるものは何でも得ることを意味し、フラッシュするEVをバッファを掲載ありバッファをそれ自身でフラッシュするのに十分でない場合は?
      2. もしそうでなければ、バッファサイズを1文字に設定できますか?
      3. 他に何かできますか?

      私はP/Invokeを処理することができます。

      は、ここで説明しますLINQPad概念実証プログラムです:それは何

      は、コマンドプロンプトをスピンアップし、それをDIRコマンドを送り、しかしそれらの10秒は、ループ内で経過していないまでということに気づくですプログラムはディレクトリ一覧を作成した直後にコマンドプロンプトが出力する "C:>"プロンプトを出力しますか?

      つまり

      が、これはコマンドプロンプトが何をするかです:

      1. 促すことにより
      2. は、別のコマンドを求める上場プロデュースディレクトリ:

      はしかし、これは "C> \"以下のプログラムは見るもの:

      1. プロデュースディレクトリリスト
      2. を210
      3. (10秒待つ)
      4. 入力ストリーム
      5. を閉じますが、プロンプト

        無効メイン(){ 文字列clientExecutablePath =「CMDを参照してください。exeファイル ";

        var psi = new ProcessStartInfo(); 
        psi.FileName = clientExecutablePath; 
        psi.RedirectStandardError = true; 
        psi.RedirectStandardInput = true; 
        psi.RedirectStandardOutput = true; 
        psi.CreateNoWindow = true; 
        psi.WorkingDirectory = @"C:\"; 
        psi.WindowStyle = ProcessWindowStyle.Hidden; 
        psi.UseShellExecute = false; 
        psi.ErrorDialog = false; 
        psi.StandardErrorEncoding = Encoding.GetEncoding("Windows-1252"); 
        psi.StandardOutputEncoding = Encoding.GetEncoding("Windows-1252"); 
        
        var p = Process.Start(psi); 
        
        var input = p.StandardInput; 
        var output = p.StandardOutput; 
        var error = p.StandardError; 
        
        Action<StreamReader, string> reader = delegate(StreamReader streamReader, string prefix) 
        { 
            string line; 
            while ((line = streamReader.ReadLine()) != null) 
            { 
             Debug.WriteLine(prefix + line); 
            } 
        }; 
        
        IAsyncResult outputReader = reader.BeginInvoke(output, "o: ", null, null); 
        IAsyncResult errorReader = reader.BeginInvoke(error, "e: ", null, null); 
        
        input.Write("dir\n"); 
        input.Flush(); 
        
        while (!p.HasExited) 
        { 
            Thread.Sleep(10000); 
            input.Close(); 
        } 
        
        reader.EndInvoke(outputReader); 
        reader.EndInvoke(errorReader); 
        

        }

  • +0

    私は今、それが説明する正規CMD.EXEプログラムを使用して、Mercurialの依存をドロップするようにプログラムを変更しました。 –

    +0

    こんにちは、私はここで同じ問題を抱えています。そしてもしそうなら、どうですか? :) – FrieK

    答えて

    1

    私はフラッシュを強制的にどのような方法はないと思う、しかし私はあなたを助けるかもしれない代替案のカップルを持っている:

    1. 私はストリームを読み込むためにReadLine()を使用していることに注意してください。これは、完全な出力行(CRLFまたは少なくともLFを含む)が書き込まれるまで戻りません。 1文字だけを読み込みます。サーバープロセスが終了するまで最後の行にCRLFを書き込んでいない場合は、探している出力の最後の部分です。
    2. プロセスのOutputDataReceivedイベントとErrorDataReceivedイベントにハンドラを追加してストリームを非同期で読み取ってから、BeginOutputReadLineとBeginErrorReadLineを使用してデータの受信を開始できます。私はイベントがどのくらい頻繁に呼び出されるかわからない:データが利用可能であるかどうか、データの完全な行が受信されるたびに、またはすべての文字について、定期的な間隔で。

    HTH、

    バート

    +0

    私は両方を試みます! –

    +0

    もちろん、それは完全に自己完結したバッファーであるかもしれません。Mercurialコマンドクライアントからの出力には、とにかくいくつかのファンキーな文字が入りますので、 "o characters "の場合、これらのバイトを取り除く必要があります。バッファリングがストリーム内にあると仮定しましたが、もちろんReadLineにもバッファリングがあります。その違いを知らないうちに私は働かなかったでしょう。 –

    関連する問題