この記事は連載物のひとつになっています。
前回扱った内容が前提になっているため(下に概要は載せていますが)一読しておくことをおすすめします。
守章: Scoopの基礎、簡単なManifestの作成
破章: バージョン管理と自動アップデート ← (今回はこれ)
離章: Scoopを用いた環境構築する際の勘所
今回はKaoriYa版Vimなどを題材に、Scoopでのバージョン管理を担うcheckver属性とautoupdate属性について解説します。
そして今回も環境構築には触れません。公式WikiよりApp Manifest Autoupdateの和訳です。
たぶんいないだろうけどKaoriYa版Vimのかんたん導入だけ知りたい人は前回の記事を読んだ上でこれを読んでください。
おさらい
前回はScoopを使うメリットと利用法を学びました。PowerShell3.0以上があれば導入も操作も簡単です。
そして下のようなJSONをGitリポジトリに登録し公開することで、誰でも自由に拡張できることも知りました。
{"##":"実行中にUAC昇格ポップアップが出ます。","license":{"identifier":"Freeware","url":"http://technet.microsoft.com/ja-jp/sysinternals/bb469936"},"depends":["sudo"],"version":"2.0","url":"http://download.sysinternals.com/files/Ctrl2Cap.zip","hash":"2d8c06374da140beda79ac1940ab2b06a56a9af182dba70a6338313d768a2ac2","installer":{"script":["sudo $dir\\ctrl2cap.exe /install","if ($? == $false) {"," Write-Host '===================================' -Foreground Red"," Write-Host 'ctrl2capの実行に失敗しました。' -Foreground Red"," Write-Host '===================================' -Foreground Red","}"]},"bin":"ctrl2cap.exe","shortcuts":[["ctrl2cap.exe","Ctrl2cap"]],"notes":["再設定をしたい場合は、以下の手順で行ってください。","- スタートメニューから「Ctrl2cap」で検索、管理者権限で実行","- 管理者権限のプロンプトで 'ctrl2cap /uninstall' を実行",]}
前回紹介したうち主要な属性の概要です。
属性 | 値 |
---|---|
bin | パスを通したいファイル |
depends | 依存するManifest |
hash | hash値 ※準必須属性 |
installer | インストール処理 |
notes | インストールの全処理完了後に出す文 |
shortcuts | スタートメニューに作るショートカット |
url | ダウンロードするファイル ※必須属性 |
version | バージョン ※必須属性 |
## | コメント |
補足: architecture属性、extract_dir属性
バージョン管理について知る前に、前回紹介できなかったarchitecture属性そしてextract_dir属性について話しておきます。
以下に今回メインの題材となるKaoriYa版Vim(以降 Vim 表記)の簡単なManifestを載せておきます。
{"homepage":"https://github.com/koron/vim-kaoriya","description":"Vim + kaoriya build system, without gvim.","version":"8.1.0005.20180520","architecture":{"32bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v8.1.0005-20180520/vim81-kaoriya-win32-8.1.0005-20180520.zip","hash":"afacd6e27304136f5ebae3edddf6e747f410880fa6a986d80be772e03ef56d36","extract_dir":"vim81-kaoriya-win32"},"64bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v8.1.0005-20180520/vim81-kaoriya-win64-8.1.0005-20180520.zip","hash":"53e8dd08e2249ce8a54784e16469151a7bf9857ac9acf3a1b341ac4e7da26fb2","extract_dir":"vim81-kaoriya-win64"}},"bin":"vim.exe"}
url/hash/extract_dirと3つの属性がarchitecture属性内の32bitおよび64bit属性に移動しています。
architecture属性を用いることで、このようにアーキテクチャ毎にリソースが異なる場合でも分離することができます。
参考までに、architecture属性によって分割できる属性は以下の通り。
- url
- hash
- bin
- shortcuts
- pre_install
- post_install
- installer
- uninstaller
- extract_dir
そしてextract_dir属性は、使用するディレクトリを抜き取るための属性です。擬似的にルートディレクトリを変更する属性、とも言えるでしょうか。
説明のために64bit版zipファイルを展開したときのツリービューを載せておきます。
.
└── vim81-kaoriya-win64
├── lua
│ ├── ...
~
├── vim.exe
├── vimrc
├── vimrun.exe
├── winpty-agent.exe
├── winpty.dll
└── xxd.exe
このままだとルート直下にvim81-kaoriya-win64
しか存在していない状態となってしまい、もしvimにパスを通すならbin属性にvim81-kaoriya-win64\\vim.exe
を渡さなければなりません。
しかしextract_dir属性に任意のディレクトリ、今回はvim81-kaoriya-win64
を指定することで実質的にルートが変更され、bin属性の値がvim.exe
とシンプルになるだけでなく後述するようにバージョン変更にも強くなります。
それでは気を取り直して、バージョン管理のための属性について見ていきましょう。
checkver属性
checkver属性は以下の内容に対して検索をかけることで、バージョンの取得を行うための属性です。
- GitHubリリースページのURL
- HTMLファイル
- JSON
ちなみに前回解説し忘れてしまったのですが、version属性も含めてバージョンは英数字と+-._
の組み合わせで構成されている必要があります。
GitHubのリリースURLから取得
一番楽なのはGitHubの最新版リリースページのURLを見る方法です。
nvmとcmderがこれを採用しているので見てみましょう。
"homepage":"https://github.com/coreybutler/nvim-windows","checkver":"github",
"homepage":"https://cmder.net","checkver":{"github":"https://github.com/cmderdev/cmder"},
ご覧の通り、homepage属性にGitHubリポジトリを当てているかで表記が変わります。
当てている場合はcheckver属性にgithub
を、そうでない場合はgithub属性を持ったオブジェクトを当てます。処理内容はどちらも同じでhttps://github.com/USERNAME/REPONAME/releases/latest
のリダイレクト先URLにあるタグからバージョンを取得します。
ちなみにこの方法が使えるのは、
- プレリリース版ではない
- タグが
^v?[\d.$]+$
の正規表現に適合する
これら2点を満たしている場合のみです。意外と限定的。
HTMLから取得
つづいて、HTMLの中から探す方法を見てみましょう。
一番よく行われているのはダウンロードするファイル名を検索する方法です。
たとえばgitのcheckverはこんな感じになっています。
"checkver":{"url":"https://github.com/git-for-windows/git/releases/latest","re":"v(?<version>[\\d\\w.]+)/PortableGit-(?<short>[\\d.]+).*\\.exe"},
url属性に対象となるURLを指定するのですが、指定したHTMLにバージョン情報しか記載されていないことはまずないので、re属性も付け加えます。こうすることで得られるHTMLから抜き出すことができます。
この正規表現の書き方にもちょっとした拡張があり、丸括弧中の先頭に?<VAR_NAME>
という接頭辞をつけることで、一致した内容に名前をつけることができます。ここでversion
という名前をつけるとそれがバージョンとして認識される仕組みです。丸括弧がひとつだけなら?<version>
すら不要です。
一方で、バージョンの構成要素が分散してしまっていたり、そのまま抜き出そうとすると曖昧すぎるマッチングになってしまう例もあるかと思います。このような場合はreplace属性を利用しましょう。
たとえばeclipse-platformを見てみましょう。
"checkver":{"url":"http://download.eclipse.org/eclipse/downloads/","re":"<a href=\"(?<drop>drops4/R-(?<release>[\\d.]+[a-z]?)-(?<date>[\\d]{12}))/\" title=\"Latest Release\">([\\d.]+)","replace":"${release}-${date}"},
このようにreplace属性内でマッチ結果をつなぎあわせることでバージョンを生成することができます。
それと、x264のリリースページのように、マッチする箇所が昇順に複数並んでいるけどそのうちの一番下にあるファイル名からコードを抜き出したい場合もあったりします。
そういうときはreverse属性にtrue
を指定してください。
"checkver":{"url":"https://download.videolan.org/pub/videolan/x264/binaries/win64/","re":"x264-r(?<version>[\\d]+)-(?<commit>[a-fA-F0-9]{7}).exe","reverse":true},
またhomepage属性に指定したURLにバージョンが入っている場合は省略した記法ができます。
"homepage":"http://www.7-zip.org/","checkver":"Download 7-zip ([^\\ ]+)",
JSONから取得
あまり見ないですが、JSONファイルにバージョンがある場合はjp属性にJSONPathで指定することで取得できます。
以下にNuGetのcheckverを挙げておきます。
"checkver":{"url":"https://dist.nuget.org/index.json","jp":"$.artifacts[0].versions[0].version"},
実際にやってみる
一通り方法が分かったところで、先程のVimにcheckver属性を付けてみましょう。
このリポジトリのタグは^v?[\d.]+$
の正規表現にマッチしないので、リリースページURLを利用する方法は使えません。
ここはわかりやすくリリースページのHTMLから取得する方法を採りましょう。
{"homepage":"https://github.com/koron/vim-kaoriya","description":"Vim + kaoriya build system, without gvim.","version":"8.1.0005.20180520","architecture":{"32bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v8.1.0005-20180520/vim81-kaoriya-win32-8.1.0005-20180520.zip","hash":"afacd6e27304136f5ebae3edddf6e747f410880fa6a986d80be772e03ef56d36","extract_dir":"vim81-kaoriya-win32"},"64bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v8.1.0005-20180520/vim81-kaoriya-win64-8.1.0005-20180520.zip","hash":"53e8dd08e2249ce8a54784e16469151a7bf9857ac9acf3a1b341ac4e7da26fb2","extract_dir":"vim81-kaoriya-win64"}},"bin":"vim.exe","checkver":{"url":"https://github.com/koron/vim-kaoriya/releases/latest","re":"vim(?<short>[\\d]+)-kaoriya-win32-(?<code>[\\d.]+)-(?<date>[\\d]{8}).zip","replace":"${code}.${date}"}}
code
に該当する部分だけでもいいのですが、個人的には更新日も知りたかったので入れてみました1。
ついでにcheckver属性を編集したら現在のversion属性もこれに合致するかどうか確認しておく癖を付けておくとなおいいです。
autoupdate属性
autoupdate属性ではcheckver属性で取得したバージョンを用いて、以下の属性を更新するための雛形を定義できます。
- url
- hash
- extract_dir
- notes(バージョン情報の使用不可)
今回はurl属性を例に解説していきます。
バージョン情報を埋め込む
バージョンは$version
という文字をそのまま埋め込むだけです。
"autoupdate":{"url":"https://beyondgrep.com/ack-$version-single-file#/ack-single-file"}
またバージョンがドット区切りであるならば各構成要素を示す特殊変数も使えます。$version
が4つに区切られている場合は順に$majorVersion
$minorVersion
$patchVersion
$buildVersion
となります。
"version":"4.76","url":"https://justgetflux.com/flux-setup4-76.exe#/flux-setup.exe","autoupdate":{"url":"https://justgetflux.com/flux-setup$majorVersion-$minorVersion.exe#/flux-setup.exe"}
architecture属性でurlが分けられている場合は、autoupdate属性内にarchitecture属性をつくります。
"autoupdate":{"architecture":{"64bit":{"url":"https://static.rust-lang.org/dist/rust-$version-x86_64-pc-windows-gnu.msi"},"32bit":{"url":"https://static.rust-lang.org/dist/rust-$version-i686-pc-windows-gnu.msi"}}}
checkver属性で使った値を利用する
checkverのre属性で変数を設定することができましたが、これをautoupdateの中でも利用することができます。
ただしreplace属性とは違って、abc
という変数はmatchAbc
と変数名が変わります。
先ほどのVimにはこれが使えそうですね。
"checkver":{"url":"https://github.com/koron/vim-kaoriya/releases/latest","re":"vim(?<short>[\\d]+)-kaoriya-win32-(?<code>[\\d.]+)-(?<date>[\\d]{8}).zip","replace":"${code}.${date}"},"autoupdate":{"architecture":{"32bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v$matchCode-$matchDate/vim$matchShort-kaoriya-win32-$matchCode-$matchDate.zip"},"64bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v$matchCode-$matchDate/vim$matchShort-kaoriya-win64-$matchCode-$matchDate.zip"}}},
hash属性を設定する
url属性の値が変われば、当然それに紐づくhash属性も変化させなければいけません。
しかしありがたいことにhash属性については指定しなくても自動でダウンロードしたファイルから算出してくれるので基本的に指定する必要はありません。
もし個別で用意してあるのであればhash属性として付け加えることができます。
指定方法や抽出方法も充実しているので、詳しくは公式Wikiをご覧ください。
実際にやってみる
url属性の書き方は既に説明したので、あとはextract_dir属性だけすが、こいつにはurl属性と同じ変数と特殊変数が使えます。
ということでVimのManifestは以下のもので完成形となります。
{"homepage":"https://github.com/koron/vim-kaoriya","description":"Vim + kaoriya build system, without gvim.","version":"8.1.0005.20180520","architecture":{"32bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v8.1.0005-20180520/vim81-kaoriya-win32-8.1.0005-20180520.zip","hash":"afacd6e27304136f5ebae3edddf6e747f410880fa6a986d80be772e03ef56d36","extract_dir":"vim81-kaoriya-win32"},"64bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v8.1.0005-20180520/vim81-kaoriya-win64-8.1.0005-20180520.zip","hash":"53e8dd08e2249ce8a54784e16469151a7bf9857ac9acf3a1b341ac4e7da26fb2","extract_dir":"vim81-kaoriya-win64"}},"bin":"vim.exe","checkver":{"url":"https://github.com/koron/vim-kaoriya/releases/latest","re":"vim(?<short>[\\d]+)-kaoriya-win32-(?<code>[\\d.]+)-(?<date>[\\d]{8}).zip","replace":"${versionCode}.${date}"},"autoupdate":{"architecture":{"32bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v$matchCode-$matchDate/vim$matchShort-kaoriya-win32-$matchCode-$matchDate.zip","extract_dir":"vim$matchShort-kaoriya-win32"},"64bit":{"url":"https://github.com/koron/vim-kaoriya/releases/download/v$matchCode-$matchDate/vim$matchShort-kaoriya-win64-$matchCode-$matchDate.zip","extract_dir":"vim$matchShort-kaoriya-win64"}}}}
バージョンの自動更新を実行しよう
さて、checver属性もautoupdate属性も付けましたが、いったいどのタイミングで更新がされるのでしょうか?
利用者のscoop update
実行時? いえいえ、これもManifest作成者がやらなくちゃいけないんです。
Windowsで自動更新する
Scoopにはもともとcheckver.ps1
というManifest自動更新用のスクリプトが用意されており、extras Bucketなどはこれを利用するための同名スクリプトが用意されています。特に理由がない限りはextras Bucketにあるcheckver.ps1
をそのまま自分のリポジトリのbinディレクトリ内に入れておきましょう。
これによって、リポジトリルートにて.\bin\checkver.ps1 MANIFEST
を叩くと公式で管理されているバージョン確認処理が、-u
オプションを付けることで自動更新の処理も併せて実行されるようになっています。
ただいちいちリポジトリに移動してコマンドを叩くのも面倒なので、いっそのこと関数にしてみましょう。どうせならscoop update
の際に一緒に実行できれば幸せですよね。
というわけでPowerShellスクリプトを作ってみました。
# globalのuser.nameとBucket所有者名が一致するものを自動更新# * リモート名は"origin"のみ対応# * sshを使うようになっていないもの(=初期状態)はスルーするので# 事前に該当リポジトリ内で"git remote set-url"を実行する必要あり# * 自動でcommitおよびpushをするので注意$my_name= git config --global user.name
$my_buckets= @()$prompt_current_dir=Get-Location$scoop_root=[environment]GetEnvironmentVariable('SCOOP', 'User')if(!$scoop_root){$scoop_root="$HOME\scoop"}Get-ChildItem$scoop_root\buckets\* | ForEach-Object {Set-Location$_$url= git remote get-url --push "origin"if($url -clike "git@*/$my_name/*"){$my_buckets +=$_}}foreach($bucketin$my_buckets){Set-Location$bucketif(Test-Path .\bin\checkver.ps1){Write-Host"Check Bucket: "$_.Name -Foreground Green
Get-ChildItem .\*.json | ForEach-Object {$json=$_.Name
.\bin\checkver.ps1 $json -u
if($(git diff$json)){Write-Host" => Update: $json" -Foreground Blue
git commit -a -m "Update: $json"}}if($(git diff)){Write-Host" => Push bucket..."
git push
}}}Set-Location$prompt_current_dir
こいつにパスを通してupdate_buckets; scoop update; scoop update *
をエイリアスにしておくことで、Scoopのアップデートと同時に独自Bucketも更新がされるようになります。
Mac/Linuxで自動更新する
もしあなたが普段Unixを使っていて、なおかつBucketのメンテナーだとしたらどうでしょう?
PowerShellもバージョン6からMacおよびLinuxでも実行できるようになったのでScoopを使って同じように……と言いたいところですが、どうも私の環境ではインストールすらできないんですよね。ここにあるCalinou氏の発言を見ると動作しているように捉えられなくもないし、Linux上でのテストコードも存在しているし、おそらく自動アップデートのスクリプトなら動くはずなんだけど。
どちらにせよ前述の通りcheckver属性とautoupdate属性に従って自身の内容を更新するだけなので、やろうと思えばPythonなどでも移植はできなくもなさそうです。
もしUnix上で自動アップデートができたら、いざWindowsを使うことになってもすぐに最新版を使えるようになりますね!!
まとめ
- checkver属性でHTMLなどからバージョンの取得方法が指定できる
- autoupdate属性で更新内容を定義できる
- url属性、extract_dir属性はバージョン情報とcheckverのre属性のマッチ結果も使える
- hash属性は基本的に指定しなくてもいい
- Scoopに用意されている
checkver.ps1
を使ってバージョン確認処理が実行可能-u
オプションをつければautoupdate属性を元に書き換えもやってくれる
あとがき
今回は自動更新にまつわる機能についての記事になりました。公式Wikiがかなり充実しているので記事にする必要もないかと思いましたが、Scoop普及のためにいろいろ頑張ってみました。
そしてこの記事を書くにあたって改めて、この自動アップデートすらも簡単に済ませられるScoopのお手軽さに感動しました。皆さんも勿論この便利さに涙を流しながら喜んでいることでしょう。私には分かってます。
あ、次回はいよいよ環境構築についての話です。ようやくです。
後述の通り、本当はビルドバージョンを入れなきゃいけない。 ↩