docker compose の dockerfile_inline の変数エスケープ

Docker Compose v2.17.3 から、 dockerfile_inline 構文compose.yaml の中に Dockerfile をインライン記述できるようになった。

そこで突然だが、 Docker クイズ!!
以下の compose.yaml をビルドしたら、 /out.txt には何が出力されているだろうか?

services:
  inline:
    build:
      context: .
      dockerfile_inline: |
        FROM alpine
        ARG arg3="dockerfile"
        ARG argDupl="dockerfile"
        RUN  export arg2=buildcontainer \
          && export argDupl=buildcontainer \
          && cat <<EOS > /out.txt
        --------
        arg2=$arg2
        arg3=$arg3
        arg2=\$arg2
        arg3=\$arg3
        EOS
        RUN cat /out.txt

docker compose --progress=plain build --no-cache オプションを付けてビルドし、 /out.txt のダンプがどうなるか見てみよう。
果たして、正解は…?

ドロドロドロドロドロドロ (ドラムロール音)

 

\デーン!!!/

#6 [inline 3/3] RUN cat /out.txt
#6 0.496 --------
#6 0.496 arg2=
#6 0.496 arg3=
#6 0.496 arg2=arg3=--------
#6 DONE 0.5s

正解できただろうか?

解説

続きを読む

Tauri v2 の VS Code デバッグを yarn 無しで実行する

Tauri v2 で開発する際、デバッグ環境を用意するのが非常に重要だ。

しかし Tauri の場合、ネイティブコードにコンパイルされる Rust 側のコアプロセスと、ブラウザ内で動く WebView プロセスが混在するため、そのデバッグ環境も複雑になる。

VS Code と yarn を組み合わせたデバッグ設定例は Tauri 公式ガイドに掲載されている。 1
しかし、この例の構成は不完全でそのまま構成しても勝手が悪い。 そもそも yarn は Tauri の開発に必須のコンポーネントではなく余計なインストールが必要になっている。

そこで、本記事では VS Code と最小のコンポーネントの組み合わせで、 Tauri v2 アプリケーションをデバッグしながら開発サイクルを回しやすくする方法を説明する。

前提条件

以下の環境が全てインストールされていることを前提とする。

  • Windows 11
  • Node.js + npm
    • v22 LTS
  • Rust (rustc)
    • toolchain は stable-msvc
  • Microsoft C++ Build Tools
    • MSVC v14* - VS 20** C++ x64/x86 ビルド ツール (最新)Windows 11 SDK をインストール
  • Visual Studio Code

Tauri v2 デバッグの特徴

続きを読む

GitHub 上のソースコードの一部を Gist のように埋め込む Cloudflare Workers

本記事は Cloudflare Advent Calendar 2024 25日目の記事だ。
空いていたので埋めちゃおう。

TL;DR

gist-it が動かなくなっちゃったので、 Cloudflare Workers で実装してみた話

ブログに GitHub 上のコードを埋め込みたい

ブログでコードの解説記事を書いていると、 GitHub 上のコードの一部を GitHub Gist のように埋め込んで表示したくなることがよくある。

以前は Gist-It というサービスを利用させていただいていたのだが、 ホストしている Google App Engine で Python 2.7 がサ終した 1 せいか、動作しなくなってしまっている。

欲しい機能は、処理内容は GitHub のソースコード取ってきて、 <pre> タグに書き込んでシンタックスハイライトを適用するような、割と単純でステートレスなもの。
このため、 Cloudflare Workers で実装してみた。

使い方

続きを読む

Power Automate で key-value Array ⇔ Object (Dictionary) を相互変換して Office Script の呼び出しを節約する

本記事は、 Microsoft Power Automate - Qiita Advent Calendar 2024 - Qiita シリーズ3 の 21日目 の記事だ。
…本当は、 シリーズ1 の 19日目 に投稿しようとしてたのだけれど、諸事情で記事更新ができず、代理投稿されてしまったので、改めて投稿し直している。

今回は、 Power Automate に於いて、連想配列の形で情報を持たせた Object と、 key-value Array の間を相互変換する方法を解説する。

Premium コネクタやループ処理などは使用せず、 O(1) オーダーのなるべく少ないステップ数で Object ⇔ Array 配列の相互変換させよう。

昨年の Power Automate Advent Calendar 2023 と同様、ステップ数を節約するテクニックの話題だ。

key-value Array ⇔ Object の変換目的

Array から Object に変換すると、 Power Automate の数式で variables('val-name')['property-name'] とアクセスできる。
このため、ループ処理で一旦統計したデータを後から参照させる場合などで都合が良い。

一方で Object から Array にしておくと、 選択アクション を使って 1ステップ で反復処理が行えるため、処理ステップ数を節約できる。

