net.elehack.gradle.science.Pandoc.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-science Show documentation
Show all versions of gradle-science Show documentation
Gradle tasks for scientific publication.
The newest version!
package net.elehack.gradle.science
import org.gradle.api.Project
import org.gradle.api.tasks.OutputFiles
import org.gradle.api.tasks.SourceTask
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.api.tasks.incremental.InputFileDetails
/**
* Task for running Pandoc. Pandoc may be run on multiple documents.
*
* The source files are compiled with Pandoc. Other files added to {@code inputs.files}
* are treated as inputs upon which all compiled files depend. A change to any of them
* results in recompiling everything.
*
* @author Michael Ekstrand
*/
class Pandoc extends SourceTask implements PandocSpec {
@Delegate PandocSpec spec = new PandocSpecImpl(project)
List documents = []
Object outputDir = {
project.buildDir
}
void outputDir(Object obj) {
outputDir = obj
}
@OutputFiles
def getOutputFiles() {
inputs.sourceFiles.files.collect { file ->
logger.info "looking up document for {}", file
lookupDocument(file).outputFile
}
}
/**
* Configure a document to compile with Pandoc. This takes a single file, and lets
* you specify per-document options.
* @param src The source file (interpreted with project.file).
* @param output The output file name (interpreted with project.file; if null, derived
* from the source file name).
* @param config A custom configuration closure for this document.
*/
void document(Map options, Object src, Closure config = null) {
logger.debug("adding document {}", src)
def output = options?.get('output')
documents << new Doc(this, src, output, config)
}
void document(Object src, Closure config) {
document(null, src, config)
}
void document(Object src) {
document(null, src, null)
}
Doc lookupDocument(File source) {
def doc = documents.find {
project.file(it.input) == source
}
return doc ?: new Doc(this, source, null, null)
}
@TaskAction
void runPandoc(IncrementalTaskInputs inc) {
def changed = new HashSet()
inc.outOfDate { InputFileDetails change ->
changed << change.file
}
def changedNonSource = changed - inputs.sourceFiles.files
Set toCompile
if (changedNonSource.isEmpty()) {
// only source files changed, compile them
toCompile = changed
} else {
// non-source files changed, compile everything
logger.info("{} non-source files changed", changedNonSource.size())
for (f in changedNonSource) {
logger.info(" {}", f)
}
toCompile = inputs.sourceFiles.files
}
for (source in toCompile) {
logger.info("compiling {}", source)
def doc = lookupDocument(source)
PandocSpecImpl spec = doc.pandocSpec
def output = doc.getOutputFile(spec)
spec.execute(source, output)
}
}
public Pandoc() {
inputs.file { bibliography }
inputs.file { template }
inputs.source {
documents.collect {
it.input
}
}
inputs.property 'args', {
fullArgs
}
}
private class Doc {
final Pandoc pandocTask
final Object input
final Object output
final Closure config
public Doc(Pandoc task, src, dst, Closure cfg) {
pandocTask = task
input = src
output = dst
config = cfg;
}
def getPandocSpec() {
def spec = copySpec()
if (config) {
config.setDelegate(spec)
config.setResolveStrategy(Closure.DELEGATE_FIRST)
config.call(input)
}
return spec
}
def getProject() {
return pandocTask.project
}
File getOutputFile() {
return getOutputFile(pandocSpec)
}
File getOutputFile(PandocSpec spec) {
if (output == null) {
def srcName = project.file(input).name
def outName = srcName.replaceAll(/(?<=\.)\w+$/,
spec.defaultOutputExtension)
def outputDir = project.file(pandocTask.outputDir)
return new File(outputDir, outName)
} else {
return project.file(output)
}
}
}
}