tech.guitarrapc.cóm

Technical updates

scoop の bucket を自動更新する

Scoop Bucket を作るのは避けたいものです。 しかし、Main や Extras に追加するのもアレだし、既存のパッケージ更新はメンテされてないし、など様々な理由で自分のバケットを作ることはあるでしょう。

自分のバケットを持った時に面倒なのが、バケットの更新追従です。 幸いにも Scoop には Excavate という自動更新する仕組みがあります。今回はこれを仕込んでみましょう。

目次

TL;DR

  • Bucket の manifest を記述した json に checkverautoupdate セクションを設定する
  • Excavate と更新スクリプトをバケットに配置する。
    • バケットフォルダで、bukcet/ などフォルダを掘っている場合はスクリプトで対応が必要
  • Excavate は docker-compose で動くので、動かしっぱなしにするか適当などこかで定期実行

実際に使用しているリポジトリ

この記事で使っている自動更新のためのスクリプトや仕組みは .github フォルダに一式が入っています。

github.com

動作環境

バケットの自動更新は以下の環境で動作します。

  • Linux コンテナ
  • PowerShell 7
  • 定期実行環境 (ローカルマシン、GitHub Actions、Kubernetes など)

Linux コンテナで動作するので、事実上実行環境に困らないでしょう。Windows でも実行できますが、私はLinuxのみで行っています。

Scoop App Manifest 自動更新の仕組み

3つやることがあります。

  1. 自動更新するバケットjsonを自動更新に対応させる
  2. 自動更新スクリプトをバケットのリポジトリにおく
  3. 自動更新を定期実行する

順番に見ていきましょう。

1. 自動更新するバケットjsonを自動更新に対応させる

Scoop App Manifest は、checkverautoupdate に適切な内容を記述することで自動更新対象のマニフェストとして認識されます。この辺りは公式の Wiki に書いてあります。

App Manifest Autoupdate · lukesampson/scoop Wiki · GitHub

といってもWikiの内容は複雑でよくわからん.... ということで実際に使っているシンプルなパターンで説明します。

GitHub のリリースページを見る

今回のパターンは GitHub Releases のパッケージ更新を見てバケットを構成している場合に利用できます。ただし、プレリリースではない && バージョン1.0.0 や v1.0.0 といったパターンでタグ公開されているの2点が前提です。

実際に利用しているctop を定義したマニフェストを用意しました。

{
    "description": "Top-like interface for container metrics",
    "homepage": "https://github.com/bcicen/ctop",
    "version": "0.7.5",
    "license": "MIT",
    "url": "https://github.com/bcicen/ctop/releases/download/v0.7.5/ctop-0.7.5-windows-amd64#/ctop.exe",
    "hash": "sha256:bffb1499d62c46b70dd25d557b653f812ccdc8b4bfb08473c063a6265faf78b3",
    "bin": "ctop.exe",
    "checkver": "github",
    "autoupdate": {
        "url": "https://github.com/bcicen/ctop/releases/download/v$version/ctop-$version-windows-amd64#/ctop.exe"
    }
}

自動バージョン更新に必要なのは、checkver と autoupdate のセクションです。

  • checkver"github" で問題ありません。これでリリースぺージのTagが \/releases\/tag\/(?:v|V)?([\d.]+) パターンで公開されていれば抽出されます。
  • autoupdate のセクションは、$version を使って実際のリリースページのダウンロードurl を表現します。url が https://github.com/bcicen/ctop/releases/download/v0.7.5/ctop-0.7.5-windows-amd64 なので、0.7.5 というバージョンが $version に置き換えられていることがわかります。

これでバケットのjsonは準備が整いました。

2. 自動更新スクリプトをバケットのリポジトリにおく

リポジトリ直下にバケットのjsonを配置しているか、bucketフォルダを掘ってそこにまとめているかで微妙に異なります。

bucket フォルダを掘っている場合は、lukesampson/scoop-extras の bin フォルダの中身を、そのまま自分のリポジトリの/binに持ってくるといいでしょう。

f:id:guitarrapc_tech:20201123222946p:plain
lukesampson/scoop-extras の bin フォルダの中身

もしもリポジトリ直下にバケットjson を置いている場合は、以下のように $dir = "$psscriptroot/.." とします。各スクリプトにこの変更がいるので面倒です。

# auto-pr.ps1
param(
    # overwrite upstream param
    [String]$upstream = "<user>/<repo>:master"
)
if(!$env:SCOOP_HOME) { $env:SCOOP_HOME = resolve-path (split-path (split-path (scoop which scoop))) }
$autopr = "$env:SCOOP_HOME/bin/auto-pr.ps1"
# $dir = "$psscriptroot/../bucket" # checks the parent dir
$dir = "$psscriptroot/.." # checks the parent dir
iex -command "$autopr -dir $dir -upstream $upstream $($args |% { "$_ " })"

これでバケットのスクリプト配置も完了です。

NOTE: 調べるとこのスクリプト名がbucket-updater.ps1 だったり auto-pr.ps1 だったりしますが、後述のExcavatorを使う場合どちらでも対応されているので大丈夫です。auto-pr.ps1 が公式でも使ってて新しいかな?

3. 自動更新を定期実行する

自動更新方法はWikiにもいくつかのっています。

App Manifest Autoupdate · lukesampson/scoop Wiki · GitHub

個人的には、ScoopInstaller/Excavatorを用いて docker-compose で実行するのがおすすめです。Linux で実行できるのと、docker-compose が利用できるので実行環境を選びません。あとこの方法なら Kubernetes で実行も簡単です。

github.com

docker-compose を実行すると ssh キーが生成されるので、公開鍵 id_rsa.pub をGitHub に登録して push できるようにしましょう。sshキーを再利用する場合は、id_rsa も取得しておいて、docker-compose 実行時にマウントさせればok です。