ほか活躍できる具体例として、Array にすることで Office Script との間での辞書型の情報の受け渡しが可能になることが挙げられる。

Office Script との引数・戻り値の受け渡しには key-value Array がよい

スクリプトのユーザー入力を取得する - Office Scripts#入力の制限 にあるように、 Office Script の入出力に設定する『型』は、リテラル型とそれらによる配列・オブジェクト型に限られる。
TypeScript で言う Indexシグネチャで表現できるディクショナリパターン の型を、 Office Script の main 関数のパラメータに使おうとすると、 Type literal contains invalid type 'Unrecognized' エラーになってしまうのだ。 1

function main(
  workbook: ExcelScript.Workbook,
  arg1: { [key: string]: { prop1: string, prop2: string } }
) { // <- Parameter type error for parameter 'arg1: TypeLiteral': Type literal contains invalid type 'Unrecognized'.
    const val: { [key: string]: { prop1: string, prop2: string } } = {}; // <- ok
}

幸い引数に object 型を設定することはできるが、型情報が綺麗サッパリ消えてしまうので、型アサーションに頼る必要が出てくる。
加えて、それでも返り値には object 型を設定できない。

function main(
  workbook: ExcelScript.Workbook,
  arg1: object
) {
  for (const key of Object.keys(arg1)) {
    const t = arg1[key] as { prop1: string, prop2: string };
  }
  return arg1; // <- Return type error: 'Object' is not supported. Try using an interface or type literal instead
}

つまり、 HTTP 要求トリガーbody('HTTP_要求').inputs.headers のような、任意のプロパティ名のオブジェクトで渡されるような情報を、 Office Script で処理して返しづらい。

このため代わりに、 { key: string, value: TYPE }[] な key-value 配列に変換して受け渡すことで、型情報を維持したまま Office Script との間で辞書型の情報を受け渡せるわけだ。

function main(
  workbook: ExcelScript.Workbook,
  arg1: { key: string, value: { prop1: string, prop2: string } }[]
): { key: string, value: { prop1: string, prop2: string } }[] { // <- ok
  return arg1; // <- ok
}

Power Automate からの Office Script の呼び出しには 3回/10秒 という制限があるので、 Power Automate の同一フロー中に何度も呼び出したり、ましてのフロー内のループ中に呼び出す事はできない。
このため、 key-value Array を引数に Office Script を 1回 呼び出してその中でまとめて処理をし、 Power Automate 側で key-value Array から辞書型のオブジェクトに戻すのが良いだろう。

相互変換の実装

続きを読む

Rust で Windows API のグローバルフック

本記事は、 Rust Advent Calendar 2024 シリーズ3 の 20日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 20日目 の記事としても登録させてもらっている。
遅刻です。申し訳ない。

今回は、やや実践的な例として、 Rust で Windows API の グローバル フック を使って、各ウィンドウに届くマウスやキーボード・ウィンドウメッセージをダーッとリアルタイムで表示するコードを書いてみよう。

フックDLLでメモリリークやセグメント違反を引き起こすとシステム丸ごと死にかねないし、フックした情報を表示するためにプロセス間通信やマルチスレッドの処理が必要になるなど、割と Rust 向きな例ではなかろうか。

フックとは

Win32 アプリケーションでは、各ウィンドウやコントロールがそれぞれイベントハンドラ(プロシージャ)を持ち、これが届いたメッセージを処理することで様々な機能を振る舞わせる。
「フック」とは、本来のプロシージャに届くはずの処理を先に引っ掛けて(フックして)、処理を間に挟んでから本来のプロシージャに返したり、あるいは処理を奪ってしまう機能だ。

グローバル フック は、同じ PC 内の権限的に許されるあらゆるプロセスのスレッドに対して、フックをねじ込む機能だ。
キーロガーなどのウイルスや、クリップボード監視のソフトなどでよく使われている(と思う)。

グローバルフックした場合、フック対象それぞれのプロセス毎に、フックプロシージャを定義した DLL をロードさせ、そのプロシージャを呼び出させる。
つまり、フックされたプロセス毎に DllMain が呼ばれるし、メモリ空間も独立する。
標準出力も、フックされたプロセスのものが利用されるので、例えばフックプロシージャで println! しても、フックを登録したプロセスではなくて、フックされたプロセス側の標準出力に書き込まれるわけだ。

graph LR
    subgraph caller[呼び出し元 exe]
        D0[DLL]
    end
    subgraph sub1[フック対象プログラム1]
        D1[DLL]
    end
    subgraph sub2[フック対象プログラム2]
        D2[DLL]
    end
    D0 -->|"登録"| D1
    D0 -->|"登録"| D2
    D1 -->|"println!"| cfor1@{ shape: f-circ }
    D2 -->|"println!"| cfor2@{ shape: f-circ }
    cfor1 --> sub1
    cfor2 --> sub2

