これは LibreOffice Advent Calendar 2020 の25日目の記事です。
(追記 2022-12-11)
アップデート版を書きました。動かない場合はこちらも参照してください。
そもそもは「LibreOffice BasicでLispインタプリタ(mal)を書いた」を書いたときに「Docker を使って REPL を試せますよ」というところまで用意したかったんですよね。ところがちょっと試して間に合わなそうだったのでいったん後回しにしていたのでした。
その後あらためて調べて、怪しいところがありつつもなんとか REPL が動かせるようになりました(記事の方にも追記しました)。
で、 Docker で Basic マクロを実行する部分だけ切り出して書いておくと誰かの役に立つかもということでこれを書いています。パッと思いつくところではテストの自動化なんかに使えそう。
最低限のサンプル
Standard
ライブラリ + Module1
モジュールだけを使った最低限の例です。
用意するファイル
Dockerfile
FROM ubuntu:18.04
RUN apt-get update \
&& apt-get -y install --no-install-recommends \
libreoffice-calc \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# ~/.config/libreoffice 以下を生成
RUN libreoffice --headless --terminate_after_init
WORKDIR /root/work
sample.sh(コンテナ内で実行するスクリプト)
escape_xml() {
cat \
| sed -e 's/&/\&/g' \
| sed -e 's/"/\"/g' \
| sed -e "s/'/\'/g" \
| sed -e 's/</\</g' \
| sed -e 's/>/\>/g'
}
print_basic_src() {
cat << BAS
Sub Main
Dim fid As Integer
fid = Freefile
Open "/tmp/output" For Binary Access Write As fid
Put(fid, 1, CStr(Time()) & Chr(10))
Close fid
End Sub
BAS
}
user_bas_dir="${HOME}/.config/libreoffice/4/user/basic"
mod_name=Module1
mod_file="${user_bas_dir}/Standard/${mod_name}.xba"
cat << XML > ${mod_file}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module
xmlns:script="http://openoffice.org/2000/script"
script:name="${mod_name}"
script:language="StarBasic"
>
$(print_basic_src | escape_xml)
</script:module>
XML
libreoffice \
--headless --norestore --nologo --nofirststartwizard --nolockcheck \
"vnd.sun.star.script:Standard.${mod_name}.Main?language=Basic&location=application"
cat /tmp/output
短いので説明するまでもないかもしれませんが、次のような処理内容です。
-
~/.config/libreoffice/4/user/basic/Standard/Module1.xba
に Basic のコードを格納- できればちゃんと XML を読み書きした方がよいと思いますが、最低限のサンプルということで
Module1.xba
をまるごと上書き
- できればちゃんと XML を読み書きした方がよいと思いますが、最低限のサンプルということで
-
libreoffice
コマンドでマクロを実行- 現在の時刻が一時ファイルに書き込まれる
- 一時ファイルに出力された内容を表示
実行
# イメージをビルド
docker build -t libreoffice-basic:trial .
# 実行
docker run --rm -v "$(pwd):/root/work" libreoffice-basic:trial bash sample.sh
うまく動いていれば docker run 〜
を実行するたびに現在時刻がプリントされます(タイムゾーン設定をしていないので日本の時刻とはずれます)。
メモ
マクロのセキュリティレベルと CUI での実行
最初は Basic のコードをファイルに入れて実行する方法を試していたのですが、この場合セキュリティレベルを「低」にしないと GUI なしでは実行できません。設定ファイルをごにょごにょすればセキュリティレベルの変更も GUI なしでできそう……と思いついて試してはみたものの、そういうのあんまりやりたくないですよね……。
というわけで、ファイルではなくユーザ管理のマクロ(マクロの管理ダイアログで「マイマクロ」と表示されるもの)として登録して実行する方法に落ち着きました。Docker を使うと既存の環境を汚さないかとか気にせず大胆にやれてよいですね。
設定の初期化
ユーザ管理のマクロの置き場所は ~/.config/libreoffice/4/user/basic
以下なのですが、apt で libreoffice をインストールしただけだとこのディレクトリや他の設定ファイルなどは生成されません。一度 LibreOffice を起動すると生成されるんですけど、普通に起動すると起動したままなので別途 kill したりしないといけない……。
どうしようかなと思ってコマンドラインオプション一覧を眺めていたら --terminate_after_init
という、名前から察するにこういう用途のために用意されていると思しきオプションを見つけました。
Developer arguments:
--terminate_after_init
Exit after initialization complete (no documents loaded).
Dockerfile 内で使っているのがこれです。ドキュメントで確認した訳ではないのでひょっとして目的外使用だったらごめんなさい。
ライブラリを追加する場合
上の例ではすでに存在している Standard
ライブラリを利用しているため不要ですが、別のライブラリを追加する場合は ~/.config/libreoffice/4/user/basic/script.xlc
に追記する必要があります。
下記は Mylib
というライブラリを追加する例。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library:libraries PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "libraries.dtd">
<library:libraries xmlns:library="http://openoffice.org/2000/library" xmlns:xlink="http://www.w3.org/1999/xlink">
<library:library library:name="Standard" xlink:href="$(USER)/basic/Standard/script.xlb/" xlink:type="simple" library:link="false"/>
+ <library:library library:name="Mylib" xlink:href="$(USER)/basic/Mylib/script.xlb/" xlink:type="simple" library:link="false"/>
</library:libraries>
環境
- Ubuntu Linux 18.04
- LibreOffice 6.0.7.3
※ コンテナの中も外も同じ
関連
他に LibreOffice 関連で書いたもの