Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve Gradle configuration cache issues #730

Open
wants to merge 2 commits into
base: development-4.x
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import org.asciidoctor.gradle.base.AsciidoctorTaskFileOperations
import org.asciidoctor.gradle.base.AsciidoctorTaskMethods
import org.asciidoctor.gradle.base.AsciidoctorTaskOutputOptions
import org.asciidoctor.gradle.base.AsciidoctorTaskWorkspacePreparation
import org.asciidoctor.gradle.base.SafeMode
import org.asciidoctor.gradle.base.Transform
import org.asciidoctor.gradle.base.internal.DefaultAsciidoctorBaseDirConfiguration
import org.asciidoctor.gradle.base.internal.DefaultAsciidoctorFileOperations
Expand All @@ -38,13 +39,14 @@ import org.asciidoctor.gradle.internal.ExecutorUtils
import org.asciidoctor.gradle.internal.JavaExecUtils
import org.asciidoctor.gradle.remote.AsciidoctorJavaExec
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.Dependency
import org.gradle.api.file.FileCollection
import org.gradle.api.logging.LogLevel
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
Expand All @@ -60,6 +62,7 @@ import org.ysb33r.grolifant.api.core.runnable.AbstractJvmModelExecTask
import org.ysb33r.grolifant.api.remote.worker.WorkerAppExecutorFactory

import java.util.function.Function
import java.util.regex.Pattern

import static org.asciidoctor.gradle.base.AsciidoctorUtils.getClassLocation
import static org.asciidoctor.gradle.base.internal.AsciidoctorAttributes.evaluateProviders
Expand Down Expand Up @@ -93,17 +96,52 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
public final static Severity WARN = Severity.WARN
public final static Severity INFO = Severity.INFO

protected final AsciidoctorJExtension asciidoctorj
private ExecutionMode inProcess
private Severity failureLevel = Severity.FATAL
private final List<Object> asciidocConfigurations = []
private final File rootDir
private final File projectDir
private final File execConfigurationDataFile
private final Function<List<Dependency>, Configuration> detachedConfigurationCreator
private final Property<FileCollection> jvmClasspath
private final List<Provider<File>> gemJarProviders = []

private final Provider<Map<String, Object>> optionsProvider
private final Provider<Map<String, Object>> attributesProvider
private final Provider<List<AsciidoctorAttributeProvider>> attributeProvidersProvider
private final Provider<FileCollection> configurationsFileCollectionProvider
private final Provider<List<Pattern>> fatalWarningsProvider
private final Provider<List<String>> requiresProvider
private final Provider<LogLevel> logLevelProvider
private final Provider<SafeMode> safeModeProvider
private final Provider<List<Object>> docExtensionsProvider

private final Provider<FileCollection> jrubyLessDependenciesProvider = project.provider {
List<Dependency> deps = this.docExtensionsProvider.get().findAll {
it instanceof Dependency
} as List<Dependency>

def detachedConfigurationCreator = { ConfigurationContainer c, List<Dependency> d ->
final cfg = c.detachedConfiguration(d.toArray() as Dependency[])
cfg.canBeConsumed = false
cfg.canBeResolved = true
cfg
}.curry(project.configurations) as Function<List<Dependency>, Configuration>

Configuration cfg = detachedConfigurationCreator.apply(deps)
asciidoctorJExtension.loadJRubyResolutionStrategy(cfg)
cfg
} as Provider<FileCollection>

private final Provider<Map<String, Map<String, Object>>> attributesByLangProvider = project.provider {
def attributesByLang = [:]
languagesAsOptionals.each { lang ->
if (lang.present) {
attributesByLang.put(lang.get(), asciidoctorJExtension.getAttributesForLang(lang.get()))
}
}
attributesByLang
} as Provider<Map<String, Map<String, Object>>>

@Delegate
private final DefaultAsciidoctorFileOperations asciidoctorTaskFileOperations

Expand Down Expand Up @@ -222,7 +260,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
*/
@Input
Map<String, Object> getOptions() {
resolveAsCacheable(asciidoctorj.options, projectOperations)
resolveAsCacheable(optionsProvider.get(), projectOperations)
}

/** Apply a new set of Asciidoctor options, clearing any options previously set.
Expand All @@ -234,7 +272,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
* @param m Map with new options
*/
void setOptions(Map m) {
asciidoctorj.options = m
asciidoctorJExtension.options = m
}

