संदर्भ और उद्देश्य

शुरुआती बिंदु

परियोजना`slider-gradle`Gradle प्लग़िन के माध्यम से AsciiDoc फ़ाइलों से Reveal.js प्रजेंटेशन बनाता है`org.asciidoctor.jvm.revealjs`. मुख्य कार्य की कॉन्फ़िगरेशन`asciidoctorRevealJs`वह रूट buildscript में सीधे रहता था`build.gradle.kts`:

plugins { id("org.asciidoctor.jvm.revealjs") }

apply<slides.SlidesPlugin>()

project.tasks.getByName<AsciidoctorJRevealJSTask>(TASK_ASCIIDOCTOR_REVEALJS) {
    repositories { ruby { gems() } }
    revealjs {
        version = "3.1.0"
        templateGitHub {
            setOrganisation("hakimel")
            setRepository("reveal.js")
            setTag("3.9.1")
        }
    }
    revealjsOptions {
        // ... configuration complète
    }
}

लक्ष्य

इस पूरी कॉन्फ़िगरेशन को`buildSrc/src/main/kotlin/slides/SlidesPlugin.kt`कि बिल्डस्क्रिप्ट उपभोक्ता कम हो जाए :

apply<slides.SlidesPlugin>()

प्लगिन को पूरी तरह से स्वायत्त होना चाहिए: यह अपने प्लगिन निर्भरताओं को स्वयं लागू करता है, अपने रिपॉज़िटरीज़ को कॉन्फ़िगर करता है, और अपने रूबी जेम्स को प्रबंधित करता है।

पहली बाधा : `ruby { gems() }

ग्रोवी शुगर सिंटैक्स क्या छिपाता है

लाइन`repositories { ruby { gems() } }`यह एक Groovy DSL एक्सटेंशन है जो केवल buildscript के निष्पादन संदर्भ में उपलब्ध है। यह buildSrc से 접근 가능한 स्थिर Kotlin API के रूप में मौजूद नहीं है।

इसको फ़ोन करने की कोशिश करते हुए`SlidesPlugin.kt`, संकलन तुरंत असफल हो जाता है।

मैकेनिज़म का विघटन

ग्रेडल कैश का विश्लेषण करने के बाद (~/.gradle/caches/modules-2/files-2.1/rubygems/), फ़ाइल में हमें पता चलता है`ivy-3.1.0.xml`: (Note: The output should be exactly " : " with a leading space, colon, and trailing space, as per the instruction to translate the fragment and preserve formatting.)

<artifact type='gem' url='https://rubygems.org/gems/asciidoctor-revealjs-3.1.0.gem' />

`ruby { gems() }`वास्तव में कर रहा थातीन भिन्न संचालन:

  1. Enregistrer un repo Ivy pointant vers https://rubygems.org/gems/

  2. समूह को बाहर रखें`rubygems`Maven रिपॉजिटरी टकराव से बचने के लिए

  3. जेम को कॉन्फ़िगरेशन में सहेजें`asciidoctorGems`जिससे JRuby इसे रनटाइम पर लोड करे

इन तीन जिम्मेदारियों को कोटलिन में अलग‑अलग रूप से पुन: उत्पन्न किया जाना चाहिए।

तीन भागों का समाधान

भाग 1 : Ivy रेपॉ rubygems के लिए

project.repositories.mavenCentral() {
    content { excludeGroup("rubygems") }
}
project.repositories.ivy {
    url = project.uri("https://rubygems.org/gems/")
    patternLayout { artifact("[module]-[revision].gem") } (1)
    metadataSources { artifact() }
    content { includeGroup("rubygems") }
}
1 एक्सटेंशन`.gem`इसे हार्डकोड किया जाना चाहिए।[ext]`डिफ़ॉल्ट रूप से में हल करता है.jar`, जिससे एक त्रुटि होती है`Resource missing`.

JBake CLI Commands ` # Initialize a new JBake project jbake -i

Bake (generate) the site jbake -b

Bake and serve locally jbake -b -s

Bake and watch for changes jbake -b --reset

Specify source and destination jbake source_folder output_folder

