11. CLI コマンド

← 標準ライブラリ · 目次 · 次:レシピ →

12のコマンド:PDF を扱うもの4つ、スクリプトを扱うもの4つ、配布用が2つ、 ライセンス用が2つ。

コマンド 動作
run スクリプトで PDF を検証
compare 2つのバージョンを比較
watch フォルダを監視して到着したファイルを検証
fix 修正を適用して新しい PDF を保存
inspect PDF の概要を素早く表示
lint スクリプトを実行せずに解析
fmt スクリプトを整形
doc スクリプトからドキュメントを生成
pack プロファイルとデータを1つにまとめる
add パッケージをインストール
fingerprint 端末の指紋
license ライセンスの検証

終了コード

検証を行うすべてのコマンドで共通です。

コード 意味
0 すべて合格
1 警告のみ
2 検証エラー、または PDF が読めない
3 スクリプトの構文エラー
pdfl run profile.pdfl file.pdf > report.json
case $? in
  0) echo "approved" ;;
  1) echo "approved with warnings" ;;
  2) echo "rejected — see report.json" ;;
  3) echo "error in the validation script" ;;
esac

pdfl run

スクリプトで PDF を検証します。

pdfl run <script.pdfl> <input.pdf> [options]
オプション 既定 動作
--output json|csv|html|pdf json レポート形式
--output-file <file> 標準出力ではなくファイルへ書き出す
--fail-on error|warning error warning にすると警告でも終了コード2
--verbose 標準エラー出力に追加情報
# 端末に JSON レポート
pdfl run prepress.pdfl magazine.pdf

# 顧客に渡す HTML
pdfl run prepress.pdfl magazine.pdf --output html --output-file report.html

# 監査用 PDF(pdf 形式は常にファイルに出力されます)
pdfl run prepress.pdfl magazine.pdf --output pdf --output-file report.pdf

# 表計算用の CSV
pdfl run prepress.pdfl magazine.pdf --output csv --output-file findings.csv

# 厳格モード:警告も不合格にする
pdfl run prepress.pdfl magazine.pdf --fail-on warning

JSON レポート

{
  "script_name": "prepress.pdfl",
  "input_file": "magazine.pdf",
  "profile": "offset-magazine",
  "status": "FAIL",
  "total_pages_analyzed": 120,
  "error_count": 2,
  "warning_count": 0,
  "info_count": 0,
  "diagnostics": [
    {
      "id": "PDFL-001",
      "severity": "error",
      "check_name": "Ink coverage",
      "message": "page 7: 324% ink (limit 300%)",
      "line": 12
    }
  ]
}

同じ PDF に同じスクリプトを適用すれば、常にバイト単位で同一のレポートが 得られます。バージョン管理や CI での差分比較に使えます。


pdfl compare

2つのバージョンを比較します:テキスト、構造、メタデータ。

pdfl compare <v1.pdf> <v2.pdf> [options]
オプション 既定 動作
--output json|csv|html|pdf json 形式
--output-file <file> ファイルへ書き出す
--normalize 大文字小文字と空白を無視
--ignore-dates 日付を伏せてから比較
--similarity-threshold <0-100> 100 許容する最小類似度
pdfl compare approved_v1.pdf new_v2.pdf --normalize --ignore-dates

# 1% までの差を許容し、それを下回るとエラー
pdfl compare v1.pdf v2.pdf --similarity-threshold 99 \
  --output html --output-file diff.html

動作の仕組み

  • ページは番号ではなく内容で対応付けられます。途中にページが挿入されても、 それ以降すべてを差分として報告することはありません。1000ページ超の文書でも 動きます。
  • 対応付いた各ページに類似度スコアと、変化した行のサンプル(- 削除、 + 追加)が付きます。
  • メタデータの変更は警告、テキストの変更はしきい値未満ならエラー、 しきい値以上なら警告になります。
  • レポートには全体スコアが similarity として入ります。
