LoginSignup
5

DockerでLibreOffice Basicマクロを実行する

Last updated at Posted at 2020-12-25

これは 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/</\&lt;/g' \
    | sed -e 's/>/\&gt;/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 をまるごと上書き
  • 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 を使うと既存の環境を汚さないかとか気にせず大胆にやれてよいですね。

image.png

設定の初期化

ユーザ管理のマクロの置き場所は ~/.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 関連で書いたもの

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5