שילוב IDE ו־DAP#

פרק זה מכסה ניפוי שגיאות מונע־עורך: Perl::LanguageServer ב־VS Code ומקביליו ב־Neovim / Emacs / IntelliJ, ניפוי שגיאות מרחוק על־גבי SSH, וניפוי שגיאות במצב מכולה באמצעות kubectl או docker.

קוראים הפונים ל־IDE במקום ל־prompt של טרמינל ימצאו כאן את ההגדרות המינימליות בנות־קיימא, את מפתחות התצורה שחשובים, ואת נקודות השבירות הידועות (Coro, מיפוי נתיבים, attach מול launch).

הנוף#

שני פרוטוקולי חוט, שניהם עם backends ב־Perl:

פרוטוקול

backend ב־Perl

סטטוס

DAP

Perl::LanguageServer

פעיל.

DBGp

Devel::Debug::DBGp

קופא מאז 2018.

עבור הגדרות חדשות, השתמשו ב־DAP דרך Perl::LanguageServer. DBGp שורד רק היכן שלקוח קיים (vim vdebug, pugdebug) כבר בשימוש.

Perl::LanguageServer מאגד LSP (אינטליגנציית קוד, אבחונים, מעבר־להגדרה) ומתאם DAP (מנפה שגיאות) בתוך תהליך אחד. החצי של LSP עובד על כל קובץ Perl בעורך; החצי של DAP רץ רק במהלך סשן ניפוי שגיאות.

הגדרת VS Code מינימלית#

צד CPAN - התקינו אל ה־Perl ש־debuggee ירוץ תחתיו:

cpanm Perl::LanguageServer

צד העורך - התקינו את ההרחבה richterger.perl:

Ctrl-P  →  ext install richterger.perl

.vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "perl",
      "request": "launch",
      "name": "Debug current file",
      "program": "${workspaceFolder}/${relativeFile}",
      "stopOnEntry": true,
      "args": [],
      "cwd": "${workspaceFolder}",
      "env": {},
      "reloadModules": true
    }
  ]
}

פתחו .pl או .pm, קבעו breakpoints ב־gutter, הקישו F5. ה־Debug Console מקבל כל ביטוי Perl, מוערך במסגרת המחסנית הנוכחית.

.vscode/settings.json עבור @INC ובחירת פרשן:

{
  "perl.perlInc": [
    "${workspaceFolder}/lib",
    "${workspaceFolder}/local/lib/perl5"
  ],
  "perl.perlCmd": "/usr/bin/perl"
}

יכולות#

Perl::LanguageServer תומך בתכונות DAP שחשובות:

  • Launch, pause, step in / over / out, return.

  • breakpoints מותנים ובלתי־מותנים, מתווספים בכל זמן.

  • בחינת משתנים על־פני מסגרות מחסנית.

  • Set variable - שינוי ערך באמצע סשן מהעורך.

  • ביטויי watch.

  • הערכה־בהקשר ב־Debug Console.

  • טעינה חמה של מודולים באמצעות reloadModules: true.

לא נתמך:

  • חיבור לתהליך רץ. request: "attach" אינו ממומש; רק "launch" (ה־LS מפעיל את ה־debuggee בעצמו).

ניפוי שגיאות מרחוק על־גבי SSH#

ערכו מקומית; נפו שגיאות על מארח מרוחק. settings.json:

{
  "perl.sshCmd": "ssh",
  "perl.sshAddr": "deploy@host.example",
  "perl.sshUser": "deploy",
  "perl.sshWorkspaceRoot": "/srv/app",
  "perl.pathMap": [
    ["/srv/app", "${workspaceFolder}"]
  ]
}

Perl::LanguageServer רץ על המארח המרוחק; העורך נשאר מקומי. pathMap מתרגם שמות קבצים ש־debuggee מדווח (/srv/app/lib/X.pm) לנתיבי עורך מקומיים (${workspaceFolder}/lib/X.pm).

breakpoints שנכשלים בשתיקה להיקשר הם כמעט תמיד אי־התאמה של pathMap.

ניפוי שגיאות במצב מכולה#

launch.json מקבל מפתחות מכולה שמפעילים docker, podman, docker-compose, או kubectl:

מפתח

ערכים

containerCmd

"docker", "docker-compose", "podman", "kubectl"

