From 7f254fa6744d8cc8f8760d34dcd4cd38ee17179c Mon Sep 17 00:00:00 2001 From: Ruk Doe Date: Sat, 3 Oct 2026 21:20:40 +0900 Subject: [PATCH 1/3] =?UTF-8?q?v2:=20PDF=20=E3=81=AF=E5=90=8C=E3=81=98?= =?UTF-8?q?=E3=83=96=E3=83=A9=E3=83=B3=E3=83=81=E3=81=AE=20pdf/=20?= =?UTF-8?q?=E3=81=AB=E7=BD=AE=E3=81=8D=E3=80=81rclone=20=E3=81=A7=20OneDri?= =?UTF-8?q?ve=20=E3=81=AA=E3=81=A9=E3=81=AB=E3=82=82=E9=80=81=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pdf ブランチをやめ、.qd と同じフォルダ構造で output-dir (既定 pdf) に置いて コミット・push する。前回変換したコミットは /.seisho に記録する - リネームは消して作り直すので、旧名の PDF が残らない - rclone-config / rclone-remote を指定すると、変換した PDF を送り、消した分は 送り先からも消す - 入力 pdf-branch / source-branch と、元のブランチへ戻す処理は無くなった Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01USCeESvgLneCai7g8399GM --- README.md | 38 +++++++--- action.yml | 198 +++++++++++++++++++++++++-------------------------- docs/spec.md | 8 +-- 3 files changed, 131 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index d3bc915..6f4adab 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # seisho / 清書 -清書。リポジトリの `.qd` を [Quarkdown](https://github.com/iamgio/quarkdown) で PDF にし、`pdf` ブランチへ置く GitHub Action。 +清書。リポジトリの `.qd` を [Quarkdown](https://github.com/iamgio/quarkdown) で PDF にし、同じブランチの `pdf/` フォルダ (と、指定すれば OneDrive などの送り先) に置く GitHub Action。 ## 使い方 @@ -8,12 +8,12 @@ # .github/workflows/pdf.yml on: push: - branches: [master] + branches: [main] permissions: contents: write -# 続けて push したときに pdf ブランチへの push がぶつからないように +# 続けて push したときに PDF のコミットがぶつからないように concurrency: pdf jobs: @@ -21,17 +21,18 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: 5ym/seisho@v1 + - uses: 5ym/seisho@v2 ``` | 入力 | 既定 | 内容 | | --- | --- | --- | -| `source-branch` | push されたブランチ | `.qd` を読むブランチ | -| `pdf-branch` | `pdf` | PDF を置くブランチ。無ければ作る | +| `output-dir` | `pdf` | PDF を置くフォルダ。`.qd` と同じフォルダ構造でこの下に置き、コミットして push する | | `default-setup` | `true` | 既定の設定 ([_setup.qd](_setup.qd)) を各文書の先頭に足す | +| `rclone-config` | | `rclone.conf` の中身。`rclone-remote` と一緒に指定すると、そこへも PDF を送る | +| `rclone-remote` | | PDF を送る先 (例 `onedrive:Documents/report`) | | `quarkdown-major` | `2` | この系列の最新リリースを使う | -動きの細かいところ (変換する範囲・消したときの扱い・作り直し方など) は [docs/spec.md](docs/spec.md) にまとめています。 +動きの細かいところは [docs/spec.md](docs/spec.md) にまとめています。 ## 書き方 @@ -40,6 +41,27 @@ jobs: - 日本語フォントは同梱されていないので `.font` で指定しています。コード用も指定しないと、コード中の日本語が豆腐になります。 - Mermaid の図の中は日本語が出ません。ラベルは英数字で書いてください。 +## OneDrive などにも置く + +送り先は [rclone](https://rclone.org/) の設定で決めます (OneDrive・Google Drive・Dropbox・S3 など)。 + +1. 手元で `rclone config` を実行し、送り先 (例 `onedrive`) を作る。ブラウザでのログインが求められます +2. できた設定 (`rclone config file` で場所が出ます) をリポジトリの secret にする: `gh secret set RCLONE_CONFIG < ~/.config/rclone/rclone.conf` +3. ワークフローに足す: + +```yaml + - uses: 5ym/seisho@v2 + with: + rclone-config: ${{ secrets.RCLONE_CONFIG }} + rclone-remote: onedrive:Documents/report +``` + +OneDrive のログインは、使わないまま 90 日ほど経つと切れます。切れたら手元で `rclone config reconnect onedrive:` をして、secret を入れ直してください。 + ## 手元で確認 -[インストール](https://github.com/iamgio/quarkdown#getting-started)して `quarkdown c 文書.qd -w -p --allow global-read` でライブプレビュー、`--pdf` で PDF です。手元では既定の設定が足されないので、同じ見た目で確かめたいときは文書の先頭に [_setup.qd](_setup.qd) の中身を写すか `.include` してください。`--allow global-read` は親ディレクトリのファイルを読むために要ります。VS Code なら公式拡張 [Quarkdown](https://marketplace.visualstudio.com/items?itemName=quarkdown.quarkdown-vscode) に `"quarkdown.additionalCompilerOptions": "--allow global-read"` を設定します。 +[インストール](https://github.com/iamgio/quarkdown#getting-started)して `quarkdown c 文書.qd -w -p --allow global-read` でライブプレビュー、`--pdf` で PDF です。手元では既定の設定が足されないので、同じ見た目で確かめたいときは文書の先頭に [_setup.qd](_setup.qd) の中身を写すか `.include` してください。VS Code なら公式拡張 [Quarkdown](https://marketplace.visualstudio.com/items?itemName=quarkdown.quarkdown-vscode) に `"quarkdown.additionalCompilerOptions": "--allow global-read"` を設定します。 + +## v1 から移る + +v1 は `pdf` ブランチに置いていました。`5ym/seisho@v2` に変え、入力の `pdf-branch`・`source-branch` を外して push すると、最初の実行で全ての PDF を `pdf/` に作ります。`pdf` ブランチは要らなくなるので消してください。 diff --git a/action.yml b/action.yml index 28ac846..8ac07a2 100644 --- a/action.yml +++ b/action.yml @@ -1,23 +1,27 @@ -name: seisho (Quarkdown to PDF branch) -description: 清書。リポジトリ内の .qd を Quarkdown で PDF にし、元のフォルダ構造のまま pdf ブランチへ置く (変更があったものだけ) +name: seisho (Quarkdown to PDF) +description: 清書。リポジトリ内の .qd を Quarkdown で PDF にし、同じブランチの pdf フォルダ (と、指定すれば OneDrive などの rclone の送り先) へ置く author: 5ym branding: icon: file-text color: gray-dark inputs: - source-branch: - description: .qd を読むブランチ。省略時は push されたブランチ - required: false - default: "" - pdf-branch: - description: PDF を置くブランチ。無ければ作る + output-dir: + description: PDF を置くフォルダ。.qd と同じフォルダ構造でこの下に置く required: false default: pdf default-setup: description: 既定の設定 (この Action の _setup.qd。A4・日本語フォントなど) を各文書の先頭に足す。文書の中で同じ関数を呼べば上書きできる required: false default: "true" + rclone-config: + description: rclone.conf の中身 (secrets から渡す)。rclone-remote と一緒に指定すると、そこへも PDF を送る + required: false + default: "" + rclone-remote: + description: PDF を送る rclone の送り先 (例 onedrive:Documents/report)。output-dir と同じフォルダ構造で置く + required: false + default: "" quarkdown-major: description: 使う Quarkdown のメジャーバージョン。その系列の最新リリースを使う required: false @@ -30,59 +34,41 @@ inputs: runs: using: composite steps: - - name: git config and fetch branch - id: init + - name: list changed .qd + id: list shell: bash + env: + OUT: ${{ inputs.output-dir }} run: | - # 最後に戻す先 (呼び出し前のブランチ。ブランチに乗っていなければコミット) - echo "orig=$(git branch --show-current || true)" >> "$GITHUB_OUTPUT" - echo "orig-sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git config --local user.name "GitHub Action" + git config --local user.name "github-actions[bot]" git config --global core.quotepath false - git fetch --no-tags --prune --depth=1 - - name: init pdf branch, remove deleted, list modified - id: check - shell: bash - env: - SRC: ${{ inputs.source-branch || github.ref_name }} - PDF: ${{ inputs.pdf-branch }} - run: | - # source-branch にチェックアウトしていないブランチを指定されたときは origin から作る - if ! git rev-parse --verify -q "refs/heads/$SRC" > /dev/null; then - git branch "$SRC" "origin/$SRC" 2> /dev/null || { - echo "ブランチ $SRC が見つかりません。push か workflow_dispatch で呼ぶか、source-branch を指定してください" >&2 - exit 1 - } - fi - echo "src=$SRC" >> "$GITHUB_OUTPUT" - if git ls-remote --exit-code --heads origin "$PDF" > /dev/null; then - git checkout "$PDF" - git fetch --unshallow origin "$PDF" || true - else - # 空のツリーの SHA を起点にすると、初回は全ての .qd が変換対象になる - git checkout --orphan "$PDF" - git rm -rf --quiet . - echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904 > convertdone.txt - git add . && git commit --quiet -m "first commit" + # 前回からの差分を取るので履歴が要る + if [ "$(git rev-parse --is-shallow-repository)" = true ]; then + git fetch --quiet --unshallow origin fi - base=$(git show "$PDF:convertdone.txt") - # _ で始まるファイル(.include で読む分割用)は単体では変換しない - list() { git diff --name-only --diff-filter="$1" "$base" "$SRC" | grep -E '\.qd$' | grep -v '\(^\|/\)_' || true; } - deleted=$(list D) - if [ -n "$deleted" ]; then - printf '%s\n' "$deleted" | while read -r f; do rm -f "${f%.*}.pdf"; done - git add -A && git commit --quiet -m "remove" || true - fi - list MAR > modified.txt - if [ -s modified.txt ]; then - echo "status=success" >> "$GITHUB_OUTPUT" - else - rm -f modified.txt + OUT=${OUT%/} + head=$(git rev-parse HEAD) + # 前回変換したコミット。無ければ (初回・フォルダを消したとき) 空のツリーから = 全部 + base=$(cat "$OUT/.seisho" 2> /dev/null || true) + git cat-file -e "$base^{commit}" 2> /dev/null || base=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + # リネームは削除 + 追加として扱い、旧名の PDF も消す。 + # _ で始まるファイル (.include で読む分割用) と出力先の中は対象外 + list() { + git diff --no-renames --name-only --diff-filter="$1" "$base" "$head" | + grep -E '\.qd$' | grep -v '\(^\|/\)_' | grep -v "^$OUT/" || true + } + list D > "$RUNNER_TEMP/seisho-deleted.txt" + list AM > "$RUNNER_TEMP/seisho-modified.txt" + echo "head=$head" >> "$GITHUB_OUTPUT" + echo "out=$OUT" >> "$GITHUB_OUTPUT" + [ -s "$RUNNER_TEMP/seisho-modified.txt" ] && echo "convert=true" >> "$GITHUB_OUTPUT" + if [ -s "$RUNNER_TEMP/seisho-modified.txt" ] || [ -s "$RUNNER_TEMP/seisho-deleted.txt" ]; then + echo "changed=true" >> "$GITHUB_OUTPUT" fi - name: resolve quarkdown version id: quarkdown - if: steps.check.outputs.status == 'success' + if: steps.list.outputs.convert == 'true' shell: bash env: GH_TOKEN: ${{ inputs.token }} @@ -97,47 +83,37 @@ runs: echo "version=${tag#v}" >> "$GITHUB_OUTPUT" - name: cache quarkdown id: quarkdown-cache - if: steps.check.outputs.status == 'success' + if: steps.list.outputs.convert == 'true' uses: actions/cache@v6 with: - # 本体(JRE同梱)・puppeteer・Chromeが全てこの下に入る + # 本体 (JRE 同梱) と chrome-headless-shell が全てこの下に入る path: ${{ runner.tool_cache }}/quarkdown key: quarkdown-${{ runner.os }}-${{ steps.quarkdown.outputs.version }} - name: install quarkdown - if: steps.check.outputs.status == 'success' && steps.quarkdown-cache.outputs.cache-hit != 'true' + if: steps.list.outputs.convert == 'true' && steps.quarkdown-cache.outputs.cache-hit != 'true' uses: quarkdown-labs/setup-quarkdown@v1 with: quarkdown-version: ${{ steps.quarkdown.outputs.version }} - name: use cached quarkdown - if: steps.check.outputs.status == 'success' && steps.quarkdown-cache.outputs.cache-hit == 'true' + if: steps.list.outputs.convert == 'true' && steps.quarkdown-cache.outputs.cache-hit == 'true' shell: bash run: | - # setup-quarkdownが作る/usr/local/binのラッパーはキャッシュ対象外なので、 - # ラッパーが設定する環境変数を張り直す。2.6以降はchrome-headless-shellを - # インストール先のlibに置き、その場所をQD_CHROME_PATHで渡す + # setup-quarkdown が作る /usr/local/bin のラッパーはキャッシュされないので、 + # ラッパーが設定する環境変数を張り直す (2.6 以降は Chrome の場所を QD_CHROME_PATH で渡す) dir="$RUNNER_TOOL_CACHE/quarkdown" echo "$dir/bin" >> "$GITHUB_PATH" - chrome=$(find "$dir/lib" -type f -name chrome-headless-shell -perm -u+x 2>/dev/null | head -n 1) + chrome=$(find "$dir/lib" -type f -name chrome-headless-shell -perm -u+x 2> /dev/null | head -n 1) if [ -n "$chrome" ]; then echo "QD_CHROME_PATH=$chrome" >> "$GITHUB_ENV" fi - # 2.5以前(puppeteerでChromeを入れていた版)向け - echo "QD_NPM_PREFIX=$dir/lib" >> "$GITHUB_ENV" - echo "PUPPETEER_CACHE_DIR=$dir/lib/puppeteer_cache" >> "$GITHUB_ENV" - name: convert - if: steps.check.outputs.status == 'success' + if: steps.list.outputs.changed == 'true' shell: bash env: - SRC: ${{ steps.check.outputs.src }} - PDF: ${{ inputs.pdf-branch }} + OUT: ${{ steps.list.outputs.out }} + HEAD_SHA: ${{ steps.list.outputs.head }} SETUP: ${{ inputs.default-setup == 'true' && format('{0}/_setup.qd', github.action_path) || '' }} run: | - git checkout "$SRC" - git checkout -b quarkdown-pdf-tmp - # 元のフォルダ構造のまま、.qd と同じ名前の pdf を作る。 - # Quarkdown は出力名の記号(全角のコロンや空白など)を - に置き換えるので、 - # 一時ディレクトリに固定の名前で出してから元の名前へ移す。 - # --pdf-no-sandbox は ubuntu ランナーでは AppArmor により Chrome の sandbox が使えないため while read -r f; do in=$f if [ -n "$SETUP" ]; then @@ -145,41 +121,61 @@ runs: in="$(dirname "$f")/.seisho.$(basename "$f")" { cat "$SETUP"; echo; cat "$f"; } > "$in" fi - out=$(mktemp -d) + # Quarkdown は出力名の記号 (全角のコロンや空白など) を - に置き換えるので、 + # 一時ディレクトリに固定の名前で出してから元の名前へ移す。 + # --pdf-no-sandbox は ubuntu ランナーでは AppArmor により Chrome の sandbox が使えないため + tmp=$(mktemp -d) quarkdown c "$in" --pdf --strict --allow global-read --pdf-no-sandbox \ - --out "$out" --out-name document - mv "$out/document.pdf" "${f%.*}.pdf" - rm -rf "$out" + --out "$tmp" --out-name document [ "$in" = "$f" ] || rm -f "$in" - done < modified.txt - git add . && git commit --quiet -m "tmp" - git checkout "$PDF" - git show quarkdown-pdf-tmp:modified.txt | sed 's/\.[^.]*$//' | while read -r f; do - git checkout quarkdown-pdf-tmp -- "$f.pdf" - done - git rev-parse "$SRC" > convertdone.txt - git add . && git commit --quiet -m "convert" - - name: push + mkdir -p "$OUT/$(dirname "$f")" + mv "$tmp/document.pdf" "$OUT/${f%.*}.pdf" + rm -rf "$tmp" + done < "$RUNNER_TEMP/seisho-modified.txt" + while read -r f; do + rm -f "$OUT/${f%.*}.pdf" + done < "$RUNNER_TEMP/seisho-deleted.txt" + [ -d "$OUT" ] && find "$OUT" -type d -empty -delete + mkdir -p "$OUT" + echo "$HEAD_SHA" > "$OUT/.seisho" + - name: commit and push + if: steps.list.outputs.changed == 'true' shell: bash env: - PDF: ${{ inputs.pdf-branch }} + OUT: ${{ steps.list.outputs.out }} run: | - if [ "$(git branch --show-current)" = "$PDF" ]; then - git push origin "HEAD:$PDF" + branch=$(git branch --show-current) + if [ -z "$branch" ]; then + echo "ブランチに乗っていないのでコミットできません。push か workflow_dispatch で呼んでください" >&2 + exit 1 fi - # 作業ツリーを呼び出し前の状態に戻す。途中で失敗しても戻す。後に続く step と、 - # action 自身の後処理 (uses: ./ で呼んだときは action.yml を作業ツリーから読み直す) のため - - name: restore working tree - if: always() && steps.init.outputs.orig-sha != '' + git add -A -- "$OUT" + git diff --cached --quiet && exit 0 + # GITHUB_TOKEN で push したコミットは次のワークフローを起動しない + git commit --quiet -m "PDF を更新する (seisho)" + for i in 1 2 3; do + git push --quiet origin "HEAD:refs/heads/$branch" && exit 0 + # 間に別の push があったら取り込み直す (PDF とソースは別の場所なのでぶつからない) + git pull --quiet --rebase origin "$branch" + done + exit 1 + - name: upload with rclone + if: steps.list.outputs.changed == 'true' && inputs.rclone-config != '' && inputs.rclone-remote != '' shell: bash env: - ORIG: ${{ steps.init.outputs.orig }} - ORIG_SHA: ${{ steps.init.outputs.orig-sha }} + OUT: ${{ steps.list.outputs.out }} + RCLONE_CONF: ${{ inputs.rclone-config }} + REMOTE: ${{ inputs.rclone-remote }} run: | - # 変換が途中で落ちたときに残る写しを消す - find . -name '.seisho.*.qd' -not -path './.git/*' -delete - if [ -n "$ORIG" ]; then - git checkout --quiet --force "$ORIG" - else - git checkout --quiet --force --detach "$ORIG_SHA" + command -v rclone > /dev/null || curl -fsSL https://rclone.org/install.sh | sudo bash > /dev/null + conf="$RUNNER_TEMP/seisho-rclone.conf" + printf '%s\n' "$RCLONE_CONF" > "$conf" + sed 's/\.qd$/.pdf/' "$RUNNER_TEMP/seisho-modified.txt" > "$RUNNER_TEMP/seisho-up.txt" + sed 's/\.qd$/.pdf/' "$RUNNER_TEMP/seisho-deleted.txt" > "$RUNNER_TEMP/seisho-rm.txt" + if [ -s "$RUNNER_TEMP/seisho-up.txt" ]; then + rclone copy --config "$conf" --files-from-raw "$RUNNER_TEMP/seisho-up.txt" "$OUT" "$REMOTE" + fi + if [ -s "$RUNNER_TEMP/seisho-rm.txt" ]; then + rclone delete --config "$conf" --files-from-raw "$RUNNER_TEMP/seisho-rm.txt" "$REMOTE" || true fi + rm -f "$conf" diff --git a/docs/spec.md b/docs/spec.md index e51a4d1..573c83e 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -1,10 +1,10 @@ # 仕様 -- `push` と `workflow_dispatch` で使えます (`pull_request` には対応していません)。 -- `.qd` と同じフォルダ構造・同じ名前で `pdf` ブランチに PDF を置きます。変更があったものだけ変換し、消した `.qd` の PDF は消します。リネームした場合は旧名の PDF が残ります。 +- `push` と `workflow_dispatch` で、ブランチに乗った状態で使えます (`pull_request` には対応していません)。PDF は呼ばれたブランチにコミットして push します。GITHUB_TOKEN で push したコミットは次のワークフローを起動しないので、変換がくり返されることはありません。 +- `.qd` と同じフォルダ構造・同じ名前で `output-dir` (既定 `pdf`) の下に PDF を置きます。 +- 前回変換したコミットを `/.seisho` に記録し、そこからの差分だけを変換します。消した `.qd` の PDF は消し、リネームは消して作り直します。全部作り直したいときは `.seisho` (かフォルダごと) を消して push します。差分を取るため、浅い clone なら履歴を取り直します。 - `_` で始まるファイルは単体では変換しません。`.include` で読み込む分割用のファイルに使います。 - `default-setup` が `true` (既定) のときは、[_setup.qd](../_setup.qd) を先頭に足した写しを同じフォルダに `.seisho.<名前>.qd` として作って変換し、終わったら消します。相対パスはそのまま使えます。先頭に 5 行足すので、`--strict` のエラーの行番号はそのぶんずれます。 -- 全部作り直したいときは `pdf` ブランチを消してから push します。 - `--strict` で変換するので、未定義の関数などがあれば失敗します。 +- `rclone-config` と `rclone-remote` を指定すると、変換した PDF を送り先にも同じフォルダ構造で送り、消した `.qd` の PDF は送り先からも消します。送り先にある他のファイルには触りません。 - Quarkdown は `quarkdown-major` の系列の最新リリースを [setup-quarkdown](https://github.com/quarkdown-labs/setup-quarkdown) で入れ、版ごとに `actions/cache` でキャッシュします。PDF は HTML をヘッドレス Chrome で描くので LaTeX は要りません。 -- 途中で `pdf` ブランチに切り替えて作業し、最後に呼び出し前のブランチ (かコミット) に戻します。この Action より前の step で作業ツリーに加えた未コミットの変更は捨てられるので、`actions/checkout` の直後に置いてください。 From 56730cda48e04d538dce4da8360fa0805b203beb Mon Sep 17 00:00:00 2001 From: Ruk Doe Date: Sat, 3 Oct 2026 21:26:51 +0900 Subject: [PATCH 2/3] =?UTF-8?q?rclone=20=E3=81=AF=E3=82=B3=E3=83=9F?= =?UTF-8?q?=E3=83=83=E3=83=88=E3=82=88=E3=82=8A=E5=85=88=E3=81=AB=E9=80=81?= =?UTF-8?q?=E3=82=8A=E3=80=81=E5=A4=B1=E6=95=97=E3=81=AF=E9=9A=A0=E3=81=95?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=83=BBapt=20=E3=81=A7=E5=85=A5=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E3=83=BB=E8=A8=AD=E5=AE=9A=E3=81=AF=20600=20=E3=81=A7?= =?UTF-8?q?=E6=9B=B8=E3=81=84=E3=81=A6=E5=BF=85=E3=81=9A=E6=B6=88=E3=81=99?= =?UTF-8?q?=E3=83=BBoutput-dir=20=E3=82=92=E6=A4=9C=E8=A8=BC=E3=81=99?= =?UTF-8?q?=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01USCeESvgLneCai7g8399GM --- action.yml | 51 ++++++++++++++++++++++++++++++--------------------- docs/spec.md | 2 +- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/action.yml b/action.yml index 8ac07a2..67efd25 100644 --- a/action.yml +++ b/action.yml @@ -48,6 +48,11 @@ runs: git fetch --quiet --unshallow origin fi OUT=${OUT%/} + case "$OUT" in + "" | . | /* | .. | ../* | */.. | */../*) + echo "output-dir にはリポジトリの中のフォルダを指定してください: '$OUT'" >&2 + exit 1 ;; + esac head=$(git rev-parse HEAD) # 前回変換したコミット。無ければ (初回・フォルダを消したとき) 空のツリーから = 全部 base=$(cat "$OUT/.seisho" 2> /dev/null || true) @@ -56,7 +61,7 @@ runs: # _ で始まるファイル (.include で読む分割用) と出力先の中は対象外 list() { git diff --no-renames --name-only --diff-filter="$1" "$base" "$head" | - grep -E '\.qd$' | grep -v '\(^\|/\)_' | grep -v "^$OUT/" || true + grep -E '\.qd$' | grep -v '\(^\|/\)_' | awk -v p="$OUT/" 'index($0, p) != 1' || true } list D > "$RUNNER_TEMP/seisho-deleted.txt" list AM > "$RUNNER_TEMP/seisho-modified.txt" @@ -138,6 +143,30 @@ runs: [ -d "$OUT" ] && find "$OUT" -type d -empty -delete mkdir -p "$OUT" echo "$HEAD_SHA" > "$OUT/.seisho" + # コミットより先に送る。送れなかったときは .seisho を進めないので、次の実行でまた送る + - name: upload with rclone + if: steps.list.outputs.changed == 'true' && inputs.rclone-config != '' && inputs.rclone-remote != '' + shell: bash + env: + OUT: ${{ steps.list.outputs.out }} + RCLONE_CONF: ${{ inputs.rclone-config }} + REMOTE: ${{ inputs.rclone-remote }} + run: | + if ! command -v rclone > /dev/null; then + sudo apt-get update -qq && sudo apt-get install -y -qq rclone > /dev/null + fi + conf="$RUNNER_TEMP/seisho-rclone.conf" + trap 'rm -f "$conf"' EXIT + (umask 077 && printf '%s\n' "$RCLONE_CONF" > "$conf") + sed 's/\.qd$/.pdf/' "$RUNNER_TEMP/seisho-modified.txt" > "$RUNNER_TEMP/seisho-up.txt" + sed 's/\.qd$/.pdf/' "$RUNNER_TEMP/seisho-deleted.txt" > "$RUNNER_TEMP/seisho-rm.txt" + if [ -s "$RUNNER_TEMP/seisho-up.txt" ]; then + rclone copy --config "$conf" --files-from-raw "$RUNNER_TEMP/seisho-up.txt" "$OUT" "$REMOTE" + fi + if [ -s "$RUNNER_TEMP/seisho-rm.txt" ]; then + # 送り先に無いファイルは一覧に出ないだけなので、ここでの失敗は本物のエラー + rclone delete --config "$conf" --files-from-raw "$RUNNER_TEMP/seisho-rm.txt" "$REMOTE" + fi - name: commit and push if: steps.list.outputs.changed == 'true' shell: bash @@ -159,23 +188,3 @@ runs: git pull --quiet --rebase origin "$branch" done exit 1 - - name: upload with rclone - if: steps.list.outputs.changed == 'true' && inputs.rclone-config != '' && inputs.rclone-remote != '' - shell: bash - env: - OUT: ${{ steps.list.outputs.out }} - RCLONE_CONF: ${{ inputs.rclone-config }} - REMOTE: ${{ inputs.rclone-remote }} - run: | - command -v rclone > /dev/null || curl -fsSL https://rclone.org/install.sh | sudo bash > /dev/null - conf="$RUNNER_TEMP/seisho-rclone.conf" - printf '%s\n' "$RCLONE_CONF" > "$conf" - sed 's/\.qd$/.pdf/' "$RUNNER_TEMP/seisho-modified.txt" > "$RUNNER_TEMP/seisho-up.txt" - sed 's/\.qd$/.pdf/' "$RUNNER_TEMP/seisho-deleted.txt" > "$RUNNER_TEMP/seisho-rm.txt" - if [ -s "$RUNNER_TEMP/seisho-up.txt" ]; then - rclone copy --config "$conf" --files-from-raw "$RUNNER_TEMP/seisho-up.txt" "$OUT" "$REMOTE" - fi - if [ -s "$RUNNER_TEMP/seisho-rm.txt" ]; then - rclone delete --config "$conf" --files-from-raw "$RUNNER_TEMP/seisho-rm.txt" "$REMOTE" || true - fi - rm -f "$conf" diff --git a/docs/spec.md b/docs/spec.md index 573c83e..13c4637 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -6,5 +6,5 @@ - `_` で始まるファイルは単体では変換しません。`.include` で読み込む分割用のファイルに使います。 - `default-setup` が `true` (既定) のときは、[_setup.qd](../_setup.qd) を先頭に足した写しを同じフォルダに `.seisho.<名前>.qd` として作って変換し、終わったら消します。相対パスはそのまま使えます。先頭に 5 行足すので、`--strict` のエラーの行番号はそのぶんずれます。 - `--strict` で変換するので、未定義の関数などがあれば失敗します。 -- `rclone-config` と `rclone-remote` を指定すると、変換した PDF を送り先にも同じフォルダ構造で送り、消した `.qd` の PDF は送り先からも消します。送り先にある他のファイルには触りません。 +- `rclone-config` と `rclone-remote` を指定すると、変換した PDF を送り先にも同じフォルダ構造で送り、消した `.qd` の PDF は送り先からも消します。送り先にある他のファイルには触りません。送るのはコミットより先で、送れなかったときはジョブを失敗させて `.seisho` を進めないので、次の実行でまた送ります。 - Quarkdown は `quarkdown-major` の系列の最新リリースを [setup-quarkdown](https://github.com/quarkdown-labs/setup-quarkdown) で入れ、版ごとに `actions/cache` でキャッシュします。PDF は HTML をヘッドレス Chrome で描くので LaTeX は要りません。 From fe9bf8f4abf62c08419ce1f2ef13077f42635d84 Mon Sep 17 00:00:00 2001 From: Ruk Doe Date: Sat, 3 Oct 2026 21:28:43 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=E9=80=81=E3=82=8A=E5=85=88=E3=81=AE?= =?UTF-8?q?=E7=A9=BA=E3=83=95=E3=82=A9=E3=83=AB=E3=83=80=E3=81=AF=E6=AE=8B?= =?UTF-8?q?=E3=81=99=E3=81=93=E3=81=A8=E3=82=92=E4=BB=95=E6=A7=98=E3=81=AB?= =?UTF-8?q?=E6=9B=B8=E3=81=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01USCeESvgLneCai7g8399GM --- docs/spec.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec.md b/docs/spec.md index 13c4637..76a6349 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -6,5 +6,5 @@ - `_` で始まるファイルは単体では変換しません。`.include` で読み込む分割用のファイルに使います。 - `default-setup` が `true` (既定) のときは、[_setup.qd](../_setup.qd) を先頭に足した写しを同じフォルダに `.seisho.<名前>.qd` として作って変換し、終わったら消します。相対パスはそのまま使えます。先頭に 5 行足すので、`--strict` のエラーの行番号はそのぶんずれます。 - `--strict` で変換するので、未定義の関数などがあれば失敗します。 -- `rclone-config` と `rclone-remote` を指定すると、変換した PDF を送り先にも同じフォルダ構造で送り、消した `.qd` の PDF は送り先からも消します。送り先にある他のファイルには触りません。送るのはコミットより先で、送れなかったときはジョブを失敗させて `.seisho` を進めないので、次の実行でまた送ります。 +- `rclone-config` と `rclone-remote` を指定すると、変換した PDF を送り先にも同じフォルダ構造で送り、消した `.qd` の PDF は送り先からも消します。送り先にある他のファイルには触りません。送り先で空になったフォルダは残ります (送り先の無関係な空フォルダまで消さないため)。送るのはコミットより先で、送れなかったときはジョブを失敗させて `.seisho` を進めないので、次の実行でまた送ります。 - Quarkdown は `quarkdown-major` の系列の最新リリースを [setup-quarkdown](https://github.com/quarkdown-labs/setup-quarkdown) で入れ、版ごとに `actions/cache` でキャッシュします。PDF は HTML をヘッドレス Chrome で描くので LaTeX は要りません。