diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4a5492f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig is awesome: https://editorconfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true + +# 4 space indentation +[*.java] +indent_style = space +indent_size = 2 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 34b1256..ea2eccc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,15 @@ +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf + +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary + .gitattributes export-ignore .gitignore export-ignore circle.yml export-ignore diff --git a/README.md b/README.md index fa3f9aa..cfb3a86 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,12 @@ A Gradle plugin, similar to the groovy and scala plugins for Gradle. -Specifically, this adds compileGosu and compileTestGosu tasks. These tasks are dependent on the compileJava and compileTestJava tasks, respectively. +Specifically, this adds `compileGosu` and `compileTestGosu` tasks. These tasks are dependent on the `compileJava` and `compileTestJava` tasks, respectively. A `gosudoc` task is also created. Java 8 is required, as is Gosu version 1.13.9+ or 1.14.2+. Gosu 1.14 and 1.14.1 are not supported. +As of this release, the plugin supports Gradle's [Configuration Cache](https://docs.gradle.org/current/userguide/configuration_cache.html). However, **the plugin now requires Gradle 8.8 or higher**. + Build status: [![Circle CI](https://circleci.com/gh/gosu-lang/gradle-gosu-plugin/tree/main.svg?style=svg)](https://circleci.com/gh/gosu-lang/gradle-gosu-plugin/tree/main) ## Why would I use this? @@ -36,6 +38,27 @@ The latest release version, and instructions to apply it, is available here: htt It is now necessary to create a single compile-time dependency on the gosu-core-api JAR. Runtime and other dependencies are automatically inferred and applied by the plugin. +Example minimal project configuration (groovy build script): +```groovy +plugins { + id 'org.gosu-lang.gosu' version '8.1.3' +} + +java { + toolchain { + it.languageVersion = JavaLanguageVersion.of 11 + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.gosu-lang.gosu:gosu-core-api:1.17.8' +} +``` + Additionally, snapshots are available from https://oss.sonatype.org/content/repositories/snapshots/org/gosu-lang/gosu/gradle-gosu-plugin/ ## Configurable Options diff --git a/build.gradle b/build.gradle index b55741a..2136727 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,6 @@ import org.gosulang.gradle.build.VersionWriterTask +import org.gradle.api.tasks.testing.logging.TestLogEvent + import java.nio.charset.StandardCharsets plugins { @@ -92,7 +94,7 @@ dependencies { test { useJUnitPlatform() testLogging { - events 'passed', 'failed', 'skipped' + events TestLogEvent.PASSED, TestLogEvent.FAILED, TestLogEvent.SKIPPED } environment('JAVA_TOOL_OPTIONS', '-Duser.language=en') } @@ -170,4 +172,4 @@ publishing { } } } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 5a0acbb..8756a49 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group=org.gosu-lang.gosu name=gradle-gosu-plugin version=8.1.3-SNAPSHOT -gradleVersion=8.6 +gradleVersion=8.8 org.gradle.caching=false org.gradle.daemon=false org.gradle.jvmargs=-Xms1g -Xmx2g -Dfile.encoding=UTF-8 @@ -10,7 +10,7 @@ org.gradle.parallel=false org.gradle.workers.max=1 gosuVersion=1.17.8 -testedVersions=8.2,8.10.1 +testedVersions=8.10.1 # Gradle plugins gradlePublishPluginVersion=1.3.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd49..e644113 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2ea3535..6f7a6eb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4..b740cf1 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/gradlew.bat b/gradlew.bat index 7101f8e..25da30d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/org/gosulang/gradle/GosuBasePlugin.java b/src/main/java/org/gosulang/gradle/GosuBasePlugin.java index 65e56c6..9e62868 100644 --- a/src/main/java/org/gosulang/gradle/GosuBasePlugin.java +++ b/src/main/java/org/gosulang/gradle/GosuBasePlugin.java @@ -1,18 +1,18 @@ package org.gosulang.gradle; -import org.codehaus.groovy.runtime.InvokerHelper; import org.gosulang.gradle.tasks.DefaultGosuSourceSet; import org.gosulang.gradle.tasks.GosuRuntime; -import org.gosulang.gradle.tasks.GosuSourceSet; +import org.gosulang.gradle.tasks.GosuSourceDirectorySet; import org.gosulang.gradle.tasks.compile.GosuCompile; import org.gosulang.gradle.tasks.gosudoc.GosuDoc; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.file.FileCollection; import org.gradle.api.file.SourceDirectorySet; +import org.gradle.api.internal.plugins.DslObject; import org.gradle.api.internal.tasks.DefaultSourceSetOutput; import org.gradle.api.model.ObjectFactory; -import org.gradle.api.plugins.Convention; import org.gradle.api.plugins.JavaBasePlugin; import org.gradle.api.reporting.ReportingExtension; import org.gradle.api.tasks.SourceSet; @@ -21,84 +21,92 @@ import org.gradle.internal.Cast; import javax.inject.Inject; -import java.io.File; +import java.util.concurrent.Callable; import static org.gosulang.gradle.tasks.Util.javaPluginExtension; +import static org.gradle.api.internal.lambdas.SerializableLambdas.spec; -public class GosuBasePlugin implements Plugin { +public abstract class GosuBasePlugin implements Plugin { public static final String GOSU_RUNTIME_EXTENSION_NAME = "gosuRuntime"; - private final ObjectFactory _objectFactory; - - private Project _project; - private GosuRuntime _gosuRuntime; - @Inject - GosuBasePlugin(ObjectFactory objectFactory){ - _objectFactory = objectFactory; - } + public abstract ObjectFactory getObjectFactory(); @Override public void apply(Project project) { - _project = project; - _project.getPluginManager().apply(JavaBasePlugin.class); + project.getPluginManager().apply(JavaBasePlugin.class); - configureGosuRuntimeExtension(); - configureCompileDefaults(); - configureSourceSetDefaults(); - configureGosuDoc(); - } - - private void configureGosuRuntimeExtension() { - _gosuRuntime = _project.getExtensions().create(GOSU_RUNTIME_EXTENSION_NAME, GosuRuntime.class); + GosuRuntime gosuRuntime = project.getExtensions().create(GOSU_RUNTIME_EXTENSION_NAME, GosuRuntime.class); + configureCompileDefaults(project, gosuRuntime); + configureSourceSetDefaults(project); + configureGosuDoc(project, gosuRuntime); } /** * Sets the gosuClasspath property for all GosuCompile tasks: compileGosu and compileTestGosu */ - private void configureCompileDefaults() { - _project.getTasks().withType(GosuCompile.class, gosuCompile -> - gosuCompile.getConventionMapping().map("gosuClasspath", () -> _gosuRuntime.inferGosuClasspath(gosuCompile.getClasspath()))); + private static void configureCompileDefaults(Project project, GosuRuntime gosuRuntime) { + project.getTasks().withType(GosuCompile.class).configureEach(gosuCompile -> { + gosuCompile.getGosuClasspath().convention((Callable) () -> gosuRuntime.inferGosuClasspath(gosuCompile.getClasspath())); + }); } - private void configureSourceSetDefaults() { - javaPluginExtension(_project).getSourceSets().all(sourceSet -> { - DefaultGosuSourceSet gosuSourceSet = new DefaultGosuSourceSet(sourceSet.getName(), _objectFactory); - //have to be revisit to avoid using the covention here - Convention sourceSetConvention = (Convention) InvokerHelper.getProperty(sourceSet, "convention"); - sourceSetConvention.getPlugins().put("gosu", gosuSourceSet); - // sourceSet.getExtensions().add(SourceDirectorySet.class, "gosu", gosuSourceSet.getGosu()); //alternative but it's not working - gosuSourceSet.getGosu().srcDir("src/" + sourceSet.getName() + "/gosu"); - sourceSet.getResources().getFilter().exclude(element -> gosuSourceSet.getGosu().contains(element.getFile())); - sourceSet.getAllSource().source(gosuSourceSet.getGosu()); - configureGosuCompile(sourceSet, gosuSourceSet); + private void configureSourceSetDefaults(Project project) { + javaPluginExtension(project).getSourceSets().all(sourceSet -> { + + GosuSourceDirectorySet gosuSource = getGosuSourceDirectorySet(sourceSet); + sourceSet.getExtensions().add(GosuSourceDirectorySet.class, "gosu", gosuSource); + gosuSource.srcDir("src/" + sourceSet.getName() + "/gosu"); + + // Explicitly capture only a FileCollection in the lambda below for compatibility with configuration-cache. + final FileCollection gosuSourceFiles = gosuSource; + sourceSet.getResources().getFilter().exclude( + spec(element -> gosuSourceFiles.contains(element.getFile())) + ); + sourceSet.getAllSource().source(gosuSource); + configureGosuCompile(project, sourceSet, gosuSource); }); } + private GosuSourceDirectorySet getGosuSourceDirectorySet(SourceSet sourceSet) { + final DefaultGosuSourceSet gosuSourceSet = getObjectFactory().newInstance(DefaultGosuSourceSet.class, sourceSet.getName()); + + // TODO remove in Gradle 9.0? + new DslObject(sourceSet).getConvention().getPlugins().put("gosu", gosuSourceSet); + + return gosuSourceSet.getGosu(); + } + /** * Create and configure default compileGosu and compileTestGosu tasks * Gradle 4.0+: call local equivalent of o.g.a.p.i.SourceSetUtil.configureForSourceSet(sourceSet, gosuSourceSet.getGosu(), gosuCompile, _project) * Gradle 2.x, 3.x: call javaPlugin.configureForSourceSet(sourceSet, gosuCompile); */ - private void configureGosuCompile(SourceSet sourceSet, GosuSourceSet gosuSourceSet) { + private void configureGosuCompile(Project project, SourceSet sourceSet, GosuSourceDirectorySet gosuSourceSet) { String compileTaskName = sourceSet.getCompileTaskName("gosu"); - TaskProvider gosuCompile = _project.getTasks().register(compileTaskName, GosuCompile.class); - configureForSourceSet(sourceSet, gosuSourceSet.getGosu(), gosuCompile, _project); + TaskProvider gosuCompile = project.getTasks().register(compileTaskName, GosuCompile.class); + configureForSourceSet(sourceSet, gosuSourceSet, gosuCompile, project); gosuCompile.configure(t -> t.dependsOn(sourceSet.getCompileJavaTaskName())); - gosuCompile.configure(t -> t.setSource((Object) gosuSourceSet.getGosu())); // Gradle 4.0 overloads setSource; must upcast to Object for backwards compatibility - _project.getTasks().getByName(sourceSet.getClassesTaskName()).dependsOn(compileTaskName); + gosuCompile.configure(t -> t.setSource((Object) gosuSourceSet)); // Gradle 4.0 overloads setSource; must upcast to Object for backwards compatibility + gosuCompile.configure(t -> { + t.getProjectName().set(t.getProject().getName()); + t.getProjectDir().set(t.getProject().getLayout().getProjectDirectory()); + }); + project.getTasks().named(sourceSet.getClassesTaskName()).configure(task -> task.dependsOn(compileTaskName)); } - private void configureGosuDoc() { - _project.getTasks().withType(GosuDoc.class, gosudoc -> { - gosudoc.getConventionMapping().map("gosuClasspath", () -> _gosuRuntime.inferGosuClasspath(gosudoc.getClasspath())); - gosudoc.getConventionMapping().map("destinationDir", () -> new File(javaPluginExtension(_project).getDocsDir().get().getAsFile(), "gosudoc")); - gosudoc.getConventionMapping().map("title", () -> _project.getExtensions().getByType(ReportingExtension.class).getApiDocTitle()); - //gosudoc.getConventionMapping().map("windowTitle", (Callable) () -> _project.getExtensions().getByType(ReportingExtension.class).getApiDocTitle()); + private static void configureGosuDoc(Project project, GosuRuntime gosuRuntime) { + project.getTasks().withType(GosuDoc.class, gosudoc -> { + gosudoc.getProjectName().set(project.getName()); + gosudoc.getProjectDir().set(project.getLayout().getProjectDirectory()); + gosudoc.getBuildDir().set(project.getLayout().getBuildDirectory()); + gosudoc.getGosuClasspath().convention((Callable) () -> gosuRuntime.inferGosuClasspath(gosudoc.getClasspath())); + gosudoc.getDestinationDir().convention(javaPluginExtension(project).getDocsDir().dir("gosudoc")); + gosudoc.getTitle().convention(project.getExtensions().getByType(ReportingExtension.class).getApiDocTitle()); }); } - private static void configureForSourceSet(final SourceSet sourceSet, final SourceDirectorySet sourceDirectorySet, TaskProvider compile, final Project target) { + private static void configureForSourceSet(final SourceSet sourceSet, final GosuSourceDirectorySet sourceDirectorySet, TaskProvider compile, final Project target) { compile.configure(t -> { t.setDescription("Compiles the " + sourceDirectorySet.getDisplayName() + "."); t.setSource(sourceSet.getJava()); diff --git a/src/main/java/org/gosulang/gradle/GosuPlugin.java b/src/main/java/org/gosulang/gradle/GosuPlugin.java index a9fb857..a5a2bee 100644 --- a/src/main/java/org/gosulang/gradle/GosuPlugin.java +++ b/src/main/java/org/gosulang/gradle/GosuPlugin.java @@ -1,20 +1,21 @@ package org.gosulang.gradle; -import org.codehaus.groovy.runtime.InvokerHelper; import org.gosulang.gradle.tasks.GosuRuntime; -import org.gosulang.gradle.tasks.GosuSourceSet; +import org.gosulang.gradle.tasks.GosuSourceDirectorySet; import org.gosulang.gradle.tasks.gosudoc.GosuDoc; import org.gradle.api.Plugin; import org.gradle.api.Project; -import org.gradle.api.plugins.Convention; +import org.gradle.api.file.SourceDirectorySet; import org.gradle.api.plugins.JavaBasePlugin; import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.internal.JavaPluginHelper; +import org.gradle.api.plugins.jvm.internal.JvmFeatureInternal; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskProvider; import static org.gosulang.gradle.tasks.Util.javaPluginExtension; -public class GosuPlugin implements Plugin { +public abstract class GosuPlugin implements Plugin { @SuppressWarnings("WeakerAccess") public static final String GOSUDOC_TASK_NAME = "gosudoc"; @@ -30,34 +31,30 @@ public void apply(Project project) { /** * Ensures that the runtime dependency on gosu-core is included the testRuntime's classpath */ - private void refreshTestRuntimeClasspath( final Project project ) { - + private void refreshTestRuntimeClasspath(final Project project) { GosuRuntime gosuRuntime = project.getExtensions().getByType(GosuRuntime.class); SourceSet main = javaPluginExtension(project).getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); SourceSet test = javaPluginExtension(project).getSourceSets().getByName(SourceSet.TEST_SOURCE_SET_NAME); test.setRuntimeClasspath(project.files( - test.getOutput(), - main.getOutput(), - project.getConfigurations().getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME), - gosuRuntime.inferGosuClasspath(project.getConfigurations().getByName(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME)))); + test.getOutput(), + main.getOutput(), + project.getConfigurations().getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME), + gosuRuntime.inferGosuClasspath(project.getConfigurations().getByName(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME)))); } - private void configureGosuDoc( final Project project ) { - SourceSet mainSourceSet = javaPluginExtension(project).getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); - Convention sourceSetConvention = (Convention) InvokerHelper.getProperty(mainSourceSet, "convention"); - GosuSourceSet gosuSourceSet = sourceSetConvention.getPlugin(GosuSourceSet.class); - - TaskProvider gosuDoc = project.getTasks().register(GOSUDOC_TASK_NAME, GosuDoc.class, t -> { - t.setDescription("Generates Gosudoc API documentation for the main source code."); - t.setGroup(JavaBasePlugin.DOCUMENTATION_GROUP); - // JvmFeatureInternal mainFeature = JavaPluginHelper.getJavaComponent(project).getMainFeature();//alternative approach but needs to be tested - // gosuDoc.setClasspath(mainFeature.getSourceSet().getOutput().plus(mainFeature.getSourceSet().getCompileClasspath())); - t.setClasspath(mainSourceSet.getOutput().plus(mainSourceSet.getCompileClasspath())); - t.setSource(gosuSourceSet.getGosu()); + private void configureGosuDoc(final Project project) { + TaskProvider gosuDoc = project.getTasks().register(GOSUDOC_TASK_NAME, GosuDoc.class, t -> { + t.setDescription("Generates Gosudoc API documentation for the main source code."); + t.setGroup(JavaBasePlugin.DOCUMENTATION_GROUP); + + JvmFeatureInternal mainFeature = JavaPluginHelper.getJavaComponent(project).getMainFeature(); //alternative approach but needs to be tested + t.getClasspath().from(mainFeature.getSourceSet().getOutput().plus(mainFeature.getSourceSet().getCompileClasspath())); + + SourceDirectorySet gosuSourceSet = mainFeature.getSourceSet().getExtensions().getByType(GosuSourceDirectorySet.class); + t.setSource(gosuSourceSet); }); } - } diff --git a/src/main/java/org/gosulang/gradle/tasks/DefaultGosuSourceDirectorySet.java b/src/main/java/org/gosulang/gradle/tasks/DefaultGosuSourceDirectorySet.java new file mode 100644 index 0000000..fe1a125 --- /dev/null +++ b/src/main/java/org/gosulang/gradle/tasks/DefaultGosuSourceDirectorySet.java @@ -0,0 +1,15 @@ +package org.gosulang.gradle.tasks; + +import org.gradle.api.file.SourceDirectorySet; +import org.gradle.api.internal.file.DefaultSourceDirectorySet; +import org.gradle.api.internal.tasks.TaskDependencyFactory; + +import javax.inject.Inject; + +public abstract class DefaultGosuSourceDirectorySet extends DefaultSourceDirectorySet implements GosuSourceDirectorySet { + + @Inject + public DefaultGosuSourceDirectorySet(SourceDirectorySet sourceDirectorySet, TaskDependencyFactory taskDependencyFactory) { + super(sourceDirectorySet, taskDependencyFactory); + } +} diff --git a/src/main/java/org/gosulang/gradle/tasks/DefaultGosuSourceSet.java b/src/main/java/org/gosulang/gradle/tasks/DefaultGosuSourceSet.java index baf8f0e..314eafa 100644 --- a/src/main/java/org/gosulang/gradle/tasks/DefaultGosuSourceSet.java +++ b/src/main/java/org/gosulang/gradle/tasks/DefaultGosuSourceSet.java @@ -1,36 +1,41 @@ package org.gosulang.gradle.tasks; -import groovy.lang.Closure; import org.gradle.api.Action; import org.gradle.api.file.SourceDirectorySet; import org.gradle.api.model.ObjectFactory; -import org.gradle.api.tasks.SourceSet; -import org.gradle.util.ConfigureUtil; +import org.gradle.api.reflect.HasPublicType; +import org.gradle.api.reflect.TypeOf; import org.gradle.util.GUtil; +import javax.inject.Inject; import java.util.Arrays; import java.util.List; -public class DefaultGosuSourceSet implements GosuSourceSet { +import static org.gradle.api.reflect.TypeOf.typeOf; - private final SourceDirectorySet _gosu; +@SuppressWarnings("DeprecatedIsStillUsed") +@Deprecated +public abstract class DefaultGosuSourceSet implements GosuSourceSet, HasPublicType { + + private final GosuSourceDirectorySet _gosu; private final SourceDirectorySet _allGosu; private static final List _gosuAndJavaExtensions = Arrays.asList("**/*.java", "**/*.gs", "**/*.gsx", "**/*.gst", "**/*.gsp"); private static final List _gosuExtensionsOnly = _gosuAndJavaExtensions.subList(1, _gosuAndJavaExtensions.size()); private final String name; - private final String baseName; private final String displayName; - public DefaultGosuSourceSet( String name, ObjectFactory objectFacotry ) { + @Inject + public abstract ObjectFactory getObjectFactory(); + @Inject + public DefaultGosuSourceSet(String name) { this.name = name; - this.baseName = name.equals(SourceSet.MAIN_SOURCE_SET_NAME) ? "" : name.toUpperCase(); displayName = GUtil.toWords(this.name); - _gosu = objectFacotry.sourceDirectorySet("gosu", displayName + " Gosu source"); + _gosu = getObjectFactory().newInstance(DefaultGosuSourceDirectorySet.class, getObjectFactory().sourceDirectorySet("gosu", displayName + " Gosu source")); _gosu.getFilter().include(_gosuAndJavaExtensions); - _allGosu = objectFacotry.sourceDirectorySet("gosu", displayName + " Gosu source"); + _allGosu = getObjectFactory().sourceDirectorySet("gosu", displayName + " Gosu source"); _allGosu.getFilter().include(_gosuExtensionsOnly); _allGosu.source(_gosu); } @@ -49,18 +54,12 @@ public String getDisplayName() { } @Override - public SourceDirectorySet getGosu() { + public GosuSourceDirectorySet getGosu() { return _gosu; } @Override - public GosuSourceSet gosu( Closure configureClosure ) { - ConfigureUtil.configure(configureClosure, getGosu()); - return this; - } - - @Override - public GosuSourceSet gosu( Action configureAction) { + public GosuSourceSet gosu(Action configureAction) { configureAction.execute(getGosu()); return this; } @@ -69,4 +68,9 @@ public GosuSourceSet gosu( Action configureAction) { public SourceDirectorySet getAllGosu() { return _allGosu; } + + @Override + public TypeOf getPublicType() { + return typeOf(org.gosulang.gradle.tasks.GosuSourceSet.class); + } } diff --git a/src/main/java/org/gosulang/gradle/tasks/GosuRuntime.java b/src/main/java/org/gosulang/gradle/tasks/GosuRuntime.java index d4a7fdb..021905d 100644 --- a/src/main/java/org/gosulang/gradle/tasks/GosuRuntime.java +++ b/src/main/java/org/gosulang/gradle/tasks/GosuRuntime.java @@ -1,31 +1,35 @@ package org.gosulang.gradle.tasks; -import groovy.lang.Closure; import org.gradle.api.Buildable; import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; +import org.gradle.api.internal.file.collections.FailingFileCollection; +import org.gradle.api.internal.file.collections.LazilyInitializedFileCollection; +import org.gradle.api.internal.project.ProjectInternal; +import org.gradle.api.internal.tasks.TaskDependencyResolveContext; +import org.gradle.api.plugins.jvm.internal.JvmPluginServices; import org.gradle.util.VersionNumber; import javax.annotation.Nullable; import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Callable; import java.util.regex.Matcher; import java.util.regex.Pattern; -public class GosuRuntime { +public abstract class GosuRuntime { private static final Pattern GOSU_JAR_PATTERN = Pattern.compile("gosu-(\\w.*?)-(\\d.*).jar"); private static final String LF = System.lineSeparator(); private final Project _project; + private final JvmPluginServices _jvmPluginServices; public GosuRuntime(Project project) { _project = project; + _jvmPluginServices = ((ProjectInternal) project).getServices().get(JvmPluginServices.class); } /** @@ -37,64 +41,66 @@ public GosuRuntime(Project project) { * @param classpath a classpath containing a 'gosu-core-api' Jar * @return a classpath containing a corresponding 'gosu-doc' Jar and its dependencies */ - public Closure inferGosuClasspath(final Iterable classpath) { - return new Closure(this, this) { - private FileCollection resolved; - - public FileCollection doCall(Object ignore) { - ConfigurableFileCollection fileCollection = _project.files((Callable) () -> { - if (resolved == null) { - resolved = doInfer(classpath); - } - return resolved; - }); - if (classpath instanceof Buildable) { - fileCollection.builtBy(((Buildable) classpath).getBuildDependencies()); + public FileCollection inferGosuClasspath(final Iterable classpath) { + return new LazilyInitializedFileCollection(((ProjectInternal) _project).getTaskDependencyFactory()) { + @Override + public String getDisplayName() { + return "Gosu runtime classpath"; + } + + @Override + public FileCollection createDelegate() { + try { + return inferGosuClasspath(); + } catch (RuntimeException e) { + return new FailingFileCollection(getDisplayName(), e); } - return fileCollection; } - }; - } - private FileCollection doInfer(Iterable classpath) { - if (_project.getRepositories().isEmpty()) { - throw new GradleException("Cannot infer Gosu classpath because no repository is declared in " + _project); - } + private Configuration inferGosuClasspath() { + File gosuCoreApiJar = findGosuJar(classpath, "core-api"); + if (gosuCoreApiJar == null) { + List classpathAsStrings = new ArrayList<>(); + classpath.forEach(file -> classpathAsStrings.add(file.getAbsolutePath())); + String flattenedClasspath = String.join(":", classpathAsStrings); + String errorMsg = String.format("Cannot infer Gosu classpath because the Gosu Core API Jar was not found." + LF + + "Does %s declare dependency to gosu-core-api? Searched classpath: %s.", _project, flattenedClasspath) + LF + + "An example dependencies closure may resemble the following:" + LF + + LF + + "dependencies {" + LF + + " implementation 'org.gosu-lang.gosu:gosu-core-api:1.14.3' //a newer version may be available" + LF + + "}" + LF; + _project.getLogger().quiet(errorMsg); + throw new GradleException(errorMsg); + } - File gosuCoreApiJar = findGosuJar(classpath, "core-api"); - - if (gosuCoreApiJar == null) { - List classpathAsStrings = new ArrayList<>(); - classpath.forEach(file -> classpathAsStrings.add(file.getAbsolutePath())); - String flattenedClasspath = String.join(":", classpathAsStrings); - String errorMsg = String.format("Cannot infer Gosu classpath because the Gosu Core API Jar was not found." + LF + - "Does %s declare dependency to gosu-core-api? Searched classpath: %s.", _project, flattenedClasspath) + LF + - "An example dependencies closure may resemble the following:" + LF + - LF + - "dependencies {" + LF + - " compile 'org.gosu-lang.gosu:gosu-core-api:1.14.3' //a newer version may be available" + LF + - "}" + LF; - _project.getLogger().quiet(errorMsg); - throw new GradleException(errorMsg); - } + String gosuCoreApiRawVersion = getGosuVersion(gosuCoreApiJar); - String gosuCoreApiRawVersion = getGosuVersion(gosuCoreApiJar); + if (gosuCoreApiRawVersion == null) { + throw new AssertionError(String.format("Unexpectedly failed to parse version of Gosu Jar file: %s in %s", gosuCoreApiJar, _project)); + } - if (gosuCoreApiRawVersion == null) { - throw new AssertionError(String.format("Unexpectedly failed to parse version of Gosu Jar file: %s in %s", gosuCoreApiJar, _project)); - } + //Use Gradle's VersionNumber construct, which implements Comparable + VersionNumber gosuCoreApiVersion = VersionNumber.parse(gosuCoreApiRawVersion); - //Use Gradle's VersionNumber construct, which implements Comparable - VersionNumber gosuCoreApiVersion = VersionNumber.parse(gosuCoreApiRawVersion); + //Gosu dist with gosuc executable is required + if (!gosuCoreApiRawVersion.endsWith("-SNAPSHOT") && !hasGosuc(gosuCoreApiVersion)) { + throw new GradleException(String.format("Please declare a dependency on Gosu version 1.13.9, 1.14.2 or greater. Found: %s", gosuCoreApiRawVersion)); + } - //Gosu dist with gosuc executable is required - if (!gosuCoreApiRawVersion.endsWith("-SNAPSHOT") && !hasGosuc(gosuCoreApiVersion)) { - throw new GradleException(String.format("Please declare a dependency on Gosu version 1.13.9, 1.14.2 or greater. Found: %s", gosuCoreApiRawVersion)); - } + Configuration gosuRuntimeClasspath = _project.getConfigurations().detachedConfiguration(); + gosuRuntimeClasspath.getDependencies().add(_project.getDependencies().create("org.gosu-lang.gosu:gosu-doc:" + gosuCoreApiRawVersion)); + _jvmPluginServices.configureAsRuntimeClasspath(gosuRuntimeClasspath); + return gosuRuntimeClasspath; + } - Configuration detachedConfiguration = _project.getConfigurations().detachedConfiguration(); - detachedConfiguration.getDependencies().add(_project.getDependencies().create("org.gosu-lang.gosu:gosu-doc:" + gosuCoreApiRawVersion)); - return detachedConfiguration; + @Override + public void visitDependencies(TaskDependencyResolveContext context) { + if (classpath instanceof Buildable) { + context.add(classpath); + } + } + }; } /** diff --git a/src/main/java/org/gosulang/gradle/tasks/GosuSourceDirectorySet.java b/src/main/java/org/gosulang/gradle/tasks/GosuSourceDirectorySet.java new file mode 100644 index 0000000..2ce602e --- /dev/null +++ b/src/main/java/org/gosulang/gradle/tasks/GosuSourceDirectorySet.java @@ -0,0 +1,6 @@ +package org.gosulang.gradle.tasks; + +import org.gradle.api.file.SourceDirectorySet; + +public interface GosuSourceDirectorySet extends SourceDirectorySet { +} diff --git a/src/main/java/org/gosulang/gradle/tasks/GosuSourceSet.java b/src/main/java/org/gosulang/gradle/tasks/GosuSourceSet.java index 00b09ec..c09ee5b 100644 --- a/src/main/java/org/gosulang/gradle/tasks/GosuSourceSet.java +++ b/src/main/java/org/gosulang/gradle/tasks/GosuSourceSet.java @@ -1,9 +1,15 @@ package org.gosulang.gradle.tasks; -import groovy.lang.Closure; import org.gradle.api.Action; import org.gradle.api.file.SourceDirectorySet; +/** + * @deprecated Using convention to contribute to source sets is deprecated. + *