/** Add additional asciidoctor options
Expand All @@ -246,7 +284,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
* @param m Map with new options
*/
void options(Map m) {
asciidoctorj.options(m)
asciidoctorJExtension.options(m)
}

/** Returns all of the Asciidoctor options.
Expand All @@ -256,7 +294,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
*/
@Input
Map<String, Object> getAttributes() {
resolveAsCacheable(asciidoctorj.attributes, projectOperations)
resolveAsCacheable(attributesProvider.get(), projectOperations)
}

/** Apply a new set of Asciidoctor options, clearing any options previously set.
Expand All @@ -268,7 +306,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
* @param m Map with new options
*/
void setAttributes(Map m) {
asciidoctorj.attributes = m
asciidoctorJExtension.attributes = m
}

/** Add additional asciidoctor options
Expand All @@ -280,7 +318,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
* @param m Map with new options
*/
void attributes(Map m) {
asciidoctorj.attributes(m)
asciidoctorJExtension.attributes(m)
}

/** Additional providers of attributes.
Expand All @@ -292,7 +330,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
*/
@Internal
List<AsciidoctorAttributeProvider> getAttributeProviders() {
asciidoctorj.attributeProviders
attributeProvidersProvider.get()
}

/** Returns all of the specified configurations as a collections of files.
Expand All @@ -301,11 +339,10 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
*
* @return FileCollection
*/
@Classpath
@SuppressWarnings('Instanceof')
FileCollection getConfigurations() {
FileCollection getConfigurations(AsciidoctorJExtension asciidoctorJExtension) {
final precompiledExtensions = findDependenciesInExtensions()
FileCollection fc = this.asciidocConfigurations.inject(asciidoctorj.configuration) {
FileCollection fc = this.asciidocConfigurations.inject(asciidoctorJExtension.configuration) {
FileCollection seed, Object it ->
seed + projectOperations.configurations.asConfiguration(it)
}
Expand Down Expand Up @@ -348,8 +385,8 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
*/
@Override
Set<Configuration> getReportableConfigurations() {
([asciidoctorj.configuration] + projectOperations.configurations.asConfigurations(asciidocConfigurations))
.toSet()
([asciidoctorJExtension.configuration] + projectOperations.configurations
.asConfigurations(asciidocConfigurations)).toSet()
}

/**
Expand Down Expand Up @@ -428,7 +465,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
entrypoint {
classpath(JavaExecUtils.getJavaExecClasspath(
projectOperations,
configurations
configurationsFileCollectionProvider.get()
))
}

Expand All @@ -440,7 +477,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
)
} else {
entrypoint {
classpath(configurations)
classpath(configurationsFileCollectionProvider)
}
}
super.exec()
Expand All @@ -467,19 +504,25 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
asciidoctorTaskFileOperations
)
this.baseDirConfiguration = new DefaultAsciidoctorBaseDirConfiguration(project, this)
this.asciidoctorj = extensions.create(AsciidoctorJExtension.NAME, AsciidoctorJExtension, this)

def asciidoctorj = extensions.create(AsciidoctorJExtension.NAME, AsciidoctorJExtension, this)
this.optionsProvider = project.provider { asciidoctorj.options }
this.safeModeProvider = project.provider { asciidoctorj.safeMode }
this.attributesProvider = project.provider { asciidoctorj.attributes }
this.attributeProvidersProvider = project.provider { asciidoctorj.attributeProviders }
this.configurationsFileCollectionProvider = project.provider { getConfigurations(asciidoctorj) }
this.fatalWarningsProvider = project.provider { asciidoctorj.fatalWarnings }
this.requiresProvider = project.provider { asciidoctorj.requires }
this.logLevelProvider = project.provider {
asciidoctorj.logLevel != null ? asciidoctorj.logLevel : LogLevel.INFO
}
this.docExtensionsProvider = project.provider { asciidoctorj.docExtensions }

this.projectDir = project.projectDir
this.rootDir = project.rootDir
this.jvmClasspath = project.objects.property(FileCollection)
this.execConfigurationDataFile = getExecConfigurationDataFile(this)
this.detachedConfigurationCreator = { ConfigurationContainer c, List<Dependency> deps ->
final cfg = c.detachedConfiguration(deps.toArray() as Dependency[])
cfg.canBeConsumed = false
cfg.canBeResolved = true
cfg
}.curry(project.configurations) as Function<List<Dependency>, Configuration>

inputs.files(this.asciidoctorj.configuration)
inputs.files { gemJarProviders }.withPathSensitivity(RELATIVE)
inputs.property 'backends', { -> backends() }
inputs.property 'asciidoctorj-version', { -> asciidoctorj.version }
Expand Down Expand Up @@ -585,13 +628,13 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
),
backendName: backendName,
logDocuments: logDocuments,
fatalMessagePatterns: asciidoctorj.fatalWarnings,
fatalMessagePatterns: fatalWarningsProvider.get(),
asciidoctorExtensions: serializableAsciidoctorJExtensions,
requires: asciidoctorj.requires,
requires: requiresProvider.get(),
copyResources: copyResources.present &&
(copyResources.get().empty || backendName in copyResources.get()),
executorLogLevel: ExecutorUtils.getExecutorLogLevel(asciidoctorj.logLevel),
safeModeLevel: asciidoctorj.safeMode.level
executorLogLevel: ExecutorUtils.getExecutorLogLevel(logLevelProvider.get()),
safeModeLevel: safeModeProvider.get().level
)
}

Expand All @@ -601,7 +644,12 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
*/
@Internal
protected List<Object> getAsciidoctorJExtensions() {
asciidoctorj.docExtensions
docExtensionsProvider.get()
}

@Internal
protected AsciidoctorJExtension getAsciidoctorJExtension() {
extensions.getByName(AsciidoctorJExtension.NAME) as AsciidoctorJExtension
}

@Nested
Expand Down Expand Up @@ -703,7 +751,7 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe

@SuppressWarnings('Instanceof')
private FileCollection findDependenciesInExtensions() {
List<Dependency> deps = asciidoctorj.docExtensions.findAll {
List<Dependency> deps = this.docExtensionsProvider.get().findAll {
it instanceof Dependency
} as List<Dependency>

Expand All @@ -719,19 +767,19 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
if (deps.empty && closurePaths.empty) {
projectOperations.fsOperations.emptyFileCollection()
} else if (closurePaths.empty) {
jrubyLessConfiguration(deps)
jrubyLessDependenciesProvider.get()
} else if (deps.empty) {
projectOperations.fsOperations.files(closurePaths)
} else {
jrubyLessConfiguration(deps) + projectOperations.fsOperations.files(closurePaths)
jrubyLessDependenciesProvider.get() + projectOperations.fsOperations.files(closurePaths)
}
}

private void handleGradleClosureInstrumentation(Set<File> closurePaths) {
// Jumping through hoops to make docExtensions based upon closures to work.
closurePaths.add(getClassLocation(org.gradle.internal.scripts.ScriptOrigin))
if (LegacyLevel.PRE_8_4 && !LegacyLevel.PRE_7_6) {
closurePaths.add(getClassLocation(org.gradle.api.GradleException))
closurePaths.add(getClassLocation(GradleException))
}
if (LegacyLevel.PRE_8_4 && !LegacyLevel.PRE_8_3) {
closurePaths.add(getInternalGradleLibraryLocation(
Expand All @@ -750,26 +798,19 @@ class AbstractAsciidoctorTask extends AbstractJvmModelExecTask<AsciidoctorJvmExe
}
}

// TODO: Try to do this without a detached configuration
private FileCollection jrubyLessConfiguration(List<Dependency> deps) {
Configuration cfg = detachedConfigurationCreator.apply(deps)
asciidoctorj.loadJRubyResolutionStrategy(cfg)
cfg
}

private Map<String, Object> preparePreserialisedAttributes(final File workingSourceDir, Optional<String> lang) {
prepareAttributes(
projectOperations.stringTools,
attributes,
(lang.present ? asciidoctorj.getAttributesForLang(lang.get()) : [:]),
(lang.present ? attributesByLangProvider.get().getOrDefault(lang.get(), [:]) : [:]),
getTaskSpecificDefaultAttributes(workingSourceDir) as Map<String, ?>,
attributeProviders,
lang
)
}

private List<Closure> findExtensionClosures() {
asciidoctorj.docExtensions.findAll {
this.docExtensionsProvider.get().findAll {
it instanceof Closure
} as List<Closure>
}
Expand Down