phpで動くfcshラッパ作った

劣化した車輪の再発明です。まあ勉強ってことで。

できる事

  • fcshを通じての高速コンパイル
  • 指定したソースファイルが更新すると自動で再コンパイル
  • trace()をコンソール出力

動くのに必要な条件

  • PHP5以降
  • fcsh要 (fcshについてはこちら)
  • php,mxmlc,fcshにパスが通ってる

使い方

  1. 下のソースを適当なディレクトリに保存
  2. 環境に合わせて$trace_file_pathを修正
  3. php c:\hoge\fcshwrap.php c:\as3\foo.as みたいな感じで実行

ソース

<?php
// fcshwrap.php

if( !isset($argv[1])) exit();

// flashlog.txtのパス
$trace_file_path = 'C:\Users\user_name\AppData\Roaming\Macromedia\Flash Player\Logs\flashlog.txt';

if( !file_exists( $trace_file_path) || !is_file( $trace_file_path)) exit();

// fcshのエラーの出力先
$error_file_path = dirname( __FILE__) . '\error_output.txt';

// ソースファイルのパス
$source_file_path = $argv[1];

// fcshとの対話を始める
$descriptorspec = array(
   0 => array( 'pipe', 'r'),
   1 => array( 'pipe', 'w'),
   2 => array( 'file', $error_file_path, 'w')
);
$process = proc_open( 'fcsh', $descriptorspec, $pipes);
if( !is_resource( $process)) exit();
echo read_msg( $pipes[1]);

// まずはじめに一度コンパイル
write_cmd( $pipes[0], 'mxmlc' . ' ' . $source_file_path);
echo $msg = read_msg( $pipes[1]);

// IDゲット
$id = getid($msg);

// エラーファイルとトレースファイルのファイル更新時刻とサイズ
$source_file_size = filesize( $source_file_path);
$source_file_ctime = filectime( $source_file_path);
$trace_file_size = filesize( $trace_file_path);
$trace_file_ctime = filectime( $trace_file_path);

while(1)
{
    clearstatcache();
    
    // ソースファイルが更新したら
    if( $source_file_size != filesize( $source_file_path) || $source_file_ctime != filectime( $source_file_path)){
        
        clearstatcache();
        $source_file_size = filesize( $source_file_path);
        $source_file_ctime = filectime( $source_file_path);
        
        write_cmd( $pipes[0], 'compile ' . $id);
        echo read_msg( $pipes[1]);
    }
    
    // traceファイルが更新してたら
    if( $trace_file_size != filesize( $trace_file_path) || $trace_file_ctime != filectime( $trace_file_path)){
        echo file_get_contents( $trace_file_path);
        file_put_contents( $trace_file_path, '');
        
        clearstatcache();
        $trace_file_size = filesize( $trace_file_path);
        $trace_file_ctime = filectime( $trace_file_path);
    }
    
    usleep( 100000);
}

//------------------------------------------------------------------------------

// IDを抜き出す
function getid( $msg)
{
    $patern = '/fcsh: Assigned (\d+) as the compile target id/';
    preg_match( $patern, $msg, $matchs);
    
    return $matchs[1];
}

// コマンドを書き込む
function write_cmd( &$stm, $cmd) 
{
    echo "\n" . $cmd . "\n";
    fwrite( $stm, $cmd . "\n");
}

// fcshの吐くメッセージを読み取る
function read_msg( &$stm)
{
    $buf = '';                 // バッファ
    $end_str = "\r\n(fcsh)";   // fcshの発言の終わり
    
    do {
        $buf .= fgetc( $stm);
    } while( substr( $buf, -strlen( $end_str), strlen( $end_str)) !== $end_str);
    
    return substr( $buf, 0 , -strlen( $end_str)) . read_err();
}

// fcshの吐くエラーを読み取る
function read_err()
{
    global $error_file_path;
    
    $cont = file_get_contents( $error_file_path);
    file_put_contents( $error_file_path, '');
    
    return "\n" . $cont;
}

ハマった点

最初fcshのエラーストリームを適切に読み出す方法が最初わからなかったものの、rascutのソース覗いてみたら、ファイルに書き出させておいて必要なときにスクリプト側で読み出すという方法をとってたのでそれを見習った。

誰か使って見てください

そんで動かねえとかあったら教えてください