11. سطر الأوامر
← المكتبة القياسية · الفهرس · التالي: وصفات عملية →
اثنا عشر أمرًا: أربعة لملفات PDF، وأربعة للنصوص البرمجية، واثنان للتوزيع، واثنان للتراخيص.
| الأمر | الغرض |
|---|---|
run |
يدقّق ملف PDF بنص برمجي |
compare |
يقارن نسختين |
watch |
يراقب مجلدًا ويدقّق ما يصل إليه |
fix |
يطبّق تعديلات ويحفظ ملف PDF جديدًا |
inspect |
نظرة سريعة على ملف PDF |
lint |
يحلّل نصًا برمجيًا دون تنفيذه |
fmt |
ينسّق نصًا برمجيًا |
doc |
يولّد توثيق نص برمجي |
pack |
يحزم الملفات التعريفية والبيانات |
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 |
— | معلومات إضافية على مخرج الأخطاء |
pdfl run prepress.pdfl magazine.pdf # JSON في الطرفية
pdfl run prepress.pdfl magazine.pdf --output html --output-file report.html
pdfl run prepress.pdfl magazine.pdf --output pdf --output-file report.pdf
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 نفسه مع النص البرمجي نفسه يعطي دائمًا تقريرًا متطابقًا بايتًا بايت: يمكن حفظه في نظام الإصدارات ومقارنة الفروق في التكامل المستمر.
pdfl compare
يقارن نسختين: النص والبنية والبيانات الوصفية.
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
كيف يعمل
- تُحاذى الصفحات بالمحتوى لا بالرقم: فإدراج صفحة في الوسط لا يجعل كل ما بعدها فروقًا. ويعمل على مستندات تتجاوز ألف صفحة.
- يحصل كل زوج على درجة تشابه وعيّنة من الأسطر المتغيرة (
-محذوف،+مضاف). - تغيّر البيانات الوصفية تحذير؛ وتغيّر النص دون العتبة خطأ، وفوقها تحذير.
- الدرجة الإجمالية في الحقل
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
# تشغيل دفعي للتكامل المستمر: يخرج بأسوأ رمز صادفه
pdfl watch inbox/ --script preflight.pdfl --once
echo "result: $?"
الـ debounce موجود لأن الملفات الكبيرة تصل قطعًا: فلا يُعالَج إلا ملف كفّ عن التغيّر، وبذلك لا يُقرأ ملف PDF نصف مكتوب.
تُكتب التقارير باسم <name>.report.json (أو .csv أو .html أو .pdf).
pdfl fix
يطبّق عمليات fix:: ويحفظ ملف PDF جديدًا. التفاصيل في الفصل 8.
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) - الفحوص المكرّرة أو الفارغة
- فضاءات الأسماء غير المعروفة (
text::وstruct::وvisual::وprepress::وcodes::وfix::وdata::) 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 — صالح للتكامل المستمر.
pdfl fmt
ينسّق النص البرمجي: إزاحة بمسافتين، ومسافات متسقة، وضغط الأسطر الفارغة.
وتبقى التعليقات والوحدات (3mm تظل 3mm) كما هي.
pdfl fmt <script.pdfl> # ينسّق في مكانه
pdfl fmt <script.pdfl> --check # لا يغيّر شيئًا؛ الرمز 1 إن لم يكن منسَّقًا
# فرض معيار الفريق في التكامل المستمر
for f in profiles/*.pdfl; do pdfl fmt "$f" --check || exit 1; done
pdfl doc
يولّد التوثيق من النص البرمجي نفسه.
pdfl doc <script.pdfl> [--output markdown|html]
ويُخرج: الملف التعريفي، وجدول الثوابت، والدوال، والاستيرادات، ولكل فحص وسومه
وما يدقّقه (رسائل 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 من المجلد، ويرفق
manifest.json يسجّل بصمة SHA-256 لكل ملف. والحزم حتمي: المجلد نفسه يُنتج
البايتات نفسها.
pdfl pack profiles/print-shop --name print-profile --version 1.0.0
pdfl add
يثبّت حزمة محلية مع التحقق من بصمات البيان.
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-idأوIOPlatformUUIDأوMachineGuid). وهي لا تنجو من إعادة تثبيت النظام، والأجهزة الافتراضية المستنسخة من الصورة نفسها تتشارك القيمة ذاتها. أما للتكامل المستمر والحاويات — حيث يُدمَّر الجهاز في كل تشغيل — فهناك ترخيص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> |
المفتاح العام المستعمل بدل المضمَّن وقت البناء |
أين يُطلب الترخيص
تتوقف run وfix وwatch وcompare وinspect بالرمز 2 إن لم يوجد ترخيص
صالح لهذا الجهاز. أما fingerprint generate فلا يطلبه أبدًا — فهو الذي ينتج القيمة
اللازمة لطلب ترخيص. وlint وfmt وdoc وpack لا تمسّ إلا النصوص البرمجية
دون ملفات PDF، فلا تطلبه هي الأخرى.
يُبحث عن الرمز بهذا الترتيب:
$PDFL_LICENSE— طريق التكامل المستمر، حيث يصير سرًّا~/.config/pdfl/license- ملف
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. ويحفظ الملف نفسه وقت آخر تشغيل، فيرفض العمل إن رجعت الساعة إلى الوراء — بهامش ساعة واحدة كي لا يصطدم بمزامنة الوقت.