PowerShellによるMMLファイル監視 – 非同期版

PowerShellによるMMLファイル監視 – 非同期版

 windows上のppmckやnsd.Libで使用するスクリプト非同期版です。
PowerShellによりmmlファイルの更新チェック機能を提供します。

もし、同期版の説明が必要であるならば、同期版を参考にして下さい。ライセンスについてもこちらで表示しています。

mmlファイルドロップで監視を始める点は同期版と同じですが、
できるだけバッチファイルを使用しない版で、総パワーシェル仕様です。
PowerShell2.0以降に対応します

 必要なのは、前回と同じく4つのスクリプトです。 powershellを呼び出すバッチファイル、mmlファイルのパスチェッカ、監視スクリプト本体、コンパイラとプレイヤーを呼び出すスクリプトです。
それとppmckのみ、set_envs.bat,mknsf.batをPowerShellスクリプトに置き変えたものを用意しました。

このうちのふたつ、powershellを呼び出すバッチファイルDrop.batと、mmlファイルパスチェッカchk_mml.ps1は、同期版とまったく同じものを使います。 このため非同期版は、監視スクリプトからの説明とします。

 それと、全てのスクリプトが入れてあるmml_watch.zipも置きました。 よろしければダウンロードしてみて下さい

注: mml_watchは、ver2bにアップデートしたため当該ファイルは、圧縮ファイル内の旧版ver1となります

 


 

□ mml_watch.ps1 – 非同期処理のファイル監視スクリプト 
 では非同期処理のファイル監視スクリプト、mml_watch.ps1から説明を始めます。

 基本的に挙動は同期版と同じですが、主にファイル変更の判定をイベントハンドラでしている点、try catchを使用している点に違いがあります。

エラーcatch時には、pauseの代わりとなるRead-Host “—” | Out-Nullでスクロールを止めるようにしています。 あと、$Argsをわざわざ$Args_pathにコピーしているのは、再ループ時に$Argsが書き換えられるためです

mml_watch.ps1

— ppmck,nsd共通

$ErrorActionPreference = “Stop”
try{

$Args_path = $Args # $Args overwrite after

.\nsf_trans.ps1 $Args_path[0] # Command

while(1){

    Add-Type -AssemblyName System.Windows.Forms | Out-Null
    $m = New-Object System.Windows.Forms.Form
    $m.WindowState = [System.Windows.Forms.FormWindowState]::Minimized
    $m.ShowInTaskbar = $false

    $w = New-Object System.IO.FileSystemWatcher
    $w.Path = $Args_path[1]
    $w.Filter = $Args_path[2]
    $w.NotifyFilter = [System.IO.NotifyFilters]::LastWrite
    $w.SynchronizingObject = $m

    $w.add_Changed({ # イベント

        Write-Host ($_.Name+ ” MODIFY`r`n”)

        .\nsf_trans.ps1 $Args_path[0] # Command

        $w.EnableRaisingEvents = $false # 終了
        $m.Dispose()
    })

    Write-Host “”
    Write-Host “Setting up watches.”
    Write-Host “Watches established.`r`n”

    $w.EnableRaisingEvents = $true # 開始
    [void]$m.ShowDialog()

} #
}
catch [Exception]{ #err_all
    Write-Host $_.exception
    Read-Host “続けるにはENTERキーを押して下さい” | Out-Null
}

参考url

 


 

□ nsf_trans.ps1 – mmlコンパイラとプレイヤーを呼び出すスクリプト 
 mmlコンパイラとプレイヤーを呼び出すスクリプトnsf_trans.ps1です。
空白のあるファイルパスに対応しています

 パワーシェルはパスの扱いで、いくつかの注意点があったのでそれを説明します。
