11/*
2- * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
2+ * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
3636import org .gradle .language .base .plugins .LifecycleBasePlugin ;
3737import org .gradle .plugins .ide .idea .model .IdeaModel ;
3838import org .gradle .util .GradleVersion ;
39+ import org .jspecify .annotations .Nullable ;
3940import org .pkl .cli .CliEvaluatorOptions ;
4041import org .pkl .core .ImportGraph ;
4142import org .pkl .core .OutputFormat ;
4243import org .pkl .core .util .IoUtils ;
43- import org .pkl .core .util .LateInit ;
44- import org .pkl .core .util .Nullable ;
4544import org .pkl .gradle .spec .AnalyzeImportsSpec ;
4645import org .pkl .gradle .spec .BasePklSpec ;
4746import org .pkl .gradle .spec .CodeGenSpec ;
@@ -71,21 +70,26 @@ public class PklPlugin implements Plugin<Project> {
7170
7271 private static final String MIN_GRADLE_VERSION = "8.2" ;
7372
74- @ LateInit private Project project ;
73+ private @ Nullable Project __project ;
7574
7675 @ Override
7776 public void apply (Project project ) {
78- this . project = project ;
77+ __project = project ;
7978
8079 if (GradleVersion .current ().compareTo (GradleVersion .version (MIN_GRADLE_VERSION )) < 0 ) {
8180 throw new GradleException (
8281 String .format ("Plugin `org.pkl` requires Gradle %s or higher." , MIN_GRADLE_VERSION ));
8382 }
8483
85- var extension = project .getExtensions ().create ("pkl" , PklExtension .class );
84+ var extension = project () .getExtensions ().create ("pkl" , PklExtension .class );
8685 configureExtension (extension );
8786 }
8887
88+ private Project project () {
89+ assert __project != null ;
90+ return __project ;
91+ }
92+
8993 private void configureExtension (PklExtension extension ) {
9094 configureEvalTasks (extension .getEvaluators ());
9195 configureJavaCodeGenTasks (extension .getJavaCodeGenerators ());
@@ -102,7 +106,7 @@ private void configureProjectPackageTasks(NamedDomainObjectContainer<ProjectPack
102106 spec -> {
103107 configureBaseSpec (spec );
104108 spec .getOutputPath ()
105- .convention (project .getLayout ().getBuildDirectory ().dir ("generated/pkl/packages" ));
109+ .convention (project () .getLayout ().getBuildDirectory ().dir ("generated/pkl/packages" ));
106110 spec .getOverwrite ().convention (false );
107111 var packageTask = createTask (ProjectPackageTask .class , spec );
108112 packageTask .configure (
@@ -113,12 +117,12 @@ private void configureProjectPackageTasks(NamedDomainObjectContainer<ProjectPack
113117 task .getJunitReportsDir ().set (spec .getJunitReportsDir ());
114118 task .getOverwrite ().set (spec .getOverwrite ());
115119 });
116- project
120+ project ()
117121 .getPluginManager ()
118122 .withPlugin (
119123 "base" ,
120124 appliedPlugin ->
121- project
125+ project ()
122126 .getTasks ()
123127 .named (
124128 LifecycleBasePlugin .BUILD_TASK_NAME ,
@@ -157,7 +161,7 @@ private void configureEvalTasks(NamedDomainObjectContainer<EvalSpec> specs) {
157161 configureBaseSpec (spec );
158162 spec .getOutputFile ()
159163 .convention (
160- project
164+ project ()
161165 .getLayout ()
162166 .getProjectDirectory ()
163167 // %{moduleDir} is resolved relatively to the working directory,
@@ -194,11 +198,12 @@ private void configureJavaCodeGenTasks(NamedDomainObjectContainer<JavaCodeGenSpe
194198 // constructor parameters annotations by setting this property to `null`.
195199 spec .getParamsAnnotation ()
196200 .set (
197- project .provider (
198- () ->
199- spec .getGenerateSpringBootConfig ().get ()
200- ? null
201- : "org.pkl.config.java.mapper.Named" ));
201+ project ()
202+ .provider (
203+ () ->
204+ spec .getGenerateSpringBootConfig ().get ()
205+ ? null
206+ : "org.pkl.config.java.mapper.Named" ));
202207
203208 createModulesTask (JavaCodeGenTask .class , spec )
204209 .configure (
@@ -211,14 +216,15 @@ private void configureJavaCodeGenTasks(NamedDomainObjectContainer<JavaCodeGenSpe
211216 });
212217 });
213218
214- project .afterEvaluate (
215- prj ->
216- specs .all (
217- spec -> {
218- configureIdeaModule (spec );
219- configureCodeGenSpecSourceDirectories (
220- spec , "java" , s -> Optional .of (s .getJava ()));
221- }));
219+ project ()
220+ .afterEvaluate (
221+ prj ->
222+ specs .all (
223+ spec -> {
224+ configureIdeaModule (spec );
225+ configureCodeGenSpecSourceDirectories (
226+ spec , "java" , s -> Optional .of (s .getJava ()));
227+ }));
222228 }
223229
224230 private void configureKotlinCodeGenTasks (NamedDomainObjectContainer <KotlinCodeGenSpec > specs ) {
@@ -237,14 +243,15 @@ private void configureKotlinCodeGenTasks(NamedDomainObjectContainer<KotlinCodeGe
237243 });
238244 });
239245
240- project .afterEvaluate (
241- prj ->
242- specs .all (
243- spec -> {
244- configureIdeaModule (spec );
245- configureCodeGenSpecSourceDirectories (
246- spec , "kotlin" , this ::getKotlinSourceDirectorySet );
247- }));
246+ project ()
247+ .afterEvaluate (
248+ prj ->
249+ specs .all (
250+ spec -> {
251+ configureIdeaModule (spec );
252+ configureCodeGenSpecSourceDirectories (
253+ spec , "kotlin" , this ::getKotlinSourceDirectorySet );
254+ }));
248255 }
249256
250257 private void configurePkldocTasks (NamedDomainObjectContainer <PkldocSpec > specs ) {
@@ -254,7 +261,7 @@ private void configurePkldocTasks(NamedDomainObjectContainer<PkldocSpec> specs)
254261
255262 spec .getOutputDir ()
256263 .convention (
257- project
264+ project ()
258265 .getLayout ()
259266 .getBuildDirectory ()
260267 .map (it -> it .dir ("pkldoc" ).dir (spec .getName ())));
@@ -284,12 +291,12 @@ private void configureTestTasks(NamedDomainObjectContainer<TestSpec> specs) {
284291 task .getOverwrite ().set (spec .getOverwrite ());
285292 });
286293
287- project
294+ project ()
288295 .getPluginManager ()
289296 .withPlugin (
290297 "base" ,
291298 appliedPlugin ->
292- project
299+ project ()
293300 .getTasks ()
294301 .named (
295302 LifecycleBasePlugin .CHECK_TASK_NAME ,
@@ -306,7 +313,7 @@ private void configureBaseSpec(BasePklSpec spec) {
306313 spec .getAllowedResources ()
307314 .convention (List .of ("env:" , "prop:" , "file:" , "modulepath:" , "https:" , "package:" ));
308315
309- spec .getEvalRootDir ().convention (project .getRootProject ().getLayout ().getProjectDirectory ());
316+ spec .getEvalRootDir ().convention (project () .getRootProject ().getLayout ().getProjectDirectory ());
310317
311318 // Defaulting to OS env vars is bad for reproducibility and cachability.
312319 // Hence, this spec defaults to empty env vars, which is consistent with other Gradle tasks
@@ -326,18 +333,19 @@ private void configureBaseSpec(BasePklSpec spec) {
326333 private void configureCodeGenSpec (CodeGenSpec spec ) {
327334 spec .getOutputDir ()
328335 .convention (
329- project
336+ project ()
330337 .getLayout ()
331338 .getBuildDirectory ()
332339 .map (it -> it .dir ("generated" ).dir ("pkl" ).dir (spec .getName ())));
333340
334341 spec .getSourceSet ()
335342 .convention (
336- project
343+ project ()
337344 .getProviders ()
338345 .provider (
339346 () -> {
340- var sourceSets = project .getExtensions ().findByType (SourceSetContainer .class );
347+ var sourceSets =
348+ project ().getExtensions ().findByType (SourceSetContainer .class );
341349 if (sourceSets == null ) {
342350 return null ;
343351 }
@@ -371,7 +379,7 @@ private void configureCodeGenSpecModulePath(CodeGenSpec spec) {
371379 // Refer to configureCodeGenSpecSourceDirectories for logic which links the codegen task
372380 // to sourceSet.getResources().getSourceDirectories().
373381
374- var modulePath = project .files ();
382+ var modulePath = project () .files ();
375383 modulePath
376384 .from (getResourceSourceDirectoriesExceptSpecOutput (spec ))
377385 // This technically breaks the dependency on compile classpath builder tasks,
@@ -411,14 +419,14 @@ private void configureCodeGenSpecSourceDirectories(
411419 String languageName ,
412420 Function <? super SourceSet , ? extends Optional <SourceDirectorySet >>
413421 extractSourceDirectorySet ) {
414- var task = project .getTasks ().named (spec .getName (), CodeGenTask .class );
422+ var task = project () .getTasks ().named (spec .getName (), CodeGenTask .class );
415423 var sourceSet = spec .getSourceSet ().get ();
416424 extractSourceDirectorySet
417425 .apply (sourceSet )
418426 .ifPresentOrElse (
419427 dirSet -> dirSet .srcDir (task .flatMap (t -> t .getOutputDir ().dir (languageName ))),
420428 () ->
421- project
429+ project ()
422430 .getLogger ()
423431 .debug (
424432 "Source directory set for language {} is not available, "
@@ -431,12 +439,12 @@ private void configureCodeGenSpecSourceDirectories(
431439 // Must be called from Project.afterEvaluate() only, because this method depends
432440 // on user-provided configuration not accessible with lazy configuration.
433441 private void configureIdeaModule (CodeGenSpec spec ) {
434- project
442+ project ()
435443 .getPluginManager ()
436444 .withPlugin (
437445 "idea" ,
438446 plugin -> {
439- var module = project .getExtensions ().getByType (IdeaModel .class ).getModule ();
447+ var module = project () .getExtensions ().getByType (IdeaModel .class ).getModule ();
440448 var outputDir = spec .getOutputDir ().get ().getAsFile ();
441449 module .getGeneratedSourceDirs ().add (outputDir );
442450 if (spec .getSourceSet ().get ().getName ().toLowerCase ().contains ("test" )) {
@@ -521,11 +529,11 @@ private <T extends ModulesTask, S extends ModulesSpec> void configureModulesTask
521529
522530 private TaskProvider <AnalyzeImportsTask > createAnalyzeImportsTask (ModulesSpec spec ) {
523531 var outputFile =
524- project
532+ project ()
525533 .getLayout ()
526534 .getBuildDirectory ()
527535 .file ("pkl-gradle/imports/" + spec .getName () + ".json" );
528- return project
536+ return project ()
529537 .getTasks ()
530538 .register (
531539 spec .getName () + "GatherImports" ,
@@ -567,7 +575,7 @@ private TaskProvider<AnalyzeImportsTask> createAnalyzeImportsTask(ModulesSpec sp
567575 private <T extends ModulesTask > TaskProvider <T > createModulesTask (
568576 Class <T > taskClass , ModulesSpec spec ) {
569577 var analyzeImportsTask = createAnalyzeImportsTask (spec );
570- return project
578+ return project ()
571579 .getTasks ()
572580 .register (
573581 spec .getName (),
@@ -576,7 +584,7 @@ private <T extends ModulesTask> TaskProvider<T> createModulesTask(
576584 }
577585
578586 private <T extends BasePklTask > TaskProvider <T > createTask (Class <T > taskClass , BasePklSpec spec ) {
579- return project
587+ return project ()
580588 .getTasks ()
581589 .register (spec .getName (), taskClass , task -> configureBaseTask (task , spec ));
582590 }
0 commit comments