このため、フックしたメッセージを登録元プロセスにて表示するためには、スレッド間参照などは使えず、プロセス間通信などを使う必要がある。
今回は、名前付きパイプで登録元プロセスに情報を渡してみる。

graph LR
    subgraph caller[呼び出し元 exe]
        D0[DLL]
    end
    subgraph sub1[フック対象プログラム1]
        D1[DLL]
    end
    subgraph sub2[フック対象プログラム2]
        D2[DLL]
    end
    D0 -->|"登録"| D1
    D0 -->|"登録"| D2
    D1 -->|"名前付きパイプ等"| caller
    D2 -->|"名前付きパイプ等"| caller

名前付きパイプによるプロセス間通信

続きを読む

AutoHotKey v2 で 令和の ThumbSense

本記事は、 Windows Advent Calendar 2024 18日目 の記事だ。
思いっきり遅刻してしまって申し訳ない。

突然だが、 ThumbSense を覚えているだろうか?
2002年に SONY が発表した、ノートPCのタッチパッドを用いて、手をホームポジションから動かさずに、マウス操作や様々なショートカットを起動するユーティリティツールだ。
(本家, 窓の杜の紹介記事)

当時はその革新的な操作体験で大いに注目されていたと記憶している 1 し、 ThumbRemap や NewtonPad などのインスパイアされたツールがいくつも登場していた。

しかし、当時のこれらの実装は Synaptic または ALPS 製のタッチパッドのドライバーをフックして実装されていた。このため、令和となった現代、 Windows 10 や Windows 11 が入っているような PC では動かない。

現在流通しているノートPCのタッチパッドは、Windows 8.1 で追加され Windows 10 で強化された、 USB 等の HID プロファイルに基づいた実装になっている。

先日の記事 の通り、 RawInput で HID の情報を拾えばかなり細かくタッチパッドの状況がとれる。
AutoHotKey 使えば、 ThumbSense のような実装もそこまで難しくないのでは…?

…と思って AutoHotKey v2 で実装してみたのが、本日の記事になる。

ThumbReSense のインストール

GitHub の advanceboy/ThumbReSense-ahk のリリースページ から、最新の exe ファイルをダウンロードして、起動するだけ。

SmartScreen の警告が出る場合は、 exe ファイルを右クリックして、セキュリティのブロック (ZoneId) を解除しよう。

また、 AutoHotKey v2 用のソースもリポジトリにあるので、こちらをダウンロードしてインストール済みの AutoHotKey v2 で起動しても OK だ。

常用するなら、 Windows のスタートアップフォルダにでも突っ込んでおけば PC 起動時に自動で起動するようになる。

AutoHotKey の制限として、通常タスクマネージャなどの管理者特権で動くソフト上では機能しないのだが、 ThumbReSense の実行ファイル (またはスクリプトを起動する AutoHotKey) 自体を管理者権限として実行すればこの制限を回避できる。
自動起動させたい場合、タスクスケジューラを使って、ログオン時に管理者権限として起動する設定にしておくと良いだろう。

残念ながら、 Windows Sandbox やリモートデスクトップでは、ホットキーを機能させる方法がなさそうだ。

使い方

続きを読む

Rust と Win32 API RawInput で HID の TouchPad を深堀り

本記事は、 Rust Advent Calendar 2024 シリーズ1 の 17日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 17日目 の記事としても登録させてもらっている。

Win32 API の RawInput を、先日紹介した Rust + windows-rs を使って呼び出し、 USB/Bluetooth HID の生入力情報を読み取っていきたい。

PC にはキーボードやマウス以外にも、スタイラスやタッチパッド等々の多くの入力デバイスが繋がるが、通常 Windows アプリにはひとつの「マウス」または「キーボード」と抽象化された状態で情報(ウィンドウメッセージ)が届く。

生入力… もとい RawInput を使うと、複数のマウス・キーボードや、任意のヒューマンインターフェイスデバイス (HID) などの、より低レベルなメッセージを受け取れるようになる。

受け取れる情報は以下の3種類。

  • マウスからの RawInput
  • キーボードからの RawInput
  • マウスやキーボード以外の、任意の HID からの RawInput

マウスやキーボードの RawInput は Windows 側で使いやすく整形された情報を取得できる。
ゲームなどでよく使われる事もあり、サンプルも数多く見つかるだろう。

本記事では、このうち最後の「任意の HID からの RawInput 情報の取得」について、高精度タッチパッドを例に簡単に説明していく。

Rust 書き始めてまだ数週間なので、あまり Rust らしい書き方になってないかもだが、その点はご容赦を。

HID プロトコルとは

続きを読む

Rust で Win32 API ことはじめ

本記事は、 Rust Advent Calendar 2024 シリーズ3 の 14日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 14日目 の記事としても登録させてもらっている。