PowerShellスクリプト間やシェルのコマンドに送るのであれば、パラメータをオブジェクトとして送っているらしく、ファイルパス名を ” で挟む必要ありません。
これとは違い、実行ファイルのnsc、nsfplay,VirtuaNSFへファイル名を送る時には文字列としているようです。 このため、”`””このようにダブルバックスラッシュをエスケープしたものをつかって、ファイルパス名を囲って対応しました

 & $exe_nsc -n -e $mml | Write-Hostについて。
$exe_nsc= “..\bin\nsc.exe”として実行ファイルを変数オブジェクト化した場合、単に$exe_nscと書き込んだだけでは、コマンドとして認識しません。 コマンド化したい場合は、実行演算子&をつけます。
また、nscのパラメータ -n -eは、オブジェクト内に入れると、上手く実行できないので外に置いてます。
そして次にくる$mmlは上記のとおり、”`””で囲った文字列として送り出しています。
最後の | Write-Hostはコンソール出力するためのものです。 そのままだと、mml_watch.ps1で呼び込んだフォームオブジェクト側に出力されるためか、コンソール側にnscから出力がきません。 パイプを経由して、nscの出力をコンソールへ読み込んでいます。

 function化について。
function err_chk($ErrLev)としたのは、メッセージ出力をできるだけ上へ置くためです。このほうが、最終的に何を行うのか把握しやすかったりします

 なお、前回と同じく、プレイヤー呼び出す当スクリプトでは、2行だけ環境に合わせて修正をする必要があります。
$exe_path に記述した、プレイヤーまでのファイルパスを的確に記述して下さい。
nsfplay,VirtuaNSFの両プレイヤーは、$exe_pathに記述したコメント記号 # の付け外しによって、選択される形となります

nsf_trans.ps1

— ppmck,nsd共通

cd (Split-Path -Parent $MyInvocation.MyCommand.Path)

#$exe_player= “..\..\nsfplay\nsfplay.exe”
$exe_player= “..\..\VirtuaNSF\VirtuaNSF.exe”

$exe_nsc= “..\bin\nsc.exe”

function err_chk($ErrLev){

    Write-Host “”
    Write-Host (“exitcode :”+ $ErrLev)

    if($ErrLev -ne 0){
        Write-Host “”
        Write-Host “// NSFfile: failure !//”
    }else{

        start $exe_player $nsf
    }
} #func

$nsf= “`””+ $Args[0]+ “.nsf`”” # esc[`”]
$mml= “`””+ $Args[0]+ “.mml`””

if((Test-Path .\mck_script\mknsf.ps1) -eq $true){ # ppmck chk

    .\mck_script\mknsf.ps1 $Args[0] | Write-Host # Command
}else{

    & $exe_nsc -n -e $mml | Write-Host # Command
}

err_chk($LASTEXITCODE)

参考url

 以上の3つのスクリプトをbinと同階層になるように、mck\mml_watch_hi, nsd\mml_watch_hi のような、単一フォルダに全て入れて下さい。
次に、ppmckのみ必要になるスクリプト、mknsf.ps1について説明します

 


 

□ mknsf.ps1 – set_envs.batとmknsf.batをPowerShellで再記述 
 set_envs.batとmknsf.batをPowerShellで書き直したmknsf.ps1を準備します。

このスクリプトはppmckのみに使用します。
以下のフォルダmck\mml_watch_hi\mck_scriptに置いて下さい。
このスクリプト.\mck_script\mknsf.ps1の有無により、上位スクリプトnsf_trans.ps1がppmck,nsd.Libを切り換えています

 簡単ではありますが、順に内容の説明をします。
$Env:は環境変数のセットです。DOSのsetコマンドと同義です。
move -force はパラメータを付けて移動上書きをしています。
DOSのMOVE /Yと同じです。
最後の行の、exit $LASTEXITCODEは、上位スクリプトに
エラーレベルを返すことを意味してます

mknsf.ps1

— ppmck

$Env:PPMCK_BASEDIR = “..”
$Env:NES_INCLUDE = $Env:PPMCK_BASEDIR+ “\nes_include”
$Env:DMC_INCLUDE = [System.IO.Path]::GetDirectoryName($Args[0])

$exe_ppmckc= $Env:PPMCK_BASEDIR+ “\bin\ppmckc.exe”
$exe_nesasm= $Env:PPMCK_BASEDIR+ “\bin\nesasm.exe”

