nyagos の自動アップデート機能(まだ道半ば)

自動アップデート機能なんてものは nyagos 自身に組み込むべきではないので、別の実行ファイルにする。だが、Goで組むとすぐ数メガバイトいってしまって望ましくない。

ということで、PowerShell で試作してみた。 今のところ、ZIPをダウンロードしてくるだけで、現行のものを差し替えることまではしない。

# $installed_version = (nyagos --show-version-only)
$installed_version = "4.4.6_0-windows-amd64"

function parseVer($s){
    $s = ($s -split "-")[0]
    $ver = 0
    foreach($v in $s -split "[_\.]"){
        try{
            $ver = $ver * 100 + [Convert]::ToInt32($v,10)
        }catch{
            break
        }
    }
    $ver
}

function getOsArch($s){
    $spec = $s -split "-"
    $spec[ $spec.Length - 2 ] + "-" + $spec[ $spec.Length - 1 ]
}

$download_pattern = "*" + (getOsArch $installed_version) + "*"
$installed_version = (parseVer $installed_version)

$cli = New-Object System.Net.WebClient
$cli.Headers['User-Agent'] = "nyagos_update"

$list = @{}

Invoke-RestMethod "https://api.github.com/repos/zetamatta/nyagos/releases" |
foreach-object {
    $_ | where-object{
        $_.tag_name -match "^[0-9]+\.[0-9]+\.[0-9]+_[0-9]+$" -and
        (parseVer $_.tag_name) -gt $installed_version
    } | foreach-object{
        $_.assets | Where-Object{ $_.name -like $download_pattern } |
        foreach-object{
            # $list[ (parseVer $_.name ) ] =
            #    @{ name=$_.name;url=$_.browser_download_url }
            Write-Output @{ name=$_.name;url=$_.browser_download_url }
            $cli.DownloadFile( $_.browser_download_url , $_.name )
        }
    }
}

nyagos は nyagos --show-version-only で自分のバージョンを標準出力へ吐いてくれる。これより大きいタグが Releases で見つけたら、要バージョンアップだ。今はテスト中なので固定値を放り込んでいる。

GitHub の Releases の履歴をとる API は、PowerShell ならば Invoke-RestMethod "https://api.github.com/repos/zetamatta/nyagos/releases" だけで Ok だ。戻り値は JSON オブジェクトに最初からなっている。

だが、その JSON オブジェクトは階層が一つ深いので、一回 ForEach-Object でトップ階層を読んで、その $_ を改めて解析してやらないといけない。

当初、これに気づかなくて、えらくハマってしまった。ForEach-Object を深くする前、$_.tag_name で得られるタグ名が現在走査しているリリースのタグネームではなく、全履歴のタグ名になっていた。おそらく、子要素の "tag_name" の値を全部検索してもってきてしまったのだろう。

その結果、$_.tag_name -match "~" の結果が True / False ではなくて、パターンにマッチする履歴のタグすべての集合になっていた。-match 演算子は左辺が文字列の時は True/False が得られるが、左辺が配列の時はマッチする要素のリストになってしまう。リストを Boolean として評価すると常に真になってしまう。そのため、本来排除したい 4.2.0_beta みたいな数字ではないタグがどうしても排除できず、小一時間悩むことになる。

アップデート対象となる履歴がわかれば ZIP ファイルのダウンロードだ。このダウンロードは System.Net.WebClient を使う。注意点としては GitHubを相手にする時は User-Agent を何でもいいのでちゃんと設定しておかないといけないという点だ。でないと 403 Forbidden されてしまう。

さて、ここまで来たら、ダウンロードした ZIP ファイルを展開して、それを現行のものと差し替えることになる。ところが、ここでやる気がなくなってしまう。次回乞うご期待