$ docker-compose up --build
$ docker-compose exec bucket cat /root/.ssh/id_rsa.pub
$ docker-compose exec bucket cat /root/.ssh/id_rsa

このコンテナイメージは定期的に呼び出して実行するには注意があります。/sbin/my_init を実行した上でないと scoop コマンドがコンテナ内部で見つからずエラーが出ます。

走らせっぱなしで定期実行する前提なイメージになっているので、自分のように定期的に呼び出し実行する場合は docker-compose で次のようなラッパーコマンドを用意して呼び出すといいでしょう。

#!/bin/bash
/sbin/my_init &
chmod 600 /root/.ssh/id_rsa
pwsh ./root/scoop/lib/install.ps1
bash -x /root/excavate.sh

これで コンテナを使っていい感じに更新されるようになります。

実行環境について

このような定期実行環境は、Kubernetes の cron job、後今日使えるようになった Amazon ECS のdocker-compose対応などが楽でしょう。

www.docker.com

GitHub Actions での使用は、使用条件のここに該当するかによりそうです。

any other activity unrelated to the production, testing, deployment, or publication of the software project associated with the repository where GitHub Actions are used.

バケットのデプロイ作業なので実行は許されそうですが、自前のクラスタで実行で行えるならそれがいいでしょう。 仮にリポジトリで実行していますが、自前Kubernetes クラスタでの実行に変更を予定しています。

以下に GitHub Actions で実行する場合の Workflow を示します。

name: auto update bucket

on:
  schedule:
    - cron: "0 * * * *"
  workflow_dispatch:

jobs:
  update:
    timeout-minutes: 10
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - run: openssl aes-256-cbc --pbkdf2 -d -in .github/.ssh/id_rsa.cipher -k ${{ secrets.CIPHER_KEY }} >> .github/.ssh/id_rsa
      - run: docker-compose up
        working-directory: .github

パッケージの更新ログの例です。

main_1  | 
main_1  | ScriptBlock ID: f43b73d1-2181-437c-9d72-8b0797e62035
main_1  | Path: /root/scoop/lib/install.ps1
main_1  | py: 1.0.1.6
main_1  | DejaVuSansMono-Bront: couldn't match '\/releases\/tag\/(?:v|V)?([\d.]+)' in https://github.com/chrismwendt/bront/releases/latest
main_1  | bombardier: 1.2.5 (scoop version is 1.2.4) autoupdate available
main_1  | Autoupdating bombardier
main_1  | Downloading bombardier-windows-386.exe to compute hashes!
main_1  | Downloading https://github.com/codesenberg/bombardier/releases/download/v1.2.5/bombardier-windows-386.exe#/bombardier.exe (9.7 MB)...
main_1  | Computed hash: d2bfd99019ca590610c89ccf829bf4c84ed6652821fe55e7f9bcf342106fe496
main_1  | Downloading bombardier-windows-amd64.exe to compute hashes!
main_1  | Downloading https://github.com/codesenberg/bombardier/releases/download/v1.2.5/bombardier-windows-amd64.exe#/bombardier.exe (10.9 MB)...
main_1  | Computed hash: 52e0c22e3a10c06f7013bbb09d713ab52fae6fba5a86a5ffcfdd6546ed86b7cf
main_1  | Nov 22 12:17:39 3e2cb27a65fb powershell[86]: (7.0.2:9:80) [ScriptBlock_Compile_Detail:ExecuteCommand.Create.Warning] Creating Scriptblock text (1 of 1):
main_1  | {⏎⏎            $architecture = $_.Name⏎⏎            if ($json.architecture.$architecture.$prop -and $json.autoupdate.architecture.$architecture.$prop) {⏎⏎                $json.architecture.$architecture.$prop = substitute (arch_specific $prop $json.autoupdate $architecture) $substitutions⏎⏎            }⏎⏎        }
main_1  | 
main_1  | ScriptBlock ID: a1ca077d-4175-458e-9ad3-e0f9e4c68c86
main_1  | Path: /root/scoop/lib/autoupdate.ps1
main_1  | Writing updated bombardier manifest
main_1  | ctop: 0.7.5
main_1  | warning: LF will be replaced by CRLF in bucket/bombardier.json.
main_1  | The file will have its original line endings in your working directory.
main_1  | Creating update bombardier (1.2.5) ...
main_1  | hub add bucket/bombardier.json
main_1  | warning: LF will be replaced by CRLF in bucket/bombardier.json.
main_1  | The file will have its original line endings in your working directory.
main_1  | hub status --porcelain -uno
main_1  | hub commit -m 'bombardier: Update to version 1.2.5'
main_1  | [master 603a742] bombardier: Update to version 1.2.5
main_1  |  1 file changed, 5 insertions(+), 5 deletions(-)
main_1  | Pushing updates ...
main_1  | hub push origin master
main_1  | Warning: Permanently added the RSA host key for IP address '140.82.112.4' to the list of known hosts.
main_1  | To github.com:guitarrapc/scoop-bucket.git
main_1  |    c5e2c3f..603a742  master -> master
main_1  | hub reset --hard
main_1  | HEAD is now at 603a742 bombardier: Update to version 1.2.5
main_1  | + '[' -f /root/bucket/bin/bucket-updater.ps1 ']'
github_main_1 exited with code 0

まとめ

難しい記述をしなくても自動更新できるのはいいことです。 実行環境だけ面倒ですね。

参考

手の入れ方が好みじゃないので参考程度にしています。 こういう公式のやり方に乗っかる場合は、コンテナに手を入れないのがおすすめです。メンテしきれなくなるので。

Scoopを使ったWindows環境構築のススメ - Hyper!!! - Qiita