page 4 → 4: similarity 97.8% | -original title | +revised title

pdfl watch

フォルダを監視し、到着または変更された PDF を検証します。

pdfl watch <folder> --script <script.pdfl> [options]
オプション 既定 動作
--pattern <glob> *.pdf 処理対象のファイル
--exclude <glob> 除外するファイル
--output-dir <folder> PDF と同じ場所 レポートの出力先
--depth <n> 1 サブフォルダの深さ
--debounce <ms> 1000 ファイルが安定するまでの待ち時間
--report json|csv|html|pdf json レポート形式
--fail-fast 最初のエラーで停止
--once 既にあるファイルを処理して終了
# 印刷所の受付フォルダを常時監視
pdfl watch inbox/ --script preflight.pdfl --output-dir reports/ --report html

# CI 向けのバッチ実行:処理後、最悪の終了コードで終了
pdfl watch inbox/ --script preflight.pdfl --once
echo "result: $?"

debounce があるのは、大きなファイルが少しずつ届くためです。ファイルの 変化が止まってから処理するので、途中まで書かれた PDF を読むことがありません。

レポートは <name>.report.json(または .csv.html.pdf)として 書き出されます。


pdfl fix

fix:: の操作を適用し、新しい PDF を保存します。詳細は第8章

pdfl fix <input.pdf> <script.pdfl> --output <output.pdf> [options]
# 何が行われるかだけ確認(保存しない)
pdfl fix original.pdf normalize.pdfl --output out.pdf --dry-run

# 実際に適用
pdfl fix original.pdf normalize.pdfl --output fixed.pdf

pdfl inspect

スクリプト無しで PDF の概要を表示します。

pdfl inspect <file.pdf>
File:     magazine.pdf
Size:     26 KB (27284713 bytes)
SHA-256:  af1029842e5bfeae338ead82fb449ef851be742b1d63117c12596e3ea123a616

Pages:    120
Page size: 496 x 709 pt
Boxes:    MediaBox, TrimBox, BleedBox

Metadata:
  Title: Example Magazine
  Creator: Adobe InDesign 19.3

Fonts:    26
  ABCDEF+Helvetica — embedded
  Arial — NOT embedded
Images:   81 (minimum DPI 136, spaces: DeviceCMYK, Indexed)
Max. estimated TAC: 300% (RGB render approximation)

Warnings:
  ! there are non-embedded fonts
  ! 3 image(s) below 300 DPI

新しいファイルが届いたら最初に実行するコマンドです。数秒で、開く価値があるか 判断できます。


pdfl lint

スクリプトを実行せずに解析し、品質上の問題を報告します。

pdfl lint <script.pdfl>

