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
フォルダを丸ごと置いてしまって、その同じ階層に以下のランチャスクリプトを置くことに:
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 ビルダなんだけれども、だとするならば、「大量のエラー」は実際は「少数の(種類の)エラーが大量(の場所で)」なのね。つまりはエラーの種類が何万も出てるわけじゃなく、「種類ごとに一箇所ずつ」見れればいいわけでしょ。
やりたかったのはこれだわ:
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 とかに加工すれば読みやすいのかな…。