$mml= “`””+ $Args[0]+ “.mml`””
$nsf= $Args[0]+ “.nsf” # shell only

if((Test-Path .\effect.h) -eq $true){ del .\effect.h }
& $exe_ppmckc -i $mml # Command

if($? -eq $true){

    if((Test-Path .\ppmck.nes) -eq $true){ del .\ppmck.nes }
    & $exe_nesasm -s -raw ppmck.asm # Command

    if($? -eq $true){

        move -force .\ppmck.nes $nsf
    }
}

exit $LASTEXITCODE

参考url

 これで必要なスクリプトが揃いました。 ここからは、監視スクリプトのテストをします。

 


 

□ nsf_trans.ps1 – 変換スクリプトのテスト 
 変換スクリプトのテスト手順です。

まず、mck\mml_watch_hi と、nsd\mml_watch_hi のフォルダにそれぞれに対応したsample.mml などを置きます。

各フォルダ上でコマンドプロンプトを立ち上げ、長いワンライナーで申し訳ありませんが、以下のコマンドを打って、順に確認してください。 ファイル名であるsampleを引数として、パワーシェルスクリプトをRemoteSignedポリシーで実行するというコマンドです

> powershell -ExecutionPolicy RemoteSigned -File nsf_trans.ps1 sample

 無事nsfファイルが出力され、滞りなくプレイヤーから再生されたら、テストはokです。

  うまくコンパイルできないケースについて。

・スクリプトの置く場所が間違っている可能性があります。
 binのあるフォルダ階層と同じ、1階層下へ置き直してみて下さい。

・ないし、ppmck, nsd.Libの切り換えミスも考えられるので、mck_scriptフォルダ、
 mknsf.ps1の有無を確認します。

・nsd.Libから、../../bin/nsd.bin: No such file or directory などと返される場合は、
 MMLの記述を、#Code “../bin/nsd.bin”のように変更をお願いします。
 binと同じ階層、1階層下であるスクリプトのディレクトリがカレントとなっているためです。

・プレイヤーが起動しないのであれば、nsf_trans.ps1に書き込んだ
 プレイヤーパスの記述が間違っているかもしれません

 もし、ここまでうまくいっているようなら、残りのテストは一つのみです。

 

□ Drop.bat – 監視スクリプトの起動テスト 
 監視スクリプトの起動テストを行います。

Drop.batにsample.mml をドロップすると
コマンドプロンプトが立ち上がりファイル監視を始めるはずです。
エディタなどでsample.mml を開き、a>cf など入力して再保存すれば、即座に反映すると思います。

 なお、Ctrl+C での終了はできないので、監視をやめたい時はウィンドウを閉じて下さい

 最後にワンポイントです。Drop.batのショートカットをつくっておくと、ちょっとだけ幸せになれるかもしれません、

 

□ 所感として 
 パス取得において、少しだけ気になったこと。

 ppmckは、1階層下のmck\songsで運用することを前提に構成されているようなのですが、nsd.Libには、もともとsongsフォルダらしきものがないので、各々の環境はまちまちのようです。

もし、nsd.Libで見受けられる2階層下側で運用する場合は、パスを適切に修正すれば一応動くとは思います。
nsd.Libでは、nsf_trans.ps1の$exe_nsc= “..\bin\nsc.exe”、
ppmckであれば、mknsf.ps1の$Env:PPMCK_BASEDIR = “..”、が直すべき部分になると思います

 ただ、階層が深くなるとその分、mmlファイルやスクリプト側のパス記述が増えることもあり、実行ファイルとスクリプトは、できるなら直近に置くのがベストな気がしてます。
mck\mml_watch_hi やnsd\watch_hi のような1階層下のフォルダに、スクリプトをアサインしたのはこの様な理由のためです。

パス取得で苦心したためか、できるだけ仕様が統一されているとありがたいなあとなんとなく思った次第です

 


 

□ 謝辞 
 参考リンクという形ばかりではありますが、今回のPowerShellをつくるにあたり、多くのサンプルと解説を参考にさせていただきました。 この場を借りてお礼を言います

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中