Clear the output directory before baking jbake -b . output --reset `

नोट: आइवी रेपो सीधे घोषित किया गया है पर`project.repositories`और नहीं एक ब्लॉक में`repositories { }`क्योंकि इस ब्लॉक का रिसीवर नहीं है`RepositoryHandler`Gradle का मानक लेकिन एक grolifant API एक्सटेंशन के साथ अनुकूल नहीं`ivy`# Gradle Integration JBake को Gradle बिल्ड में JBake Gradle प्लगइन का उपयोग करके या JBake CLI को सीधे बुलाकर एकीकृत किया जा सकता है:

----
tasks.register<JavaExec>("bake") {
    mainClass.set("org.jbake.launcher.Main")
    classpath = configurations["jbake"]
    args = listOf(projectDir.absolutePath, "$buildDir/jbake")
}

=== भाग 2: निर्भरता asciidoctorGems

प्लगइन`org.asciidoctor.jvm.gems`इसे पहले लागू किया जाना चाहिए — यह कॉन्फ़िगरेशन बनाता है`asciidoctorGems`और कार्य`asciidoctorGemsPrepare`:

[source,kotlin]
----
project.plugins.apply("org.asciidoctor.jvm.gems")
project.plugins.apply("org.asciidoctor.jvm.revealjs") (1)

project.dependencies {
    add("asciidoctorGems", "rubygems:asciidoctor-revealjs:3.1.0@gem") (2)
}
----

<1> लागू करने का क्रम महत्वपूर्ण है :
### JBake CLI कमांड
----

# एक नया JBake प्रोजेक्ट प्रारंभ करें jbake -i

# बेक (जेनरेट) साइट jbake -b

# बेक और स्थानीय रूप से परोसें jbake -b -s

# बेक और बदलावों की निगरानी करें jbake -b --reset

# स्रोत और गंतव्य निर्दिष्ट करें jbake source_folder output_folder

# बेकिंग से पहले आउटपुट निर्देशिका साफ़ करें jbake -b . output --reset`gems`पहले`revealjs`. <2> योग्यकर्ता`@gem`निर्भरता पर सही एक्सटेंशन बल दें।

=== भाग 3 : settings.gradle.kts

`dependencyResolutionManagement`में`settings.gradle.kts`इसे परियोजनाओं को अपने स्वयं के रिपॉज़िटरी की घोषणा करने की अनुमति देनी चाहिए :

[source,kotlin]
----
@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
}
----

इसी पंक्ति के बिना, Gradle प्लगइन में घोषित रिपॉज़िटरी को अनदेखा करता है और gems का समाधान विफल हो जाता है।

== बाइटकोड्स द्वारा API का आत्मनिरीक्षण

=== क्यों `javap` ?

प्लगइन`asciidoctor-gradle-jvm-slides` est en version `4.0.0-alpha.1`. उसका दस्तावेज़ अस्तित्वहीन या अपूर्ण है। एकमात्र विश्वसनीय स्रोत संकलित क्लासेस की प्रत्यक्ष जाँच है।

=== कार्य का पदानुक्रम

[source,bash]
----
javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
  org.asciidoctor.gradle.jvm.slides.AsciidoctorJRevealJSTask
----

परिणाम :

[source]
----
public class AsciidoctorJRevealJSTask
  extends org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask
  implements org.asciidoctor.gradle.base.slides.SlidesToExportAware
----

=== की खोज `forkOptions

निरीक्षण करते हुए.

</think>

निरीक्षण करते हुए`AbstractAsciidoctorTask`:

[source,bash]
----
javap -p -classpath asciidoctor-gradle-jvm-4.0.0-alpha.1.jar \
  org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask | grep -i "fork\|exec\|jvm"
----

पाया जाता है:

[source]
----
final org.ysb33r.grolifant.api.v4.JavaForkOptions javaForkOptions;
public void forkOptions(org.gradle.api.Action<org.ysb33r.grolifant.api.v4.JavaForkOptions>);
public static final org.asciidoctor.gradle.base.process.ProcessMode JAVA_EXEC;
----

=== JavaForkOptions की एपीआई (grolifant)

`javaLauncher`इस कार्य पर मौजूद नहीं है। वास्तविक API का`org.ysb33r.grolifant.api.v4.JavaForkOptions`दिखाता है :

[source]
----
public void executable(java.lang.Object);  (1)
public void setExecutable(java.lang.Object);
----

<1> पद्धति`executable(Object)`असाइनमेंट को बदलता है`executable = ...`जो कंपाइल नहीं होता (`val`पुन: आवंटित नहीं किया जा सकता).

=== RevealJSExtension

`revealjs { }`कार्य की एक विधि नहीं है, लेकिन एक**परियोजना विस्तार**:

[source,bash]
----
javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
  org.asciidoctor.gradle.jvm.slides.RevealJSExtension
----

इस तक पहुँचा जाता है:

[source,kotlin]
----
project.extensions.getByType<RevealJSExtension>().apply {
    version = "3.1.0"
    templateGitHub {
        setOrganisation("hakimel")
        setRepository("reveal.js")
        setTag("3.9.1")
    }
}
----

== जावा टूलचेन कॉन्फ़िगरेशन

=== JavaToolchainService की समस्या

`JavaToolchainService`यह प्रोजेक्ट एक्सटेंशन नहीं है। निम्नलिखित कॉल विफल होता है :

[source,kotlin]
----
// ERREUR : Extension of type 'JavaToolchainService' does not exist
project.extensions.getByType<JavaToolchainService>()
----

अच्छी API है`serviceOf`:

[source,kotlin]
----
import org.gradle.kotlin.dsl.support.serviceOf

project.tasks.getByName<AsciidoctorJRevealJSTask>(TASK_ASCIIDOCTOR_REVEALJS) {
    setInProcess("JAVA_EXEC")
    forkOptions {
        executable(
            project.serviceOf<JavaToolchainService>()
                .launcherFor {
                    languageVersion.set(JavaLanguageVersion.of(17))
                    vendor.set(JvmVendorSpec.ADOPTIUM)
                }
                .get()
                .executablePath
                .asFile
                .absolutePath
        )
    }
}
----

== स्वचालित डॉकर का पता लगाना

=== संदर्भ

Asciidoctor/JRuby प्लगिन को Java 17 की आवश्यकता है। Kotlin 2.0.x बिल्डSrc में Java 25 का समर्थन नहीं करता (वर्ज़न पार्सर क्रैश हो जाता है पर`"25.0.2"`Gradle डेमन को इसलिए Java 17 पर चलना चाहिए या Docker का उपयोग किया जाना चाहिए।

=== रणनीति

1. Docker उपलब्ध → कंटेनर के माध्यम से निष्पादन`eclipse-temurin:17`(डिफ़ॉल्ट व्यवहार)
2. Docker अनुपस्थित + Java 17 → स्थानीय निष्पादन
3. Docker अनुपस्थित + Java > 17 → स्पष्ट त्रुटि

[source,kotlin]
----
val isDockerAvailable = try {
    Runtime.getRuntime().exec(arrayOf("docker", "info")).waitFor() == 0
} catch (e: Exception) {
    false
}

val javaVersion = JavaVersion.current().majorVersion.toInt()

when {
    isDockerAvailable -> project.tasks.register<Exec>(TASK_ASCIIDOCTOR_REVEALJS) {
        group = GROUP_TASK_SLIDER
        description = "Slider settings and generation (via Docker)"
        dependsOn(TASK_CLEAN_SLIDES_BUILD)
        finalizedBy(TASK_DASHBOARD_SLIDES_BUILD)
        commandLine(
            "docker", "run", "--rm",
            "-v", "${project.rootDir.absolutePath}:/workspace",
            "-v", "${System.getProperty("user.home")}/.gradle:/root/.gradle",
            "-w", "/workspace",
            "eclipse-temurin:17",
            "./gradlew", TASK_ASCIIDOCTOR_REVEALJS
        )
        workingDir = project.rootDir
    }
    javaVersion == 17 -> {
        project.repositories.mavenCentral() {
            content { excludeGroup("rubygems") }
        }
        project.repositories.ivy {
            url = project.uri("https://rubygems.org/gems/")
            patternLayout { artifact("[module]-[revision].gem") }
            metadataSources { artifact() }
            content { includeGroup("rubygems") }
        }
        project.extensions.getByType<RevealJSExtension>().apply {
            version = "3.1.0"
            templateGitHub {
                setOrganisation("hakimel")
                setRepository("reveal.js")
                setTag("3.9.1")
            }
        }
        project.tasks.getByName<AsciidoctorJRevealJSTask>(TASK_ASCIIDOCTOR_REVEALJS) {
            setInProcess("JAVA_EXEC")
            forkOptions {
                executable(
                    project.serviceOf<JavaToolchainService>()
                        .launcherFor {
                            languageVersion.set(JavaLanguageVersion.of(17))
                            vendor.set(JvmVendorSpec.ADOPTIUM)
                        }
                        .get()
                        .executablePath
                        .asFile
                        .absolutePath
                )
            }
            // ... reste de la configuration
        }
    }
    else -> error(
        "Docker est requis pour exécuter $TASK_ASCIIDOCTOR_REVEALJS " +
        "avec Java $javaVersion. Installez Docker ou utilisez Java 17."
    )
}
----

== अंतिम परिणाम

=== भोक्ता बिल्डस्क्रिप्ट

[source,kotlin]
----
apply<slides.SlidesPlugin>()
----

इतना ही। प्लगिन पूरी जिम्मेदारी लेता है।

=== settings.gradle.kts

[source,kotlin]
----
pluginManagement {
    repositories {
        mavenLocal()
        gradlePluginPortal()
    }
}

plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}