Rust で Win32 API を叩くにあたって、最初に知っておきたい情報をまとめておく。

Win32 API を呼ぶ手段

C# の P/Invoke のように一つ一つの API をソースコード上で定義してリンクすれば、呼び出せなくはない。 1

しかしそれは流石に面倒なので、 Microsoft による windows-rs のクレートを使うのが基本となる。

windows-rs とは

windows-rs は、 Microsoft 自身が Windows API のメタデータから生成されたコードを用いて、 Rust から Windows API を呼び出しやすくするクレートを提供するプロジェクトだ。
その仕組みの通り、 Win32 API のほぼ全てに加え、 COM API や WinRT もその多くがカバーしている。

大まかな情報は、以下のページにまとまっていて基本的にはこれを読み進めればよい。

しかしそれではわざわざ記事を書く必要性が薄いので、この記事では Win32 API コードを書くにあたって、最初に知っておきたい情報をまとめておこう。

なお、後述するが windows-rs は COM や WinRT の API もカバーしており、それぞれ呼び出し方にコツがある。
すべてを解説すると分量が多いので、本記事では Win32 API の範囲に限って説明する。


ところで、↑のドキュメントのドメインである kennykerr.ca って誰のやねんって話だが、 Microsoft のエンジニア らしい。
Microsoft 公式マニュアルが個人名のドメインに置かれているってどうなのと言う気もせんでもないが、元々個人の趣味プロジェクトだったのかな…?

また、 2024年12月現在最新版が 0.58.0 と、セマンティックバージョン的にもまだ破壊的変更が入りうるものだ。
最近こそ更新は落ち着いてきているものの、以下の情報が今後変わりうることはご留意いただきたい。

windows クレート と windows-sys クレートの使い分け

続きを読む

自動で最新状態を維持! Docker Compose でコンテナのイメージを定期的に更新・再起動する方法

本記事は、 Docker/コンテナ仮想環境 Advent Calendar 2024 8日目の記事だ。

「Docker は開発向けの環境だ、運用するなら K8s などのコンテナオーケストレーションツールを使え!」…とひとは言う。
しかし、 DB やアプリ等々の複数のコンテナをひとつのマシンで動かすなら、 Docker Compose でビルドまで担わせてしまう手軽さと手っ取り早さはなかなか捨てがたい。

趣味の範囲や、チームの範囲でしか使わず、そんながっつり作り込んだシステムでも無ければ、ベースイメージが更新される度に自動的にコンテナを差し替えてしまいたくなる。
そんな状況で、実行しているイメージやビルドするベースイメージに更新があった場合のみ、自動でコンテナを Recreate して再アップさせる cron ジョブを考えてみる。

Compose で定期 pull とビルドしてイメージの更新があったら再 up する cron コマンド

cd /path/to/dirname/; { docker compose --ansi never pull --no-parallel; docker compose --ansi never --progress=plain build --pull; } 2>&1 | bash -c "tee >( logger -i -t user/docker-auto-rebuild -p user.info )" | grep -E '\s+Pull complete\s*$|^#[0-9]+\s+resolve\s+' && docker compose --ansi never up -d 2>&1 | logger -i -t user/docker-auto-recreate -p user.info

こんなコマンドを、 cron に登録してやろう。

動作確認したバージョンは、 Docker Engine v27.3.1, Docker Compose vv2.29.7 だ。

$ docker version --format "Client: {{.Client.Version}}, Server: {{.Server.Version}}"
Client: 27.3.1, Server: 27.3.1
$ docker compose version
Docker Compose version v2.29.7

実行ログは journalctl を使って以下のように実行したら見れるぞ。

$ journalctl -t user/docker-auto-rebuild -t user/docker-auto-recreate --since "1day ago"

続きを読む

プロキシ環境下の Rust の導入方法と Rust Analyzer のコード補完トラブル解決ガイド

本記事は、 Rust Advent Calendar 2024 4日目 の記事だ。
ついでに、 Windows Advent Calendar 2024 4日目 の記事としても登録させてもらっている。

どちらもまだ空きが在るので是非登録してね!

Rust Advent Calendar 2024 シリーズ 2 の 3日目 の記事は、 @yo-naka 氏の Observable Framework のデータローダーを Rust で書く方法 #ObservableFramework
データ可視化用の静的サイトジェネレーター Observable Framework のデータローダーを、省メモリで高速に処理できる Rust で書くという内容だった。


さて4日目の本記事では、プロキシ環境下にて Windows + vscode + Rust Analyzer の組み合わせで使用しようとしたところ、標準ライブラリ等のコード補完が期待通り動いてくれなかった問題の対処メモを共有したい。

ついでに、プロキシ環境下のセットアップや、 vscode でデバッグする手順も示す。

再現手順

続きを読む