TeXLive on FreeBSD(ファイル名と格闘編)

portshakerで得られるtexliveのports collectionにprint/texlive-japanese-otf-uptexというものが出てきましたが、ファイル名に()と空白を含んでおり、print/texlive-core/bsd.texlive.mkではうまく処理できていません。また、pkg-plistも不完全な状態です。

今回はこれを解決してみよう、という話です。

FreeBSDのtexlive portsは、texlive の tlpobj を公式のperl scriptではなくて自前の print/texlive-core/bsd.texlive.mk で取り扱うようにできているようです。そして、そこではawkスクリプトが用いられています。ファイル名に空白を含んでいることは想定外のようですので、そこから直します。tlpobjのフォーマットはよくわかりませんが、公式のperl module(例えば、http://distrib-coffee.ipsl.jussieu.fr/pub/mirrors/ctan/systems/texlive/tlnet/tlpkg/TeXLive/ の TLPOBJ.pm, TLConfig.pmあたり)を参考にすると、デフォルト設定では、" ほげほげ"という行があったら(先頭空白に注意)、"$prefix/ほげほげ"、というパスを表す、さらに、もし" RELOC/ほげほげ"という文字列の場合は、設定ファイル(これはどこにあるのか…)で指定された文字列に置換してから"$prefix/"を先頭に付加する、というシンプルな仕組みのようです。一方で、bsd.texlive.mkの方では、空白入りファイル名は想定せずに、インストールするファイルのsrcとdstとオプション(pkg-plistに出てくる、%%NOPORTDOCS%%など)を空白区切りファイルに一旦格納します。ここが問題なので、とりあえず、ファイル名やパス名にコンマは出てこないだろう、と仮定し(この仮定はまずいかも知れないが、他の文字でもいい。何なら良いだろうか?)、コンマ区切りファイル(CSV)にいったん格納するように変更します。

--- portshaker/freebsd_texlive/print/texlive-core/bsd.texlive.mk	2012-01-20 00:31:50.290495850 +0900
+++ bsd.texlive.mk	2012-02-06 00:42:08.985429696 +0900
@@ -24,81 +24,82 @@
 FETCH_ARGS=	-ApR	# Do NOT restart a previously interrupted transfer
 USE_XZ=		yes
 NO_BUILD=	yes
+NO_WRKSUBDIR=	yes
 
 MKTEXLSR=	${PREFIX}/bin/mktexlsr
 
 ${WRKDIR}/.install_files: build
-	@(  cd ${WRKDIR} && cat tlpkg/tlpobj/${PORTNAME}.tlpobj | awk '\
-		$$0 ~ /^ / { \
-		    source=$$1; \
-		    target="share/" $$1; \
-		    if (index($$1, "RELOC/")) { \
-			sub("RELOC/", "", source); \
-			sub("RELOC/", "texmf-dist/", target); \
+	@(  cd ${WRKDIR} && ${CAT} tlpkg/tlpobj/${PORTNAME}.tlpobj | ${GREP} ^\  | ${AWK} '\
+		{ \
+		    source=substr($$0, 2, length($$0)); \
+		    target="share/" source; \
+		    if (index(source, "RELOC/")) { \
+			sub("RELOC/","",source); \
+			sub("RELOC/", "texmf-dist/",target); \
 		    } \
-		    if (system("[ -e ${PREFIX}/" target " ]") != 0) { \
-			print source "	" target; \
+		    if (system("[ -e \"${PREFIX}/" target "\" ]") != 0) { \
+			print source "," target ","; \
 		    } \
 		}' > ${WRKDIR}/.install_files; \
 	)
 .if !defined(NOPORTDOCS)
-	@(  cd ${WRKDIR} && cat tlpkg/tlpobj/${PORTNAME}.doc.tlpobj | awk '\
-		$$0 ~ /^ / { \
-		    source=$$1; \
-		    target="share/" $$1; \
-		    if (index($$1, "RELOC/")) { \
-			sub("RELOC/", "", source); \
-			sub("RELOC/", "texmf-dist/", target); \
+	@(  cd ${WRKDIR} && ${CAT} tlpkg/tlpobj/${PORTNAME}.doc.tlpobj | ${GREP} ^\  | ${AWK} '\
+		{ \
+		    source=substr($$0, 2, length($$0)); \
+		    target="share/" source; \
+		    if (index(source, "RELOC/")) { \
+			sub("RELOC/","",source); \
+			sub("RELOC/", "texmf-dist/",target); \
 		    } \
-		    if (system("[ -e ${PREFIX}/" target " ]") != 0) { \
-			print source "	" target "	%%PORTDOCS%%"; \
+		    if (system("[ -e \"${PREFIX}/" target "\" ]") != 0) { \
+			print source "," target ",%%PORTDOCS%%"; \
 		    } \
 		}' >> ${WRKDIR}/.install_files; \
 	)
 .endif
 .if !defined(NOPORTSRC)
-	@(  cd ${WRKDIR} && cat tlpkg/tlpobj/${PORTNAME}.source.tlpobj | awk '\
-		$$0 ~ /^ / { \
-		    source=$$1; \
-		    target="share/" $$1; \
-		    if (index($$1, "RELOC/")) { \
-			sub("RELOC/", "", source); \
-			sub("RELOC/", "texmf-dist/", target); \
+	@(  cd ${WRKDIR} && ${CAT} tlpkg/tlpobj/${PORTNAME}.source.tlpobj | ${GREP} ^\  | ${AWK} '\
+		{ \
+		    source=substr($$0, 2, length($$0)); \
+		    target="share/" source; \
+		    if (index(source, "RELOC/")) { \
+			sub("RELOC/", "",source); \
+			sub("RELOC/", "texmf-dist/",target); \
 		    } \
-		    if (system("[ -e ${PREFIX}/" target " ]") != 0) { \
-			print source "	" target "	%%PORTSRC%%"; \
+		    if (system("[ -e \"${PREFIX}/" target "\" ]") != 0) { \
+			print source "," target ",%%PORTSRC%%"; \
 		    } \
 		}' >> ${WRKDIR}/.install_files; \
 	)
 .endif
 
 pkg-plist: ${WRKDIR}/.install_files
-	@sort -k 2 < ${WRKDIR}/.install_files | awk ' { print $$3 $$2 } ' > ${PLIST}
-	@for dir in `cut -f 2 < ${WRKDIR}/.install_files | xargs dirname | sort -r | uniq`; do \
+	@${SORT} -t',' -k 2 < ${WRKDIR}/.install_files | ${AWK} -F',' ' { print $$3 $$2 } ' > ${PLIST}
+	@for dir in `${CUT} -d',' -f 2 < ${WRKDIR}/.install_files | ${XARGS} dirname | ${SORT} -r | uniq`; do \
 	    if [ ! -d "${PREFIX}/$$dir" ]; then \
-		echo @dirrmtry $$dir >> ${PLIST} ;\
+		${ECHO} @dirrmtry $$dir >> ${PLIST} ;\
 	    fi; \
 	done
-	@echo "@exec %D/bin/mktexlsr" >> ${PLIST}
-	@echo "@unexec %D/bin/mktexlsr" >> ${PLIST}
+	@${ECHO} "@exec %D/bin/mktexlsr" >> ${PLIST}
+	@${ECHO} "@unexec %D/bin/mktexlsr" >> ${PLIST}
 
 do-install: ${WRKDIR}/.install_files
-	@for dir in `cut -f 2 < ${WRKDIR}/.install_files | xargs dirname | sort -r | uniq`; do \
+	@for dir in `${CUT} -d',' -f 2 < ${WRKDIR}/.install_files | ${XARGS} dirname | ${SORT} -r | uniq`; do \
 	    if [ ! -d "${PREFIX}/$$dir" ]; then \
 		${MKDIR} "${PREFIX}/$$dir" ;\
 	    fi; \
 	done
-	@(  cd ${WRKDIR} && while read source target junk; do \
+	@( cd ${WRKDIR} && IFS="," && while read source target junk; do \
 		${INSTALL_DATA} $$source ${PREFIX}/$$target; \
 	    done < ${WRKDIR}/.install_files \
 	)
 
 post-install:
 .if defined(WITHOUT_TEXLIVE_MKTEXLSR)
-	@echo "WITHOUT_TEXLIVE_MKTEXLSR is set.  Not running ${MKTEXLSR}."
-	@echo "You MUST run 'mktexlsr' to update TeXLive installed files database."
+	@${ECHO} "WITHOUT_TEXLIVE_MKTEXLSR is set.  Not running ${MKTEXLSR}."
+	@${ECHO} "You MUST run 'mktexlsr' to update TeXLive installed files database."
 .else
-	@echo "Updating ls-R databases..."
+	@${ECHO} "Updating ls-R databases..."
 	@${MKTEXLSR}
 .endif
 

awkで先頭一文字だけ除く美しい方法がよくわからないので結局、substrしました。初めてIFS使った。ついでに、echoを${ECHO}にするとか、コマンドの変数化もやりました(uniqだけ/usr/ports/Mk/bsd.commands.mkに見付からなかったので、置き換えてません。ないのか…)。さらについでに、以前も指摘したエラーメッセージの抑制のパッチも入っています。このパッチは、 http://www.gfd-dennou.org/member/murashin/distfiles/patches/bsd.texlive.mk.patch に、ファイルそのものは http://www.gfd-dennou.org/member/murashin/distfiles/patches/bsd.texlive.mk.escaped-shell-chars に置いてあります。

パッチは ~/bsd.texlive.mk.patch にあるとして、 パッチを print/texlive-core/bsd.texlive.mkに当てて、pkg-plistを作りなおして、make install します。

# cd /usr/ports/print/texlive-core/
# patch < ~/bsd.texlive.mk.patch
# cd ../texlive-japanese-otf-uptex/
# make pkg-plist
# make install

これは、print/texlive-japanese-otf-uptex, あるいはパッケージ名としては texlive-japanese-otf-uptex-20120203 をインストールした状態、もっと正確に言えば、texlive-japanese-otf-uptex-20120203 の内容物をインストールした状態で行ってはいけません。その場合、正常なpkg-plistが生成されません。これは、pkg-plist生成時およびインストール時に、存在しないファイルだけをインストールするようになっているからです。

というわけで、print/japanese-otf-uptexを正常にインストールできるようになりました。なお、上記のパッチはfreebsd-texliveの開発・メンテナのromainさんに送りました。下手な英語で通じるのかどうか不安ですが、とりあえず待ちです。

(2012/2/6 0:55ごろ訂正) tlpobjに" RELOC"がない場合、エンバグしてしまっていたので、直しました。汚いですが。それに伴って上記のdiffも入れ換えてあります。前後の文面も多少変えました。それ以前のものを持っていってしまった方はご注意下さい。

(2012/2/6 5:50ごろ訂正) PORTDOCSについてインストールされない不具合が混入していたので直しました。ご注意下さい。また、生成されるpkg-plistは、このパッチを適用するかしないかにかかわらず、不完全である疑いがあります。特に@dirrmtry回りが怪しいです。こちらもご注意を。

(2012/2/7 3:30ごろ訂正) RELOC を置換するあたりの文を、正しくしました。