検出する内容:

  • 宣言されて一度も使われない変数・ブロック引数・関数(_ を前置すると 抑制されます:_page
  • 重複またはの check
  • 未知の名前空間(text::struct::visual::prepress::codes::fix::data::
  • check の外にある assert / require
  • fix:: の使用(pdfl fix でのみ動作します)
$ pdfl lint profile.pdfl
profile.pdfl: warning: variable 'LIMIT' declared and never used
profile.pdfl: warning: check "Fonts" declared 2 times

警告があれば終了コード 1 になります。CI で使えます。


pdfl fmt

スクリプトを整形します:2スペースのインデント、一貫した空白、空行の圧縮。 コメントと単位(3mm3mm のまま)は保持されます。

pdfl fmt <script.pdfl>            # その場で整形
pdfl fmt <script.pdfl> --check    # 書き換えず、未整形なら終了コード1
# CI でチーム標準を強制する
for f in profiles/*.pdfl; do pdfl fmt "$f" --check || exit 1; done

pdfl doc

スクリプト自身からドキュメントを生成します。

pdfl doc <script.pdfl> [--output markdown|html]

出力内容:プロファイル、定数の表、関数、import、そして各 check のタグと 検証内容(assert のメッセージが説明になります)。

pdfl doc prepress.pdfl > docs/prepress-profile.md
pdfl doc prepress.pdfl --output html > profile.html

コードを読まない制作管理者に、プロファイルが何を検証しているかを伝えるための 成果物です。


pdfl pack

スクリプトとデータを配布可能な .pdflpkg にまとめます。

pdfl pack <folder> [--name <name>] [--version <version>] [--output <file>]

フォルダ内の .pdfl.csv.txt.json.xlsx を再帰的に収集し、 各ファイルの SHA-256 を記録した manifest.json を付けます。パッケージは 決定的です:同じフォルダからは同一のバイト列が生成されます。

pdfl pack profiles/print-shop --name print-profile --version 1.0.0

pdfl add

ローカルのパッケージをインストールし、マニフェストのハッシュを検証します。

pdfl add <package.pdflpkg> [--dir <folder>]
pdfl add print-profile.pdflpkg
# ./pdfl_profiles/print-profile@1.0.0/ にインストールされます

pdfl run pdfl_profiles/print-profile@1.0.0/prepress.pdfl file.pdf

いずれかのファイルのハッシュが記録と異なる場合、インストールは拒否され ます。改ざんや破損したパッケージは入りません。

リモートリポジトリと電子署名はこのバージョンには含まれません。add は ローカルファイルからインストールします。


pdfl fingerprint

この端末の指紋 — ライセンスを受け取るために提供元へ送る値です。

pdfl fingerprint generate

指紋だけが標準出力に出ます。周りの説明は標準エラー出力に出るので、 pdfl fingerprint generate 2>/dev/null でそのままパイプに渡せる値が得られます。

$ pdfl fingerprint generate
Device fingerprint for this machine:

1a7553e711c53306be083ea8927c9cbe

Send it to your vendor to be issued a license.
It changes if the operating system is reinstalled.

指紋はシステムのマシン識別子(/etc/machine-idIOPlatformUUIDMachineGuid)から作られます。OS を再インストールすると変わり、同じ イメージから複製した仮想マシンは同じ値を共有します。実行ごとに端末が破棄される CI やコンテナ向けには、端末を見ない seatless ライセンスがあります。


pdfl license

受け取ったライセンスを検証します。pdfl検証だけを行います。発行するのは 提供元で、そこで使う秘密鍵はバイナリに同梱されません。

pdfl license check <token>
$ pdfl license check "$(cat license.txt)"
signature:  ok
customer:   Example Print Shop
expires:    2027-01-01
features:   all
device:     1a7553e711c53306be083ea8927c9cbe
this machine: matches

この端末で有効なら終了コード 0、そうでなければ 2 — 署名は正しいが別の端末の ライセンスである場合も含みます。その場合はメッセージがそう伝えます。

オプション 動作
--pubkey <base64> 埋め込まれた鍵の代わりに使う公開鍵

ライセンスが必要なコマンド

runfixwatchcompareinspect は、この端末で有効なライセンスが 無ければ終了コード 2 で停止します。fingerprint generate決して要求しません — ライ センスを申請するための値を作るのがそれだからです。lintfmtdocpack はスクリプトだけを扱い PDF に触れないので、こちらも要求しません。

トークンは次の順で探されます:

  1. $PDFL_LICENSE — CI 向けの経路。シークレットとして渡します
  2. ~/.config/pdfl/license
  3. 実行ファイルの隣の pdfl.license
$ pdfl run profile.pdfl file.pdf
error: no license found

Run 'pdfl fingerprint generate' and send the value to your vendor
to be issued a license. Then set PDFL_LICENSE, or save the token to
/home/you/.config/pdfl/license.

seatless ライセンスには実行回数の上限があり、~/.config/pdfl/state で数え られます。同じファイルが最後の実行時刻も記録し、時計が巻き戻されていれば実行を 拒否します。時刻同期と衝突しないよう、1時間の余裕があります。


← 標準ライブラリ · 目次 · 次:レシピ →