package nz.stanger.lecture; import groovy.lang.Closure; import java.util.Set; import org.gradle.api.DefaultTask; import org.gradle.api.NonNullApi; import org.gradle.api.file.ConfigurableFileTree; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.FileTreeElement; import org.gradle.api.provider.Property; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.IgnoreEmptyDirectories; import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.PathSensitive; import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.util.PatternFilterable; import org.gradle.work.DisableCachingByDefault; import org.gradle.work.Incremental; /** * Custom task to generate images from text-based source formats, like PlantUML * or SVG. Apparently we shouldn't extend {@code SourceTask}, as Gradle wants to * move away from extending task types and SourceTask is at some point going to * disappear: * {@link https://github.com/gradle/gradle/issues/11461#issuecomment-560392782} * * This is based on how {@code SourceTask} does things, but without the instance * variables, as they aren't needed and make things more complex than necessary. * {@link https://github.com/gradle/gradle/blob/master/subprojects/core/src/main/java/org/gradle/api/tasks/SourceTask.java} * * In particular, {@code ConvertImageTask} implements {@code PatternFilterable} * so that it can have consistent {@code include} and {@code exclude} methods. * We don't need the separate internal {@code PatternSet} that * {@code SourceTask} has because we're using {@code ConfigurableFileTree} * (which implements {@code PatternFilterable}) instead of * {@code ConfigurableFileCollection}. * * @see org.gradle.api.file.ConfigurableFileTree * @see org.gradle.api.tasks.SourceTask * @see org.gradle.api.tasks.util.PatternFilterable */ @NonNullApi @DisableCachingByDefault(because = "Super-class, not to be instantiated directly") abstract public class GenerateImageFromSourceTask extends DefaultTask implements PatternFilterable { /** * Bitmap image transcoder hint: DPI of output image. 200 dpi looks * reasonable. {@link https://stackoverflow.com/a/63684055} */ public static final Integer OUTPUT_DPI = 200; /** * Bitmap image transcoder hint: scaled resolution of output image. * {@link https://stackoverflow.com/a/63684055} */ public static final Float SCALE_BY_RESOLUTION = OUTPUT_DPI / 72f; /** * Bitmap image transcoder hint: scaled pixel size of output image. * {@link https://stackoverflow.com/a/63684055} */ public static final Float PIXEL_UNIT_TO_MM = 25.4f / OUTPUT_DPI; /** * Name of the FOP configuration file. */ public static final String FOP_CONFIG_FILENAME = "fopconfig.xml"; /** * Output format of the generated image. */ private final Property<ImageFormat> outputFormat = getProject().getObjects().property(ImageFormat.class); /** * Returns the source for this task. Ignores source files which do not * exist. * * @return the source */ @InputFiles @IgnoreEmptyDirectories @PathSensitive(PathSensitivity.NAME_ONLY) @Incremental abstract public ConfigurableFileTree getSource(); /** * Returns the output directory for this task. * * @return the output directory */ @OutputDirectory abstract public DirectoryProperty getOutputDir(); /** * Returns the output format for this task. * * @return the output format */ @Internal public Property<ImageFormat> getOutputFormat() { return outputFormat; } /** * Sets the output format for this task. * * @param format a string value that matches the {@code ImageFormat} enum * @see stanger.nz.lecture.ImageFormat */ public void setOutputFormat(String format) { outputFormat.set(ImageFormat.valueOf(format.toUpperCase())); } /** * {@inheritDoc} */ @Override public PatternFilterable include(String... includes) { getSource().include(includes); return this; } /** * {@inheritDoc} */ @Override public PatternFilterable include(Iterable<String> includes) { getSource().include(includes); return this; } /** * {@inheritDoc} */ @Override public PatternFilterable include(Spec<FileTreeElement> includeSpec) { getSource().include(includeSpec); return this; } /** * {@inheritDoc} */ @Override public PatternFilterable include(Closure includeSpec) { getSource().include(includeSpec); return this; } /** * {@inheritDoc} */ @Override public PatternFilterable exclude(String... excludes) { getSource().exclude(excludes); return this; } /** * {@inheritDoc} */ @Override public PatternFilterable exclude(Iterable<String> excludes) { getSource().exclude(excludes); return this; } /** * {@inheritDoc} */ @Override public PatternFilterable exclude(Spec<FileTreeElement> excludeSpec) { getSource().exclude(excludeSpec); return this; } /** * {@inheritDoc} */ @Override public GenerateImageFromSourceTask exclude(Closure excludeSpec) { getSource().exclude(excludeSpec); return this; } /** * {@inheritDoc} */ @Internal @Override public Set<String> getIncludes() { return getSource().getIncludes(); } /** * {@inheritDoc} */ @Override public PatternFilterable setIncludes(Iterable<String> includes) { getSource().setIncludes(includes); return this; } /** * {@inheritDoc} */ @Internal @Override public Set<String> getExcludes() { return getSource().getExcludes(); } /** * {@inheritDoc} */ @Override public PatternFilterable setExcludes(Iterable<String> excludes) { getSource().setExcludes(excludes); return this; } }