はじめに
プライベートな環境で使う Wiki として PukiWiki はとても便利なのですが、できれば Markdown 記法が使える Wiki を使いたいところです。
(GitHub の Readme は Markdown 形式ですし、YouTrack, Redmine 等のタスク管理ツールも Markdown 形式をサポートし始めている)
私の社内では Markdown 形式で記述する Wiki として Growi(旧crowi-plus) を使っています。
新しく Growi にページを作成する場合はよいのですが、Pukiwiki をメインで使っていた時代に記述したページが残っています。
今回、それらを Growi へ移行する機会が出来ました。
既に こちらの記事 にある Pukiwiki 記法から Markdown 形式へ変換するワンライナーのコマンドを使えば、人手を使って移行してもそこまでの日数はかからない見込みでした。
そのため、移行スクリプトを作成するのはコストに見合わないとの考えでしたが、使う人が多ければ、コスト回収が出来るかもしれない、、、
ということで作成することにしてみました。
移行作業を一括で行うスクリプトは こちら で公開しています。
本記事内ではスクリプトの一部を引用しつつ、移行するために必要な内容を紹介します。
Pukiwiki から Growi へ移行する流れ
- Pukiwiki のページデータと添付ファイルデータを dump ディレクトリ配下にコピーする
- ディレクトリ構造は Pukiwiki のページ階層と合わせる
- ページデータは page.txt として保存 (まだ Pukiwiki 形式のまま)
- 添付ファイルは attachments 配下に保存
- Pukiwiki のデータを Markdown 形式に変換する
- Growi の API を使ってページを作成する
Pukiwiki のページデータと添付ファイルデータを dump ディレクトリ配下にコピーする
Pukiwiki のページは次の構造を持つ。
- ページデータは
${Pukiwikiインストールディレクトリ}/wiki
配下に${ページ名}.txt
として保存されている - ページデータのファイル名は、ページ名を URL エンコードした文字列から
%
を削除したものである - ページの階層構造はページ名に含まれる
/
で表される
URL エンコードされた文字列は nkf
コマンドで --url-input
オプションをつけることでデコードできる。
そこで、sed
コマンドを使って、一度ファイル名を 2 文字ずつ取り出して %
をつけて URL エンコードに変換することにする。
例えば1つのファイル ${F}
をデコードするためには次のコマンドを実行する。
echo ${F} | sed -e 's/\.txt$//' | sed -e 's/\(..\)/%\1/g' | nkf --url-input
その他、dump ディレクトリへ保存するために必要となる処理はディレクトリ作成とファイルコピーなので、適宜 mkdir
コマンド cp
コマンドを使う。
また、${Pukiwikiインストールディレクトリ}/wiki
配下にはページデータの他に Pukiwiki の設定を保存するためのファイルがあるため、コピー対象から除外しておく。(Pukiwiki の設定ファイルはファイル名が :config
で始まる)
一方で添付ファイルは次の構造を持つ。
- 添付ファイルは
${Pukiwikiインストールディレクトリ}/attach
配下に${ページ名}_${添付ファイル名}
として保存されている。 - 添付ファイルの添付ファイル名と添付先ページ名は URL エンコードした文字列から
%
を削除したものである
ページ名と添付ファイル名がアンダースコア _
でつながっているが、分けて考えればページ名を処理した時と同じ方法で処理できる。
echo ${F} | sed -e 's/^[^_]*_//g' | sed -e 's/\(..\)/%\1/g' | nkf --url-input
以上を全てのファイルに対して行い、適宜ディレクトリ作成とコピー処理を行った結果が次のスクリプトである。
#!/bin/bash -ex
# read configs
. config/env.sh
# dump pukiwiki pages
cd ${PUKIWIKI_PAGE_DIR}
for f in *.txt; do
PAGE_NAME=$(echo ${f} | sed -e 's/\.txt$//' | sed -e 's/\(..\)/%\1/g' | nkf --url-input)
# ignore settings files
if [[ "${PAGE_NAME}" =~ ^:config/ ]]; then
continue;
fi
# copy page directory
PAGE_DIR_NAME=$(echo ${PAGE_NAME} | sed -e 's#[^/]/$##g')
mkdir -p "${DUMP_DIR}/${PAGE_DIR_NAME}"
cp -ip "${PUKIWIKI_PAGE_DIR}/${f}" "${DUMP_DIR}/${PAGE_DIR_NAME}/${PAGE_FILE_NAME}"
done
# dump attachments
cd ${PUKIWIKI_ATTACHMENTS_DIR}
for f in *; do
if [[ ! "${f}" =~ ^[0-9A-F_]+$ ]]; then
continue;
fi
# copy attachments
PAGE_DIR_NAME=$(echo ${f} | sed -e 's/_.*$//' | sed -e 's/\(..\)/%\1/g' | nkf --url-input)
ATTACHMENTS_FILE_NAME=$(echo ${f} | sed -e 's/^[^_]*_//g' | sed -e 's/\(..\)/%\1/g' | nkf --url-input)
mkdir -p "${DUMP_DIR}/${PAGE_DIR_NAME}/${ATTACHMENTS_DIR_NAME}"
cp -ip "${PUKIWIKI_ATTACHMENTS_DIR}/${f}" "${DUMP_DIR}/${PAGE_DIR_NAME}/${ATTACHMENTS_DIR_NAME}/${ATTACHMENTS_FILE_NAME}"
done
#!/bin/bash -e
# User configs
## Output directory to execute script
DUMP_DIR="${PWD}/dump"
## Target directory to convert (Files are NOT overrided by script.)
PUKIWIKI_DATADIR="${PWD}/pukiwiki"
# System config
SCRIPT_PATH="${PWD}"
CMD_CREATE_CROWI_PAGE="create-crowi-page.rb"
CMD_ATTACH_FILE_TO_CROWI_PAGE="attach-files-to-crowi-page.rb"
PAGE_FILE_NAME="page.txt"
ATTACHMENTS_DIR_NAME="attachments"
## Target directory
PUKIWIKI_PAGE_DIR="${PUKIWIKI_DATADIR}/wiki"
PUKIWIKI_ATTACHMENTS_DIR="${PUKIWIKI_DATADIR}/attach"
Pukiwiki のデータを Markdown 形式に変換する
既に こちらの記事 にある Pukiwiki 記法から Markdown 形式へ変換するワンライナーのコマンドを使うことにした。
dump ディレクトリ配下に保存した全ての Pukiwiki ページデータに対して Markdown 形式への変換処理を行う。
尚、デコードされたファイルをシェルスクリプトで処理する際の注意点として、ファイル名にスペースが含まれる場合を考慮しないといけない。
cp
, mkdir
コマンドでスペースが含まれるファイルを扱うにはダブルクオート "
で括ればよい。
for
でループする際は区切り文字列 $IFS
を変更する。
#!/bin/bash -ex
# read variables
. config/env.sh
# see. https://ja.stackoverflow.com/questions/39713/%E4%BB%BB%E6%84%8F%E3%81%AE%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AE%E4%B8%AD%E3%82%92%E6%A4%9C%E7%B4%A2%E3%81%97-%E6%9D%A1%E4%BB%B6%E3%81%AB%E4%B8%80%E8%87%B4%E3%81%97%E3%81%9F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8C%E3%81%82%E3%82%8C%E3%81%B0%E5%87%A6%E7%90%86%E3%82%92%E3%81%99%E3%82%8B%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E6%9B%B8%E3%81%8D%E3%81%9F%E3%81%84
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
# convert pukiwiki pages to markdown
cd ${DUMP_DIR}
for f in `find . -name ${PAGE_FILE_NAME}`; do
# convert content from pukiwiki to markdown
TEMPFILE=$(mktemp -t conv-pkwk2growi.XXXXX) || exit 1
# see. https://qiita.com/yuki-takei/items/152e20f4421333ae8fd9
cat "${f}" | sed -e 's/ \[#[0-9a-z]\+\]$//g' \
-e 's/^\*\*\*/###/g' -e 's/^\*\*/##/g' -e 's/^\*/#/g' \
-e 's/^---/ -/g' -e 's/^--/ -/g' -e 's/^\(\s*\)-\([^ ]\)/\1- \2/g' \
-e 's/^[\+][\+][\+]/ 1./g' -e 's/^[\+][\+]/ 1./g' -e 's/^[\+]/1./g' -e 's/^\(\s*\)1\.\([^ ]\)/\11. \2/g' \
-e 's/&br;/<br>/g' \
-e 's/^#pre{*/```/g' -e 's/^}}*/```/g' \
-e 's/%%/~~/g' \
-e "s/^\#lsx/`echo -ne '\u0024'`lsx()/g" -e 's/^\(#\+\)\([^ #]\)/\1 \2/g' \
> "${TEMPFILE}"
mv "$TEMPFILE" "${f}"
done
Growi の API を使ってページを作成する
dump に保存した Markdown 形式のファイルを Growi のページとして保存する。
Growi は Crowi 互換の API があるため、これを使う。
今回は API を使ってページを作成するための Ruby 用 gem の crowi-client があるのでそれを使うことにした。
2021/05/30追記:本記事執筆後、GROWI の API のみに対応するクライアントを作る目的で growi-client を作りました。crowi-client より多少新しいです。
crowi-client の使い方は次のとおり。
- gem パッケージをインストールする (※今回は bundle install する前提)
-
config/settings.yml
に API token と Growi の URL を記述する - Ruby ファイルを用意して
require 'crowi-client'
で呼び出す - 各種操作用リクエスト
CPApiRequestPagesCreate
等のインスタンスを作成する - crowi-client の
request
メソッドを使ってリクエストを Growi へ送信する
ページを新規作成するためには CPApiRequestPagesCreate
インスタンスを使えばよい。
既存ページが Growi にあればページ作成はせず、存在しなかった場合のみ Pukiwiki から移行したページを作成することとして、次の Ruby スクリプトを作成した。
require 'bundler'
Bundler.require
require 'crowi-client'
if ARGV.length < 1
puts "$0 CROWI_PAGE_NAME"
exit 1
end
page_name = ARGV[0]
if CrowiClient.instance.page_exist?(path_exp: page_name)
puts "Cannot create page. Because page '#{page_name}' is already exists. Ignore this page."
exit 0
end
# Create page files
body = STDIN.read
req = CPApiRequestPagesCreate.new path: page_name, body: body
puts CrowiClient.instance.request(req)
また、全てのファイルに対して上記 Ruby スクリプトを実行するよう、次のシェルスクリプトを作成した。
#!/bin/bash -ex
# read variables
. config/env.sh
# see. https://ja.stackoverflow.com/questions/39713/%E4%BB%BB%E6%84%8F%E3%81%AE%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AE%E4%B8%AD%E3%82%92%E6%A4%9C%E7%B4%A2%E3%81%97-%E6%9D%A1%
E4%BB%B6%E3%81%AB%E4%B8%80%E8%87%B4%E3%81%97%E3%81%9F%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%8C%E3%81%82%E3%82%8C%E3%81%B0%E5%87%A6%E7%90%86%E3%82%92%E3%81%99%E3%82%8B%E3%82%B7%
E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%82%92%E6%9B%B8%E3%81%8D%E3%81%9F%E3%81%84
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
# register markdown data to Growi
cd ${DUMP_DIR}
for f in `find . -name ${PAGE_FILE_NAME}`; do
RELATIVE_FILE_PATH=$(realpath --relative-to="${SCRIPT_PATH}" "${f}")
PAGE_NAME=$(echo ${f} | sed -e 's#/page.txt##' | sed -e 's#^\./##')
cd "${SCRIPT_PATH}"
cat "${RELATIVE_FILE_PATH}" | ruby "${CMD_CREATE_CROWI_PAGE}" "/${PAGE_NAME}"
cd "${DUMP_DIR}"
done
スクリプトを実行する
以上、全ての流れを行えば Pukiwiki のページを Growi へ移行できます。
スクリプトを使って移行する場合は次の操作を行います。(詳細はREADMEを参照して下さい)
実行環境準備
- リポジトリをクローンする
git clone https://github.com/ryu-sato/conv-pkwk2growi.git
-
config/env.sh
の User Config 箇所を適宜設定する -
config/settings.yml
を作成して Growi の API_TOKEN と URL を設定する - Gem ファイルをインストールする
bundle install
コンバート方法
- Pukiwiki データをディレクトリへ dump する (
dump-pkwk.sh
) - dump したファイルを Markdown 形式へ変更(
conv-pkwk2md.sh
) - Growi へ dump したファイルをアップロードする(
create-crowi-page.sh
)
bash dump-pkwk.sh
bash conv-pkwk2md.sh
bash create-crowi-page.sh
最後に
実際にスクリプトを使って移行はできたものの困った点が2つあったため共有します。
- crowi-client を使って添付ファイルを Growi のページに添付できなかった
- 添付ファイルは手動で移行する必要があります
- crowi-client が Basic 認証に対応していないため Growi のページに Basic 認証を設けている場合は Authentication Error となる
- 移行時に一時的に Basic 認証を解除する等の対応をする必要があります
多くの人にスクリプトを使って楽に Growi へ移行してもらえれば幸いです。