+ * You can configure the Gosu sources via the {@code GosuSourceDirectorySet} extension + * (e.g. {@code sourceSet.getExtensions().getByType(GosuSourceDirectorySet.class).setSrcDirs(...)}). + */ +@Deprecated public interface GosuSourceSet { /** @@ -13,16 +19,6 @@ public interface GosuSourceSet { */ SourceDirectorySet getGosu(); - /** - * Configures the Gosu source for this set. - * - *

The given closure is used to configure the {@link SourceDirectorySet} which contains the Gosu source. - * - * @param configureClosure The closure to use to configure the Gosu source. - * @return this - */ - GosuSourceSet gosu(Closure configureClosure); - /** * Configures the Gosu source for this set. * @@ -31,7 +27,7 @@ public interface GosuSourceSet { * @param configureAction The action to use to configure the Gosu source. * @return this */ - GosuSourceSet gosu( Action configureAction); + GosuSourceSet gosu(Action configureAction); /** * All Gosu source for this source set. diff --git a/src/main/java/org/gosulang/gradle/tasks/InfersGosuRuntime.java b/src/main/java/org/gosulang/gradle/tasks/InfersGosuRuntime.java index 363b5d2..6de4eaf 100644 --- a/src/main/java/org/gosulang/gradle/tasks/InfersGosuRuntime.java +++ b/src/main/java/org/gosulang/gradle/tasks/InfersGosuRuntime.java @@ -1,12 +1,11 @@ package org.gosulang.gradle.tasks; -import groovy.lang.Closure; import org.gradle.api.file.FileCollection; public interface InfersGosuRuntime { - Closure getGosuClasspath(); + FileCollection getGosuClasspath(); - void setGosuClasspath(Closure gosuClasspathClosure); + void setGosuClasspath(FileCollection gosuClasspath); } diff --git a/src/main/java/org/gosulang/gradle/tasks/compile/CommandLineGosuCompiler.java b/src/main/java/org/gosulang/gradle/tasks/compile/CommandLineGosuCompiler.java index c4c7ec9..6b9613d 100644 --- a/src/main/java/org/gosulang/gradle/tasks/compile/CommandLineGosuCompiler.java +++ b/src/main/java/org/gosulang/gradle/tasks/compile/CommandLineGosuCompiler.java @@ -2,17 +2,20 @@ import org.apache.tools.ant.taskdefs.condition.Os; import org.gosulang.gradle.tasks.Util; -import org.gradle.api.Project; +import org.gradle.api.JavaVersion; +import org.gradle.api.file.Directory; import org.gradle.api.file.FileCollection; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; +import org.gradle.api.model.ObjectFactory; import org.gradle.api.tasks.WorkResult; import org.gradle.api.tasks.compile.BaseForkOptions; +import org.gradle.process.ExecOperations; import org.gradle.process.ExecResult; import org.gradle.process.JavaExecSpec; import org.gradle.util.GUtil; -import org.gradle.api.JavaVersion; +import javax.inject.Inject; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -21,15 +24,22 @@ import java.util.ArrayList; import java.util.List; -public class CommandLineGosuCompiler implements GosuCompiler { +public abstract class CommandLineGosuCompiler implements GosuCompiler { private static final Logger LOGGER = Logging.getLogger(CommandLineGosuCompiler.class); - - private final Project _project; + + private final Directory _projectDir; // TODO replace, all we need is workingDir private final GosuCompileSpec _spec; private final String _projectName; - - public CommandLineGosuCompiler(Project project, GosuCompileSpec spec, String projectName ) { - _project = project; + + @Inject + public abstract ObjectFactory getObjectFactory(); + + @Inject + public abstract ExecOperations getExecOperations(); + + @Inject + public CommandLineGosuCompiler(Directory projectDir, GosuCompileSpec spec, String projectName ) { + _projectDir = projectDir; _spec = spec; _projectName = projectName; } @@ -56,13 +66,13 @@ public WorkResult execute( GosuCompileSpec spec ) { ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - ExecResult result = _project.javaexec(javaExecSpec -> { - FileCollection gosuClasspathJars = spec.getGosuClasspath().call(); + ExecResult result = getExecOperations().javaexec(javaExecSpec -> { + FileCollection gosuClasspathJars = getObjectFactory().fileCollection().from(spec.getGosuClasspath()); if (!JavaVersion.current().isJava11Compatible()) { //if it is not java 11 - gosuClasspathJars = gosuClasspathJars.plus(_project.files(Util.findToolsJar())); + gosuClasspathJars = gosuClasspathJars.plus(getObjectFactory().fileCollection().from(Util.findToolsJar())); } - javaExecSpec.setWorkingDir((Object) _project.getProjectDir()); // Gradle 4.0 overloads ProcessForkOptions#setWorkingDir; must upcast to Object for backwards compatibility + javaExecSpec.setWorkingDir(_projectDir); setJvmArgs(javaExecSpec, _spec.getGosuCompileOptions().getForkOptions()); javaExecSpec.getMainClass().set("gw.lang.gosuc.cli.CommandLineCompiler"); javaExecSpec.setClasspath(gosuClasspathJars) diff --git a/src/main/java/org/gosulang/gradle/tasks/compile/DefaultGosuCompileSpec.java b/src/main/java/org/gosulang/gradle/tasks/compile/DefaultGosuCompileSpec.java index 8f9755c..89ccb7c 100644 --- a/src/main/java/org/gosulang/gradle/tasks/compile/DefaultGosuCompileSpec.java +++ b/src/main/java/org/gosulang/gradle/tasks/compile/DefaultGosuCompileSpec.java @@ -1,6 +1,5 @@ package org.gosulang.gradle.tasks.compile; -import groovy.lang.Closure; import org.gradle.api.file.FileCollection; import org.gradle.api.tasks.compile.CompileOptions; @@ -12,7 +11,7 @@ public class DefaultGosuCompileSpec implements GosuCompileSpec { private GosuCompileOptions _gosuCompileOptions; - private transient Closure _gosuClasspath; + private FileCollection _gosuClasspath; private FileCollection _srcDirSet; @Override @@ -26,13 +25,13 @@ public void setSourceRoots( FileCollection srcDirSet ) { } @Override - public Closure getGosuClasspath() { + public FileCollection getGosuClasspath() { return _gosuClasspath; } @Override - public void setGosuClasspath(Closure _gosuClasspathClosure) { - _gosuClasspath = _gosuClasspathClosure; + public void setGosuClasspath(FileCollection gosuClasspath) { + _gosuClasspath = gosuClasspath; } public GosuCompileOptions getGosuCompileOptions() { diff --git a/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompile.java b/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompile.java index a0e7b44..0935ccf 100644 --- a/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompile.java +++ b/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompile.java @@ -1,62 +1,70 @@ package org.gosulang.gradle.tasks.compile; -import groovy.lang.Closure; -import org.gosulang.gradle.tasks.InfersGosuRuntime; -import org.gradle.api.GradleException; +import org.gradle.api.InvalidUserDataException; import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTree; -import org.gradle.api.file.SourceDirectorySet; import org.gradle.api.internal.file.FileTreeInternal; import org.gradle.api.internal.tasks.compile.CompilationSourceDirs; import org.gradle.api.logging.Logger; import org.gradle.api.model.ObjectFactory; import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.*; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.CompileClasspath; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.SkipWhenEmpty; +import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.compile.AbstractCompile; import org.gradle.api.tasks.compile.CompileOptions; -import org.gradle.util.VersionNumber; import javax.inject.Inject; import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.concurrent.Callable; +import java.util.function.BiFunction; import static org.gradle.api.tasks.PathSensitivity.NAME_ONLY; @CacheableTask -public class GosuCompile extends AbstractCompile implements InfersGosuRuntime { +public abstract class GosuCompile extends AbstractCompile { private GosuCompiler _compiler; - private Closure _gosuClasspath; - private Closure _orderClasspath; + private BiFunction _orderClasspathFunction; private final CompileOptions _compileOptions; private final GosuCompileOptions _gosuCompileOptions = new GosuCompileOptions(); - private final FileCollection stableSources = getProject().files(new Callable() { - @Override - public FileTree call() { - return getSource(); - } - }); + private final FileCollection stableSources = getProject().files((Callable) this::getSource); + + @Inject + public abstract ObjectFactory getObjectFactory(); @Inject public GosuCompile() { - _compileOptions = getServices().get(ObjectFactory.class).newInstance(CompileOptions.class); + _compileOptions = getObjectFactory().newInstance(CompileOptions.class); } @TaskAction protected void compile() { - DefaultGosuCompileSpec spec = createSpec(); + GosuCompileSpec spec = createSpec(); _compiler = getCompiler(spec); _compiler.execute(spec); } + @Internal + public abstract DirectoryProperty getProjectDir(); + + @Internal + public abstract Property getProjectName(); + /** * {@inheritDoc} */ @@ -96,78 +104,30 @@ public FileCollection getClasspath() { /** * @return the classpath to use to load the Gosu compiler. + *

+ * This value is set by default in {@link org.gosulang.gradle.GosuBasePlugin} by inferring the gosu-core-api jar from the compile-time classpath */ - @Override @Classpath - @InputFiles - public Closure getGosuClasspath() { - return _gosuClasspath; - } + public abstract ConfigurableFileCollection getGosuClasspath(); // { - @Override - public void setGosuClasspath(Closure gosuClasspathClosure) { - _gosuClasspath = gosuClasspathClosure; - } - - /** - * Annotating as @Input or @InputFiles causes errors in Guidewire applications, even when paired with @Optional. - * Marking as @Internal instead to skip warning thrown by :validateTaskProperties (org.gradle.plugin.devel.tasks.ValidateTaskProperties) - * @return a Closure returning a classpath to be passed to the GosuCompile task - */ @Internal - public Closure getOrderClasspath() { - return _orderClasspath; + public BiFunction getOrderClasspathFunction() { + return _orderClasspathFunction; } - /** - * Normally setting this value is not required. - * Certain projects relying on depth-first resolution of module dependencies can use this - * Closure to reorder the classpath as needed. - * - * @param orderClasspath a Closure returning a classpath to be passed to the GosuCompile task - */ - public void setOrderClasspath(Closure orderClasspath) { - _orderClasspath = orderClasspath; + public void setOrderClasspathFunction(BiFunction orderClasspathFunction) { + _orderClasspathFunction = orderClasspathFunction; } -/* @Internal + @Internal public FileCollection getSourceRoots() { - Set returnValues = new HashSet<>(); - //noinspection Convert2streamapi - // for(Object obj : getSourceReflectively()) { - for(Object obj : getSource()) { - if(obj instanceof SourceDirectorySet) { - returnValues.addAll(((SourceDirectorySet) obj).getSrcDirs()); - } - } - return getProject().files(returnValues); - }*/ - - -@Internal -public FileCollection getSourceRoots() { - FileTreeInternal stableSourcesAsFileTree = (FileTreeInternal) getStableSources().getAsFileTree(); - List sourceRoots = CompilationSourceDirs.inferSourceRoots(stableSourcesAsFileTree); - return getProject().getLayout().files(sourceRoots); -} - - - - //!! todo: find a better way to iterate the FileTree - private Iterable getSourceReflectively() { - try { - // Field field = SourceTask.class.getDeclaredField("source"); - Field field = SourceTask.class.getDeclaredField("sourceFiles"); - field.setAccessible(true); - return (Iterable)field.get(this); - } catch (Exception e) { - throw new RuntimeException(e); - } + FileTreeInternal stableSourcesAsFileTree = (FileTreeInternal) getStableSources().getAsFileTree(); + List sourceRoots = CompilationSourceDirs.inferSourceRoots(stableSourcesAsFileTree); + return getObjectFactory().fileCollection().from(sourceRoots); } - private DefaultGosuCompileSpec createSpec() { + private GosuCompileSpec createSpec() { DefaultGosuCompileSpec spec = new DefaultGosuCompileSpec(); - Project project = getProject(); spec.setSource(getSource()); spec.setSourceRoots(getSourceRoots()); spec.setDestinationDir(getDestinationDirectory().get().getAsFile()); @@ -176,17 +136,18 @@ private DefaultGosuCompileSpec createSpec() { spec.setCompileOptions(_compileOptions); spec.setGosuCompileOptions(_gosuCompileOptions); - if (_orderClasspath == null) { + if (_orderClasspathFunction == null) { spec.setClasspath(asList(getClasspath())); } else { - spec.setClasspath(asList(_orderClasspath.call(project, project.getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)))); - //spec.setClasspath(asList(_orderClasspath.call(project, project.getConfigurations().getByName(JavaPlugin.COMPILE_ONLY_CONFIGURATION_NAME)))); + spec.setClasspath(asList(_orderClasspathFunction.apply(getProject(), getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)))); + // FIXME getProject() may break configuration cache } - Logger logger = project.getLogger(); + Logger logger = getLogger(); + String projectName = getProjectName().get(); if(logger.isInfoEnabled()) { - logger.info("Gosu Compiler source roots for {} are:", project.getName()); + logger.info("Gosu Compiler source roots for {} are:", projectName); if(spec.getSourceRoots().isEmpty()) { logger.info(""); } else { @@ -195,7 +156,7 @@ private DefaultGosuCompileSpec createSpec() { } } - logger.info("Gosu Compiler Spec classpath for {} is:", project.getName()); + logger.info("Gosu Compiler Spec classpath for {} is:", projectName); if(!spec.getClasspath().iterator().hasNext()) { logger.info(""); } else { @@ -204,8 +165,8 @@ private DefaultGosuCompileSpec createSpec() { } } - logger.info("Gosu Compile Spec gosuClasspath for {} is:", project.getName()); - FileCollection gosuClasspath = spec.getGosuClasspath().call(); + logger.info("Gosu Compile Spec gosuClasspath for {} is:", projectName); + FileCollection gosuClasspath = getObjectFactory().fileCollection().from(spec.getGosuClasspath()); if(gosuClasspath.isEmpty()) { logger.info(""); } else { @@ -219,13 +180,20 @@ private DefaultGosuCompileSpec createSpec() { } private GosuCompiler getCompiler(GosuCompileSpec spec) { + assertGosuClasspathIsNotEmpty(); if(_compiler == null) { - GosuCompilerFactory gosuCompilerFactory = new GosuCompilerFactory(getProject(), this.getPath()); + GosuCompilerFactory gosuCompilerFactory = getServices().get(ObjectFactory.class).newInstance(GosuCompilerFactory.class, getProjectDir().get(), this.getPath()); // FIXME don't call getProject() _compiler = gosuCompilerFactory.newCompiler(spec); } return _compiler; } + protected void assertGosuClasspathIsNotEmpty() { + if (getGosuClasspath().isEmpty()) { + throw new InvalidUserDataException("Cannot infer Gosu classpath because the Gosu Core API Jar was not found."); + } + } + private List asList(final FileCollection files) { List list = new ArrayList<>(); files.forEach(list::add); diff --git a/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompilerFactory.java b/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompilerFactory.java index e044d87..f4a1925 100644 --- a/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompilerFactory.java +++ b/src/main/java/org/gosulang/gradle/tasks/compile/GosuCompilerFactory.java @@ -1,14 +1,21 @@ package org.gosulang.gradle.tasks.compile; -import org.gradle.api.Project; +import org.gradle.api.file.Directory; +import org.gradle.api.model.ObjectFactory; -public class GosuCompilerFactory implements IGosuCompilerFactory { +import javax.inject.Inject; - private final Project _project; +public abstract class GosuCompilerFactory implements IGosuCompilerFactory { + + private final Directory _projectDir; private final String _taskPath; - public GosuCompilerFactory(Project project, String forTask) { - _project = project; + @Inject + public abstract ObjectFactory getObjectFactory(); + + @Inject + public GosuCompilerFactory(Directory projectDir, String forTask) { + _projectDir = projectDir; _taskPath = forTask; } @@ -17,7 +24,7 @@ public GosuCompiler newCompiler( GosuCompileSpec spec ) { GosuCompileOptions gosuOptions = spec.getGosuCompileOptions(); GosuCompiler gosuCompiler; if(gosuOptions.isFork()) { - gosuCompiler = new CommandLineGosuCompiler(_project, spec, _taskPath); + gosuCompiler = getObjectFactory().newInstance(CommandLineGosuCompiler.class, _projectDir, spec, _taskPath); } else { gosuCompiler = new InProcessGosuCompiler(); } diff --git a/src/main/java/org/gosulang/gradle/tasks/gosudoc/CommandLineGosuDoc.java b/src/main/java/org/gosulang/gradle/tasks/gosudoc/CommandLineGosuDoc.java index 6ce178c..6c1ec60 100644 --- a/src/main/java/org/gosulang/gradle/tasks/gosudoc/CommandLineGosuDoc.java +++ b/src/main/java/org/gosulang/gradle/tasks/gosudoc/CommandLineGosuDoc.java @@ -4,15 +4,20 @@ import org.gosulang.gradle.tasks.Util; import org.gradle.api.GradleException; import org.gradle.api.JavaVersion; -import org.gradle.api.Project; +import org.gradle.api.file.Directory; import org.gradle.api.file.FileCollection; +import org.gradle.api.file.FileSystemOperations; +import org.gradle.api.file.RegularFile; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; +import org.gradle.api.model.ObjectFactory; import org.gradle.api.tasks.compile.BaseForkOptions; +import org.gradle.process.ExecOperations; import org.gradle.process.ExecResult; import org.gradle.process.JavaExecSpec; import org.gradle.tooling.BuildException; +import javax.inject.Inject; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -24,30 +29,43 @@ import java.util.jar.Manifest; import java.util.regex.Pattern; -public class CommandLineGosuDoc { +public abstract class CommandLineGosuDoc { private static final Logger LOGGER = Logging.getLogger(CommandLineGosuDoc.class); private final FileCollection _source; - private final File _targetDir; + private final Directory _targetDir; private final FileCollection _projectClasspath; private final FileCollection _gosuClasspath; private final GosuDocOptions _options; - private final Project _project; + private final String _projectName; + private final Directory _projectDir; + private final Directory _buildDir; + @Inject + public abstract ObjectFactory getObjectFactory(); - public CommandLineGosuDoc(FileCollection source, File targetDir, FileCollection gosuClasspath, FileCollection projectClasspath, GosuDocOptions options, Project project) { + @Inject + public abstract ExecOperations getExecOperations(); + + @Inject + public abstract FileSystemOperations getFs(); + + @Inject + public CommandLineGosuDoc(FileCollection source, Directory targetDir, FileCollection gosuClasspath, FileCollection projectClasspath, GosuDocOptions options, String projectName, Directory projectDir, Directory buildDir) { _source = source; _targetDir = targetDir; _gosuClasspath = gosuClasspath; _projectClasspath = projectClasspath; _options = options; - _project = project; + _projectName = projectName; + _projectDir = projectDir; + _buildDir = buildDir; } public void execute() { String startupMsg = "Initializing gosudoc generator"; - if(_project.getName().isEmpty()) { - startupMsg += " for " + _project.getName(); + if(!_projectName.isEmpty()) { + startupMsg += " for " + _projectName; } LOGGER.info(startupMsg); @@ -55,17 +73,17 @@ public void execute() { // We don't want that, so instead we create a temp directory with the contents of 'source' // Copying 'source' to the temp dir should honor its include/exclude patterns // Finally, the tmpdir will be the sole inputdir passed to the gosudoc task - final File tmpDir = new File(_project.getBuildDir(), "tmp/gosudoc"); - _project.delete(tmpDir); - _project.copy(copySpec -> copySpec.from(_source).into(tmpDir)); + final RegularFile tmpDir = _buildDir.file("tmp/gosudoc"); + getFs().delete(files-> files.delete(tmpDir)); + getFs().copy(copySpec -> copySpec.from(_source).into(tmpDir)); List gosudocArgs = new ArrayList<>(); gosudocArgs.add("-inputDirs"); - gosudocArgs.add(tmpDir.getAbsolutePath()); + gosudocArgs.add(tmpDir.getAsFile().getAbsolutePath()); gosudocArgs.add("-output"); - gosudocArgs.add(_targetDir.getAbsolutePath()); + gosudocArgs.add(_targetDir.getAsFile().getAbsolutePath()); if(_options.isVerbose()) { gosudocArgs.add("-verbose"); @@ -74,9 +92,9 @@ public void execute() { ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - FileCollection jointClasspath = _project.files(_gosuClasspath).plus(_projectClasspath); + FileCollection jointClasspath = getObjectFactory().fileCollection().from(_gosuClasspath).plus(_projectClasspath); if (!JavaVersion.current().isJava11Compatible()) { //if it is not java 11 - jointClasspath = jointClasspath.plus(_project.files(Util.findToolsJar())); + jointClasspath = jointClasspath.plus(getObjectFactory().fileCollection().from(Util.findToolsJar())); } //FileCollection jointClasspath = _project.files(_gosuClasspath).plus(_projectClasspath); @@ -90,12 +108,12 @@ public void execute() { LOGGER.info("Created classpathJar at " + classpathJar.getAbsolutePath()); - ExecResult result = _project.javaexec(javaExecSpec -> { + ExecResult result = getExecOperations().javaexec(javaExecSpec -> { - javaExecSpec.setWorkingDir((Object) _project.getProjectDir()); // Gradle 4.0 overloads ProcessForkOptions#setWorkingDir; must upcast to Object for backwards compatibility + javaExecSpec.setWorkingDir(_projectDir); setJvmArgs(javaExecSpec, _options.getForkOptions()); javaExecSpec.getMainClass().set("gw.gosudoc.cli.Gosudoc"); - javaExecSpec.setClasspath(_project.files(classpathJar)) + javaExecSpec.setClasspath(getObjectFactory().fileCollection().from(classpathJar)) .setArgs((Iterable) gosudocArgs); // Gradle 4.0 overloads JavaExecSpec#setArgs; must upcast to Iterable for backwards compatibility javaExecSpec.setStandardOutput(stdout); javaExecSpec.setErrorOutput(stderr); @@ -119,13 +137,13 @@ public void execute() { private File createClasspathJarFromFileCollection(FileCollection classpath) throws IOException { File tempFile; if (LOGGER.isDebugEnabled()) { - tempFile = File.createTempFile(CommandLineGosuDoc.class.getName(), "classpath.jar", new File(_targetDir.getAbsolutePath())); + tempFile = File.createTempFile(CommandLineGosuDoc.class.getName(), "classpath.jar", new File(_targetDir.getAsFile().getAbsolutePath())); } else { tempFile = File.createTempFile(CommandLineGosuDoc.class.getName(), "classpath.jar"); tempFile.deleteOnExit(); - } - - LOGGER.info("Creating classpath JAR at " + tempFile.getAbsolutePath()); + } + + LOGGER.info("Creating classpath JAR at {}", tempFile.getAbsolutePath()); Manifest man = new Manifest(); man.getMainAttributes().putValue(Attributes.Name.MANIFEST_VERSION.toString(), "1.0"); diff --git a/src/main/java/org/gosulang/gradle/tasks/gosudoc/GosuDoc.java b/src/main/java/org/gosulang/gradle/tasks/gosudoc/GosuDoc.java index 8e8ec79..ad0f015 100644 --- a/src/main/java/org/gosulang/gradle/tasks/gosudoc/GosuDoc.java +++ b/src/main/java/org/gosulang/gradle/tasks/gosudoc/GosuDoc.java @@ -1,14 +1,15 @@ package org.gosulang.gradle.tasks.gosudoc; -import groovy.lang.Closure; -import org.gosulang.gradle.tasks.InfersGosuRuntime; -import org.gradle.api.file.FileCollection; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.FileTree; import org.gradle.api.logging.LogLevel; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.Classpath; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.OutputDirectory; @@ -17,21 +18,31 @@ import org.gradle.api.tasks.SourceTask; import org.gradle.api.tasks.TaskAction; +import javax.inject.Inject; import java.io.File; @CacheableTask -public class GosuDoc extends SourceTask implements InfersGosuRuntime { +public abstract class GosuDoc extends SourceTask /*implements InfersGosuRuntime*/ { - private FileCollection _classpath; - private Closure _gosuClasspath; - private File _destinationDir; private GosuDocOptions _gosuDocOptions = new GosuDocOptions(); - private String _title; + @Inject + public abstract ObjectFactory getObjectFactory(); + + @Inject public GosuDoc() { getLogging().captureStandardOutput(LogLevel.INFO); } + @Internal + public abstract Property getProjectName(); + + @Internal + public abstract DirectoryProperty getProjectDir(); + + @Internal + public abstract DirectoryProperty getBuildDir(); + /** * {@inheritDoc} */ @@ -46,13 +57,7 @@ public FileTree getSource() { * @return the target directory to generate the API documentation. */ @OutputDirectory - public File getDestinationDir() { - return _destinationDir; - } - - public void setDestinationDir( File destinationDir ) { - _destinationDir = destinationDir; - } + public abstract DirectoryProperty getDestinationDir(); /** *

Returns the classpath to use to locate classes referenced by the documented source.

@@ -60,30 +65,15 @@ public void setDestinationDir( File destinationDir ) { * @return The classpath. */ @Classpath - @InputFiles - public FileCollection getClasspath() { - return _classpath; - } - - public void setClasspath( FileCollection classpath ) { - _classpath = classpath; - } + public abstract ConfigurableFileCollection getClasspath(); /** * Returns the classpath to use to load the gosudoc tool. + * * @return the classpath to use to load the gosudoc tool. */ - @Override @Classpath - @InputFiles - public Closure getGosuClasspath() { - return _gosuClasspath; - } - - @Override - public void setGosuClasspath( Closure gosuClasspathClosure ) { - _gosuClasspath = gosuClasspathClosure; - } + public abstract ConfigurableFileCollection getGosuClasspath(); /** * Returns the gosudoc generation options. @@ -104,20 +94,14 @@ public void setGosuDocOptions(GosuDocOptions gosuDocOptions) { */ @Input @Optional - public String getTitle() { - return _title; - } - - public void setTitle( String title ) { - this._title = title; - } + public abstract Property getTitle(); @TaskAction protected void generate() { GosuDocOptions options = getGosuDocOptions(); if (options.getTitle() != null && !options.getTitle().isEmpty()) { - options.setTitle(getTitle()); + options.setTitle(getTitle().get()); } - new CommandLineGosuDoc(getSource(), getDestinationDir(), getGosuClasspath().call(), getClasspath(), options, getProject()).execute(); + getObjectFactory().newInstance(CommandLineGosuDoc.class, getSource(), getDestinationDir().get(), getGosuClasspath(), getClasspath(), options, getProjectName().get(), getProjectDir().get(), getBuildDir().get()).execute(); } } diff --git a/src/test/groovy/org/gosulang/gradle/functional/ConfigurationCacheClasspathReorderTest.groovy b/src/test/groovy/org/gosulang/gradle/functional/ConfigurationCacheClasspathReorderTest.groovy new file mode 100644 index 0000000..1859ebe --- /dev/null +++ b/src/test/groovy/org/gosulang/gradle/functional/ConfigurationCacheClasspathReorderTest.groovy @@ -0,0 +1,76 @@ +package org.gosulang.gradle.functional + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import spock.lang.Ignore + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +@Ignore('This is known to fail when configuration-cache is enabled') +class ConfigurationCacheClasspathReorderTest extends AbstractGosuPluginSpecification { + + File srcMainGosu + File simplePogo + + @Override + def setup() { + srcMainGosu = testProjectDir.newFolder('src', 'main', 'gosu') + } + + def 'apply gosu plugin and reorder classpath with configuration cache in strict mode'() { + given: + buildScript << getBasicBuildScriptForTesting() + buildScript.text += + ''' + |tasks.withType(org.gosulang.gradle.tasks.compile.GosuCompile).configureEach { t -> + | // this accepts a BiFunction, which in this case reverses the classpath order + | t.orderClasspathFunction = (Project p, Configuration c) -> { + | t.logger.quiet("Project name: {}", p.name) + | def originalList = c.getFiles().asList() + | def reversedList = [] + | ListIterator li = originalList.listIterator(originalList.size()) + | while(li.hasPrevious()) { + | reversedList.add(li.previous()) + | } + | t.logger.quiet('Original list: {}', originalList) + | t.logger.quiet('Reversed list: {}', reversedList) + | return p.objects.fileCollection().from(reversedList) + | } + |} + | + '''.stripMargin() + testProjectDir.newFile('settings.gradle') << 'enableFeaturePreview "STABLE_CONFIGURATION_CACHE"' + + simplePogo = new File(srcMainGosu, asPath('example', 'gradle', 'SimplePogo.gs')) + simplePogo.getParentFile().mkdirs() + simplePogo << """ + package example.gradle + + class SimplePogo {}""" + + when: + GradleRunner runner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath() + .withArguments('compileGosu', '--no-configuration-cache') + .withGradleVersion(gradleVersion) +// .forwardOutput() + + BuildResult result = runner.build() + + then: + result.task(":compileGosu").outcome == SUCCESS + result.output.contains('Configuration cache entry stored.') + + when: + result = runner.build() + + then: + result.task(":compileGosu").outcome == SUCCESS + result.output.contains('Reusing configuration cache.') + result.output.contains('Configuration cache entry reused.') + + where: + gradleVersion << gradleVersionsToTest + } +} diff --git a/src/test/groovy/org/gosulang/gradle/functional/ConfigurationCacheNoOpTest.groovy b/src/test/groovy/org/gosulang/gradle/functional/ConfigurationCacheNoOpTest.groovy new file mode 100644 index 0000000..d71af7c --- /dev/null +++ b/src/test/groovy/org/gosulang/gradle/functional/ConfigurationCacheNoOpTest.groovy @@ -0,0 +1,39 @@ +package org.gosulang.gradle.functional + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner + +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class ConfigurationCacheNoOpTest extends AbstractGosuPluginSpecification { + + def 'apply gosu plugin and run help with configuration cache in strict mode'() { + given: + buildScript << getBasicBuildScriptForTesting() + testProjectDir.newFile('settings.gradle') << 'enableFeaturePreview "STABLE_CONFIGURATION_CACHE"' + + when: + GradleRunner runner = GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withPluginClasspath() + .withArguments('help', '--configuration-cache') + .withGradleVersion(gradleVersion) + + BuildResult result = runner.build() + + then: + result.task(":help").outcome == SUCCESS + result.output.contains('Configuration cache entry stored.') + + when: + result = runner.build() + + then: + result.task(":help").outcome == SUCCESS + result.output.contains('Reusing configuration cache.') + result.output.contains('Configuration cache entry reused.') + + where: + gradleVersion << gradleVersionsToTest + } +} diff --git a/src/test/groovy/org/gosulang/gradle/functional/LocalBuildCacheTest.groovy b/src/test/groovy/org/gosulang/gradle/functional/LocalBuildCacheTest.groovy index 6106442..8062cde 100644 --- a/src/test/groovy/org/gosulang/gradle/functional/LocalBuildCacheTest.groovy +++ b/src/test/groovy/org/gosulang/gradle/functional/LocalBuildCacheTest.groovy @@ -37,6 +37,7 @@ class LocalBuildCacheTest extends AbstractGosuPluginSpecification { def 'apply gosu plugin and compile [Gradle #gradleVersion]'() { given: buildScript << getBasicBuildScriptForTesting() + testProjectDir.newFile('settings.gradle') << 'enableFeaturePreview "STABLE_CONFIGURATION_CACHE"' simplePogo = new File(srcMainGosu, asPath('example', 'gradle', 'SimplePogo.gs')) simplePogo.getParentFile().mkdirs() @@ -50,7 +51,9 @@ class LocalBuildCacheTest extends AbstractGosuPluginSpecification { .withProjectDir(testProjectDir.root) .withTestKitDir(testKitDir.root) .withPluginClasspath() - .withArguments('gosudoc', '--build-cache') + .withArguments('gosudoc', '--build-cache', '--configuration-cache') +// .forwardOutput() +// .withDebug(true) BuildResult result = runner.build() @@ -58,25 +61,28 @@ class LocalBuildCacheTest extends AbstractGosuPluginSpecification { result.task(":compileGosu").outcome == SUCCESS result.task(":gosudoc").outcome == SUCCESS - if(VersionNumber.parse(gradleVersion) >= VersionNumber.parse('4.0')) { - result.output.contains('2 actionable tasks: 2 executed') - } else { - result.output.contains(""" -5 tasks in build, out of which 3 (60%) were executed -2 (40%) no-source -2 (40%) cache miss -1 (20%) not cacheable -""") - } + result.output.contains('Calculating task graph as no cached configuration is available for tasks: gosudoc') + result.output.contains('2 actionable tasks: 2 executed') + result.output.contains('Configuration cache entry stored.') assertTaskOutputs() - + when: + GradleRunner.create() + .withProjectDir(testProjectDir.root) + .withTestKitDir(testKitDir.root) + .withPluginClasspath() + .withArguments('clean') + .build() + + and: runner = GradleRunner.create() .withProjectDir(testProjectDir.root) .withTestKitDir(testKitDir.root) .withPluginClasspath() - .withArguments('clean', 'gosudoc', '--build-cache') + .withArguments('gosudoc', '--build-cache', '--configuration-cache') +// .forwardOutput() +// .withDebug(true) result = runner.build() @@ -84,22 +90,14 @@ class LocalBuildCacheTest extends AbstractGosuPluginSpecification { result.task(":compileGosu").outcome == FROM_CACHE result.task(":gosudoc").outcome == FROM_CACHE - if(VersionNumber.parse(gradleVersion) >= VersionNumber.parse('4.0')) { - result.output.contains('2 actionable tasks: 0 executed') - } else { - result.output.contains(""" -6 tasks in build, out of which 1 (17%) were executed -1 (17%) up-to-date -2 (33%) no-source -2 (33%) loaded from cache -1 (17%) not cacheable -""") - } + result.output.contains('Reusing configuration cache.') + result.output.contains('2 actionable tasks: 2 from cache') + result.output.contains('Configuration cache entry reused.') assertTaskOutputs() where: - gradleVersion << gradleVersionsToTest.findAll { VersionNumber.parse(it) >= VersionNumber.parse('3.5') } // build caching only available since Gradle 3.5 + gradleVersion << gradleVersionsToTest } private boolean assertTaskOutputs() { diff --git a/src/test/groovy/org/gosulang/gradle/unit/DefaultGosuSourceSetTest.groovy b/src/test/groovy/org/gosulang/gradle/unit/DefaultGosuSourceSetTest.groovy index 2abd0fc..de4974f 100644 --- a/src/test/groovy/org/gosulang/gradle/unit/DefaultGosuSourceSetTest.groovy +++ b/src/test/groovy/org/gosulang/gradle/unit/DefaultGosuSourceSetTest.groovy @@ -33,7 +33,7 @@ class DefaultGosuSourceSetTest extends Specification { def setup() { _testProjectDir.create() Project project = createRootProject(_testProjectDir.root) - sourceSet = new DefaultGosuSourceSet("", project.objects); + sourceSet = project.objects.newInstance(DefaultGosuSourceSet, "") } def 'verify_the_default_values'() { diff --git a/src/test/groovy/org/gosulang/gradle/unit/GosuRuntimeTest.groovy b/src/test/groovy/org/gosulang/gradle/unit/GosuRuntimeTest.groovy index d09bf10..ea2cdfb 100644 --- a/src/test/groovy/org/gosulang/gradle/unit/GosuRuntimeTest.groovy +++ b/src/test/groovy/org/gosulang/gradle/unit/GosuRuntimeTest.groovy @@ -17,12 +17,12 @@ class GosuRuntimeTest extends Specification { def 'inference fails if no repository declared'() { when: def gosuClasspath = project.gosuRuntime.inferGosuClasspath([new File('other.jar'), new File('gosu-core-api-1.8.jar')]) - gosuClasspath.call().files + gosuClasspath.files then: GradleException e = thrown() System.out.println(e.message) - e.message.equals('Cannot infer Gosu classpath because no repository is declared in ' + project) + e.message.equals('Please declare a dependency on Gosu version 1.13.9, 1.14.2 or greater. Found: 1.8') } def 'test to find Gosu Jars on class path'() {