@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
}

rootProject.name = "slider-gradle"
----

== जाल और समाधानों का सारांश

[cols="2,3,3"]
|===
|समस्या |कारण |समाधान

|`ruby { gems() }`Kotlin में उपलब्ध नहीं |केवल Groovy DSL एक्सटेंशन |तीन अलग‑अलग तंत्र : Ivy रेपो + Maven बहिष्करण +`asciidoctorGems` |Gradle एक की खोज कर रहा है`.jar`एक के बजाय`.gem` |`[ext]`हल करता है से`jar`डिफ़फ़ॉल्ट रूप से |Hardcoder`.gem`इवी पैटर्न में + योग्यता`@gem` |`ivy { }`में कंपाइल नहीं होता`repositories { }` |रिसीवर grolifant Kotlin DSL के साथ असंगत |सीधी कॉल`project.repositories.ivy { }` |`javaLauncher`अनसुलझा |अस्तित्वहीन गुणधर्म पर`AsciidoctorJRevealJSTask` |`setInProcess("JAVA_EXEC")`+`forkOptions { executable(...) }` |`executable = ...`कंपाइल नहीं होता |संपत्ति`val`में`JavaForkOptions`grolifant |पद्धति`executable(Object)`के स्थान पर |`JavaToolchainService`के माध्यम से नहीं मिला`extensions` |यह Gradle का एक सेवा है, एक एक्सटेंशन नहीं |`project.serviceOf<JavaToolchainService>()` |`revealjs { }`कार्य में हल नहीं |परियोजना विस्तार, कार्य की विधि नहीं |`project.extensions.getByType<RevealJSExtension>()` |बिल्ड Java 25 के साथ क्रैश होती है |Kotlin 2.0.x दो अंकों वाले Java संस्करणों को पार्स नहीं करता |स्वचालित Docker पहचान + Java 17 का फॉलबैक
|===

== जाँच की विधि : अज्ञात API को javap के साथ पढ़ना

=== सिद्धांत

जब दस्तावेज़ अनुपलब्ध या अधूरा हो, तब बाइटकोड सत्य का स्रोत होता है। `javap`यह JDK का मानक टूल है जो फ़ाइलों को डीकंपाइल करता है`.class` en signatures Java lisibles, स्रोत कोड की आवश्यकता नहीं

=== चरण 1: Gradle कैश में jar को खोजें

Gradle सभी अपनी निर्भरताओं को डाउनलोड करता है में`~/.gradle/caches/modules-2/files-2.1/`. पहला कदम वह jar खोजना है जिसमें जाँचने के लिए क्लास मौजूद है:

[source,bash]
----
find ~/.gradle/caches -name "asciidoctor-gradle-jvm-slides*.jar" 2>/dev/null
----

.परिणाम :

[source]
----
/home/user/.gradle/caches/modules-2/files-2.1/org.asciidoctor/
asciidoctor-gradle-jvm-slides/4.0.0-alpha.1/.../
asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar
----

=== चरण 2 : jar की कक्षाओं की सूची बनाएं

क्लास का निरीक्षण करने से पहले, हम जाँचते हैं कि यह jar में वास्तव में मौजूद है:

[source,bash]
----
jar tf asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar | grep -i "RevealJS\|revealjs"
----

.यह सभी उपलब्ध वर्गों को प्रकट करता है : `AsciidoctorJRevealJSTask`, `RevealJSExtension`, `RevealJSOptions`, etc.

=== चरण 3 : एक कक्षा का निरीक्षण करें

[source,bash]
----
javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
org.asciidoctor.gradle.jvm.slides.AsciidoctorJRevealJSTask
----

