المقالة 5 : مغامرة الملف libs.versions.toml المشترك
نُشر في 27 September 2025
مقدمة
في رحلتنا لإنشاء الإضافة`site-baker`, نحن سعينا إلى الحفاظ على قاعدة كود نظيفة وموحدة. إحدى أفضل الممارسات في بيئة Gradle الحديثة هي استخدام الـقائمة الإصدارات(no response)libs.versions.toml) لإدارة الاعتماديات. لكن ما الذي يحدث عندما يصبح مشروعك أكثر تعقيدًا، مثلبناء مركبحيث يجب أن يُدرج بناء مستقل (إضافيتنا) في آخر؟
هنا حيث اتخذت مغامرتنا منعطفًا غير متوقع. كنا نريد أن يكون برنامجنا plugin`site-baker`, الذي هو نفسه مشروع Gradle، يستخدم نفس كتالوج الإصدارات كما في مشروعنا الرئيسي. هذه المقالة، الخامسة في سلسلتنا، تروي كيف حللنا هذا التحدي.
1. كتالوج الإصدارات (libs.versions.toml) : تذكير
الملف`gradle/libs.versions.toml`هي ميزة في Gradle تسمح بتركيز الإصدارات والإحداثيات للاعتمادات لمشروعك. عادةً ما يتم تنظيمه في أربعة أقسام :
-
[versions]`يحدد أسماء مستعارة لأرقام الإصدار (مثال:`kotlin = "1.9.20") -
[libraries]: يحدد أسماء مستعارة للاعتمادات الكاملة، باستخدام الإصدارات المعرفة أعلاه (ex:`kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }`). -
[bundles]: يجمع عدة مكتبات تحت اسم مستعار واحد (مثال:`jackson = ["jackson-core", "jackson-databind"]`). -
`[plugins]`يُعرّف أسماءً مستعارةً للمكوّنات الإضافية Gradle.
بعد تعريفه، يقوم Gradle تلقائيًا بإنشاء الوصولات ذات النوع، مما يجعل ذلك`build.gradle.kts`أكثر قابلية للقراءة :
dependencies {
// Au lieu de : implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.20")
implementation(libs.kotlin.stdlib)
}
@startuml !theme plain file "gradle/libs.versions.toml" as Toml node "Gradle" as G file "build.gradle.kts" as BuildScript Toml --> G : "يُقرأ بواسطة" G --> BuildScript : "يُنشئ الخاصية `libs`" BuildScript -> G : "يستخدم `libs` لإعلان التبعيات" @enduml
2. المشكلة: بناء مركب وعالمين منفصلين
هيكل مشروعنا هوبناء مركب. المشروع الرئيسي (thymeleaf.cheroliv.com) يتضمن مشروع البرنامج المساعد`site-baker`) عبر الأمر`includeBuild("site-baker")في الملف`settings.gradle.kts.
@startuml
!theme plain
package "مشروع رئيسي" {
file "settings.gradle.kts" as MainSettings
folder "gradle" {
file "libs.versions.toml" as MainToml
}
}
package "إضافة `site-baker` (إنشاء شامل)" {
file "settings.gradle.kts" as PluginSettings
file "build.gradle.kts" as PluginBuild
}
MainSettings -> PluginSettings : `includeBuild("site-baker")`
PluginBuild ..> MainToml : كان يريد الوصول إلى…
note right on link: ...لكن لم يستطع!
@enduml
المشكلة هي أنه، افتراضيًا، البناء المشمول هوعالم منفصل. لديه إعداداته الخاصة، ودورة حياته الخاصة، ولا يرى الملف`libs.versions.toml`من البناء الرئيسي. لنا`plugin/build.gradle.kts`كان يحاول použit Actually misuse: ensure Arabic correctly spelled: "كان يحاول استخدم" no it’s "يحاول". Yes "كان يحاول استخدام". I’ll output that. Ensure leading space.
Let’s write: " كان يحاول استخدام". Done.
</think> كان يحاول استخدام`libs.plugins.kotlin.jvm`, لكن الشيء`libs`لم يتم إنشاؤه من الملف TOML الصحيح، مما تسبب في حدوث أخطاء في البناء.
الحل : مشاركة حلّ التبعيات
بعد عدة بحوث، تبين أن الحل هو ميزة في Gradle مصممة بدقة لهذا الحالة:`dependencyResolutionManagement`.
في الملف`settings.gradle.kts` du بناء شامل(site-baker/settings.gradle.kts), يمكننا إخبار Gradle حيث يمكن العثور على كتالوج الإصدارات لاستخدامه.
هذا هو الإعداد الذي أضفناه إلى`site-baker/settings.gradle.kts`:
// site-baker/settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
gradlePluginPortal()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}
rootProject.name = "site-baker"
include("plugin")
لنحلل الجزء الحاسم :
versionCatalogs {
create("libs") { // Crée un catalogue nommé 'libs'
from(files("../gradle/libs.versions.toml")) // En utilisant ce fichier
}
}
-
create("libs"): نعلن عن كتالوج الإصدارات الذي سيكون متاحًا عبر الاسم المستعار`libs`. -
from(files("../gradle/libs.versions.toml")): هذا هو السحر. نحن نُخبر Gradle أن مصدر هذا الفهرس هو ملف TOML الموجود في الدليل`gradle` du المشروع الأصلي(../)
مع هذه الإعدادات، البناء`site-baker`يعرف الآن أنه يجب عليه استخدام كتالوج إصدارات المشروع الرئيسي. الكائن`libs`تم إنشاؤه بشكل صحيح، والاعتماديات محلولة كما هو متوقع.
4. الخلاصة : قوة构建ات المركبة المدارة جيدًا
كانت هذه التجربة غنية بالدروس. فهرس الإصدارات هو أداة رائعة للصيانة، لكن سلوكه في سيناريوهات التراكيب المركبة ليس دائمًا بديهيا.
المفتاح هو أن تتذكر أن البناء المتضمن يظل بناءً مستقلاً. لمشاركة الإعدادات مثل كتالوج الإصدارات، يتعين عليك استخدام الآليات الصريحة التي توفرها Gradle، مثل bloc`dependencyResolutionManagement`في`settings.gradle.kts`.
من خلال حلّ هذه المشكلة، لم ننظفّ البناء فحسب؛ بل قوّينا أيضًا اتساق مشروعنا من خلال التأكد من أن الإضافة ومشروعها الرئيسي يشاركان مصدرًا فريدًا للحقيقة بالنسبة لتبعياتهما.
في المقال القادم، سنستمر في إثراء المكوّن الإضافي الخاص بنا بإضافة مهام أكثر تعقيدًا، الآن أن إدارة الاعتماد لدينا أصبحت قويةً وموحدة.