containerMode

"run" (מכולה רעננה) או "exec" (קיימת)

containerName

תמונה (עבור run) או שם מכולה (עבור exec)

containerArgs

ארגומנטים נוספים המועברים לזמן הריצה של המכולה.

pathMap

[["/in/container", "/on/host"], ...]

חיבור למכולת Docker שכבר רצה:

{
  "type": "perl",
  "request": "launch",
  "name": "Debug in container",
  "program": "/app/bin/worker.pl",
  "containerCmd": "docker",
  "containerMode": "exec",
  "containerName": "my-running-worker",
  "pathMap": [["/app", "${workspaceFolder}"]]
}

pod של Kubernetes:

{
  "type": "perl",
  "request": "launch",
  "name": "Debug in pod",
  "program": "/app/bin/worker.pl",
  "containerCmd": "kubectl",
  "containerMode": "exec",
  "containerName": "my-pod-abc123",
  "containerArgs": ["-n", "staging", "--container", "app"],
  "pathMap": [["/app", "${workspaceFolder}"]]
}

מגבלות:

  • Perl::LanguageServer חייב להיות מותקן בתוך התמונה. שלבו אותו ב־Dockerfile או בנו וריאנט dev-image.

  • pathMap הוא מצב הכשל הגדול היחיד ביותר. breakpoints שלעולם אינם נקשרים פירושם ש־debuggee מדווח על נתיב שאינו מתורגם.

עורכים אחרים#

  • Neovim - השתמשו ב־nvim-dap עם Perl::LanguageServer כמתאם. מפרט המתאם הוא קטע Lua קצר המצביע אל perl -MPerl::LanguageServer -e '...'.

  • Emacs - dap-mode עם אותו מתאם.

  • IntelliJ - Devel::Camelcadedb + תוסף JetBrains Perl. לא DAP; פרוטוקול קנייני. בר־קיימא אך מחוץ למערכת האקולוגית של Perl::LanguageServer.

  • Sublime Text - לקוחות DAP קיימים באמצעות תוספים; השתמשו ב־Perl::LanguageServer כמתאם.

הפעלות במצב מיוחד#

מפתחות launch.json להפעלה לא־ברירת־מחדל:

מפתח

השפעה

useTaintForDebug

מזריק -T לקריאת ה־perl של ה־debuggee.

sudoUser

מבצע re-exec ל־debuggee כמשתמש הזה (דורש sudo ללא סיסמה).

reloadModules

מאפשר טעינה חמה של מודולים במהלך הסשן.

stopOnEntry

עצירה בהוראה הראשונה.

מלכודות#

  • שגיאות בזמן BEGIN צצות כאירועי ״output״ של DAP, לא כאירועי עצירה־ב־breakpoint. השתמשו ב־stopOnEntry: true כדי לקבל עצירה כלשהי אם הסקריפט מת ב־BEGIN.

  • $SIG{__DIE__} של היישום יכול לבלוע חריגות לפני שהמטפל של מנפה השגיאות רץ. עטפו את המטפל של היישום בשמירת if ($^S) (ראו exceptions).

  • ביטויי watch מוערכים מחדש בכל צעד. הימנעו מביטויים יקרים או בעלי תופעות לוואי.

  • אין source maps. ל־Perl אין מושג מקביל ל־source map של JavaScript. source filters (Smart::Comments) יכולים להזיז מספרי שורות מדווחים בשורה אחת; breakpoints בקבצים מסוננים עלולים לנחות על השורה השגויה.

  • צעידה ב־Future::AsyncAwait. עובד למקרים פשוטים; צעידה דרך שרשרות await מורכבות אינה אמינה. רדו ל־perl -d לחקירת async מעמיקה, או השתמשו בלוגינג.

  • Windows native - טיפול ה־stdin של Perl::LanguageServer שבור ב־Windows. WSL עובד.

  • Coro. Perl::LanguageServer מסתמך על Coro פנימית; נקודת השבירות המצוטטת ביותר היא Coro המקיים אינטראקציה גרועה עם תצורות build חריגות. אם השרת מסרב לעלות, בדקו תחילה את לוג ההתקנה של Coro.

למידע נוסף#

  • interactive-debugger - perl -d ישירות, כאשר ערימת ה־IDE היא גוזמה או לא זמינה.