epubcheck で locale 変更、ほか

ePUB にご用がおありでな。

idpf の EPUB Validator (beta) に頼りたかったのにまったく使えず(ERR_EMPTY_RESPONSE)。仕方なく「ハードルが高いコマンドライン」。

「ハードルが高いコマンドライン」?

違うよ。全ての CUI がハードルが高いわけじゃない。「java + Windows」という組み合わせが「最凶コンボ」なのである。Unix だから簡単になる、というものでもないけれど、「特に Windows での java がムゴい」。まぁいいか、それは。要は java で作られたものは「置き場所と起動に困る」てことです、ぶっちゃけ。

で、「先天的に java なので面倒だなぁ」なことのほかに、使ってみて二つばかり「やだなぁ」だった。

一つ目はチェック結果がなぜか標準エラーに行ってしまうこと。これもあれよ、「正しいけどさぁ」て話。つまり、全体のサマリだけが標準出力へ、詳細のチェックエラーは全部標準エラーへ、と「正しい」考えに基づいて吐き出し分けられてる。はいはい、正しいよ、正しいね。

二つ目。正直「日本語化」がいらない場合の制御の話。最初制御の仕方がわからず徘徊した。なお、「locale」はバージョン 4 以降の機能らしいので、これ以前のバージョンを使うなら、思う存分英語を堪能したまえよ。ワタシの場合は要するに「grep が面倒だから英語でいいんだってば」ってことで「あえて英語で出せや」てのが一つと、もう一つは「英語で書かなければならない文書に貼り付ける必要がある」てことね。これは -Duser.language=en で。はぁん。java やってたの、もう10年近く前になるもんなぁ、完全に失念してるわ、そういえばだいたいこんなだったな。

というわけで、「置き場所と起動で困る」は、もう仕方がないのでもともとパスが通ってる場所に epubcheck-4.0.1 フォルダを丸ごと置いてしまって、その同じ階層に以下のランチャスクリプトを置くことに:

epubcheck (MSYS bash 用である)
1 #! /bin/sh
2 export PATH=${PATH}:"/c/Program Files (x86)/Java/jre1.8.0_101/bin"
3 dn=`dirname $0`
4 
5 java -Duser.language=en -jar ${dn}/epubcheck-4.0.1/epubcheck.jar "$@" 2>&1

こういうのを自分で書く必要がある、てのが「保守問題」を引き起こしちゃうのでまさにイヤなんだけれど、背に腹は変えられぬ、つーか。まぁ仕方ないわな。






19:10追記:
ちげって、ばーか。

ついついイラついた記念で必要最小限だけやっちまったが、そもそもこんなことだけをしたかったわけではねーわ。

当たり前のことなんだけれども、「手作り手作業で ePUB を書いている」んでない限りは普通は相手にする ePUB は何某かのツールの生成物である。今のワタシの場合はこれは Sphinx の epub/epub3 ビルダなんだけれども、だとするならば、「大量のエラー」は実際は「少数の(種類の)エラーが大量(の場所で)」なのね。つまりはエラーの種類が何万も出てるわけじゃなく、「種類ごとに一箇所ずつ」見れればいいわけでしょ。

やりたかったのはこれだわ:

epubcheck.py (Python 2.7 向けに書いた(てしまった))
 1 #! /usr/bin/env python
 2 # -*- coding: utf-8 -*-
 3 import os
 4 from subprocess import Popen, PIPE
 5 import sys
 6 import re
 7 from collections import defaultdict
 8 
 9 def invoke_epubcheck():
10     env = {"PATH": "c:/Program Files (x86)/Java/jre1.8.0_101/bin"}  #
11     jar = os.path.join(
12         os.path.abspath(os.path.dirname(__file__)),
13         "epubcheck-4.0.1",  #
14         "epubcheck.jar")
15 
16     return Popen(
17         ["java", "-Duser.language=en", "-jar", jar, sys.argv[1:]],
18         bufsize=-1, stdout=PIPE, stderr=PIPE, env=env)
19 
20 
21 def get_epubcheck_result():
22     _RGX = re.compile(r"^([^:]+): (.*\(\d+,\d+\)): (.*\.)$")
23 
24     res = defaultdict(list)
25     for line in invoke_epubcheck().stderr.readlines():
26         s = line.strip()
27         m = _RGX.match(s)
28         if m:
29             res[m.group(1, 3)].append(m.group(2))
30 
31     return res
32 
33 
34 if __name__ == '__main__':
35     res = get_epubcheck_result()
36     for k in res:
37         code, mes = k
38         pos = res[k]
39         print("{}: {}: {}".format(code, mes, pos[0]))

あとはこれを html とかに加工すれば読みやすいのかな…。