विकल्प`-p`सभी सदस्यों को प्रदर्शित करता है, निजी सदस्यों सहित। परिणाम तुरंत मुख्य पंक्ति दिखाता है :

[source]
----
public class AsciidoctorJRevealJSTask
extends org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask
----

=== चरण 4 : पदानुक्रम में ऊपर उठना

कार्य विस्तृत होता है`AbstractAsciidoctorTask`. इसे उसकी बारी पर निरीक्षण किया जाता है पहले उसके जार को खोजते हुए :

[source,bash]
----
find ~/.gradle/caches -name "asciidoctor-gradle-jvm-[0-9]*.jar" 2>/dev/null

javap -p -classpath asciidoctor-gradle-jvm-4.0.0-alpha.1.jar \
org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask | grep -i "fork\|exec\|jvm\|java"
----

वही पता चलता है।`forkOptions`, `JAVA_EXEC`, et `javaForkOptions` de type `org.ysb33r.grolifant.api.v4.JavaForkOptions`.

=== चरण 5: अज्ञात प्रकारों का पालन करें

`JavaForkOptions`एक अज्ञात गrolifant कक्षा है। हम इसके jar को खोजते हैं :

[source,bash]
----
find ~/.gradle/caches -name "grolifant*.jar" 2>/dev/null
----

फिर हम इसकी जाँच करते हैं:

[source,bash]
----
javap -p -classpath grolifant40-legacy-api-2.0.0-alpha.6.jar \
org.ysb33r.grolifant.api.v4.JavaForkOptions
----

वहाँ इसे पाया जाता है`executable(java.lang.Object)`— बुलाने की सही विधि, के विपरीत`executable = ...`जो संकलित नहीं होता क्योंकि यह एक संपत्ति है`val`.

=== चरण 6: परियोजना एक्सटेंशन की जाँच करें

के लिए`revealjs { }`, प्रश्न यह था: क्या यह कार्य की एक विधि है या प्रोजेक्ट का एक विस्तार? निरीक्षण का`AsciidoctorJRevealJSTask` कोई भी तरीका नहीं दिखाता`revealjs`. फिर निरीक्षण किया जाता है`RevealJSExtension`:

[source,bash]
----
javap -p -classpath asciidoctor-gradle-jvm-slides-4.0.0-alpha.1.jar \
org.asciidoctor.gradle.jvm.slides.RevealJSExtension | head -5
----

[source]
----
public class RevealJSExtension implements groovy.lang.GroovyObject {
public static final java.lang.String NAME;
----

की मौजूदगी`NAME`यह पुष्टि करता है कि यह एक पंजीकृत एक्सटेंशन परियोजना पर है, के माध्यम से सुलभ`project.extensions.getByType<RevealJSExtension>()`.

=== विधि का सारांश

[cols="1,3"]
|===
|चरण |क्रिया

|1 |`find ~/.gradle/caches -name "*.jar"`— जार को खोजें |2 |`jar tf jar.jar \| grep NomClasse`— जाँचना कि कक्षा मौजूद है |3 |`javap -p -classpath jar.jar NomCompletClasse`— कक्षा का निरीक्षण करें |4 |पहचानकर्ता`extends`और हिरार्की में चढ़ना |5 |अज्ञात प्रकारों को अपने जारों में ट्रैक करें |6 |खोजें`NAME`एक प्रोजेक्ट एक्सटेंशन की पहचान करने के लिए
|===

यह विधि किसी भी Gradle प्लगइन पर लागू होती है जिसका API दस्तावेज़ीकृत नहीं है या जिसका अल्फा संस्करण अब मौजूदा दस्तावेज़ से मेल नहीं खाता।

== अगला कदम

यह buildSrc प्लगिन को Gradle Plugin Portal या Maven Local पर प्रकाशित किए गए एक स्वतंत्र प्रोजेक्ट में निकाला जाएगा। उपयोग करने वाला buildscript तब : बन जाएगा।

[source,kotlin]
----
plugins { id("slides") version "1.0.0" }
----

Et `settings.gradle.kts`इसे उसके न्यूनतम स्तर तक घटा दिया जाएगा बिना किसी संदर्भ के`foojay-resolver-convention`, JDK का प्रावधान प्लगिन द्वारा स्वयं प्रबंधित किया जाता है या यह एक आवश्यक शर्त के रूप में दस्तावेज़ीकृत किया जाता है।

संबंधित लेख