diff --git a/README.adoc b/README.adoc index a2eb232c..17fb74eb 100644 --- a/README.adoc +++ b/README.adoc @@ -130,7 +130,7 @@ When converting to HTML, images must be copied to the output location so that th ---- outputDirectory:: defaults to `${project.build.directory}/generated-docs` -outputFile:: defaults to `null`, can be used to override the name of the generated output file. This is useful for backends, that create a single file, e.g. the pdf backend. All output will be redirected to the same file, the same way as the `-o, --out-file=OUT_FILE` option from the `asciidoctor` CLI command. +outputFile:: defaults to `null`, used to override the name of the generated output file, can be a relative or absolute path. Useful for backends that create a single file, e.g. the pdf backend. All output will be redirected to the same file, the same way as the `-o, --out-file=OUT_FILE` option from the `asciidoctor` CLI command. baseDir:: (not Maven's basedir) enables to set the root path for resources (e.g. included files), defaults to `${sourceDirectory}` skip:: set this to `true` to bypass generation, defaults to `false` preserveDirectories:: enables to specify whether the documents should be rendered in the same folder structure as in the source directory or not, defaults to `false`. diff --git a/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java b/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java index 59832171..cf7d6e80 100644 --- a/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java +++ b/src/main/java/org/asciidoctor/maven/AsciidoctorMojo.java @@ -215,15 +215,17 @@ public void execute() throws MojoExecutionException, MojoFailureException { prepareResources(); copyResources(); - if (sourceDocumentName == null) { - for (final File f : scanSourceFiles()) { - setDestinationPaths(optionsBuilder, f); - renderFile(asciidoctor, optionsBuilder.asMap(), f); - } - } else { - File sourceFile = new File(sourceDirectory, sourceDocumentName); - setDestinationPaths(optionsBuilder, sourceFile); - renderFile(asciidoctor, optionsBuilder.asMap(), sourceFile); + // Prepare sources + final List sourceFiles = sourceDocumentName == null ? + scanSourceFiles() : Arrays.asList(new File(sourceDirectory, sourceDocumentName)); + + final Set dirs = new HashSet(); + for (final File source : sourceFiles) { + final File destinationPath = setDestinationPaths(optionsBuilder, source); + if (!dirs.add(destinationPath)) + getLog().warn("Duplicated destination found: overwriting file: " + destinationPath.getAbsolutePath()); + + renderFile(asciidoctor, optionsBuilder.asMap(), source); } if (synchronizations != null && !synchronizations.isEmpty()) { @@ -286,7 +288,6 @@ private void copyResources() throws MojoExecutionException { outputResourcesFiltering.filterResources(resourcesExecution); } catch (MavenFilteringException e) { throw new MojoExecutionException("Could not copy resources", e); - } } @@ -295,8 +296,9 @@ private void copyResources() throws MojoExecutionException { * * @param optionsBuilder AsciidoctorJ options to be updated. * @param sourceFile AsciiDoc source file to process. + * @return the final destination file path. */ - private void setDestinationPaths(OptionsBuilder optionsBuilder, final File sourceFile) throws MojoExecutionException { + private File setDestinationPaths(OptionsBuilder optionsBuilder, final File sourceFile) throws MojoExecutionException { try { if (baseDir != null) { optionsBuilder.baseDir(baseDir); @@ -309,8 +311,8 @@ private void setDestinationPaths(OptionsBuilder optionsBuilder, final File sourc } } if (preserveDirectories) { - String propostalPath = sourceFile.getParentFile().getCanonicalPath().substring(sourceDirectory.getCanonicalPath().length()); - File relativePath = new File(outputDirectory.getCanonicalPath() + propostalPath); + final String candidatePath = sourceFile.getParentFile().getCanonicalPath().substring(sourceDirectory.getCanonicalPath().length()); + final File relativePath = new File(outputDirectory.getCanonicalPath() + candidatePath); optionsBuilder.toDir(relativePath).destinationDir(relativePath); } else { optionsBuilder.toDir(outputDirectory).destinationDir(outputDirectory); @@ -319,6 +321,12 @@ private void setDestinationPaths(OptionsBuilder optionsBuilder, final File sourc //allow overriding the output file name optionsBuilder.toFile(outputFile); } + // return destination file path + if (outputFile != null) { + return outputFile.isAbsolute() ? + outputFile : new File((String) optionsBuilder.asMap().get(Options.DESTINATION_DIR), outputFile.getPath()); + } else + return new File((String) optionsBuilder.asMap().get(Options.DESTINATION_DIR), sourceFile.getName()); } catch (IOException e) { throw new MojoExecutionException("Unable to locate output directory", e); } @@ -712,8 +720,8 @@ public void setBaseDir(File baseDir) { this.baseDir = baseDir; } - public void setPreserveDirertories(boolean preserveDirertories) { - this.preserveDirectories = preserveDirertories; + public void setPreserveDirectories(boolean preserveDirectories) { + this.preserveDirectories = preserveDirectories; } public void setRelativeBaseDir(boolean relativeBaseDir) { diff --git a/src/test/groovy/org/asciidoctor/maven/test/AsciidoctorMojoTest.groovy b/src/test/groovy/org/asciidoctor/maven/test/AsciidoctorMojoTest.groovy index 8122dc95..d509335f 100644 --- a/src/test/groovy/org/asciidoctor/maven/test/AsciidoctorMojoTest.groovy +++ b/src/test/groovy/org/asciidoctor/maven/test/AsciidoctorMojoTest.groovy @@ -277,6 +277,38 @@ class AsciidoctorMojoTest extends Specification { text.contains('i class="fa icon-tip"') } + def "override output file with absolute path"() { + setup: + File srcDir = new File(DEFAULT_SOURCE_DIRECTORY) + File outputDir = new File('target/asciidoctor-output') + File outputFile = new File(System.getProperty('java.io.tmpdir'), 'custom_output_file.html') + + if (!outputDir.exists()) + outputDir.mkdir() + when: + AsciidoctorMojo mojo = new AsciidoctorMojo() + mojo.attributes["icons"] = "font" + mojo.embedAssets = true + mojo.imagesDir = '' + mojo.outputDirectory = outputDir + mojo.outputFile = outputFile + mojo.sourceDirectory = srcDir + mojo.sourceDocumentName = 'sample-embedded.adoc' + mojo.backend = 'html' + mojo.execute() + then: + outputDir.list().toList().isEmpty() == false + outputDir.list().toList().contains('custom_output_file.html') + + File sampleOutput = new File(outputDir, 'custom_output_file.html') + sampleOutput.length() > 0 + String text = sampleOutput.getText() + text.contains('Asciidoctor default stylesheet') + text.contains('data:image/png;base64,iVBORw0KGgo') + text.contains('font-awesome.min.css') + text.contains('i class="fa icon-tip"') + } + def "missing-attribute skip"() { given: File srcDir = new File(DEFAULT_SOURCE_DIRECTORY) @@ -1092,7 +1124,7 @@ class AsciidoctorMojoTest extends Specification { directory: relativeTestsPath, excludes : ['**/*.jpg'] ] as Resource] - mojo.preserveDirertories = true + mojo.preserveDirectories = true mojo.backend = 'html5' mojo.outputDirectory = outputDir mojo.execute() @@ -1147,7 +1179,7 @@ class AsciidoctorMojoTest extends Specification { when: AsciidoctorMojo mojo = new AsciidoctorMojo() mojo.sourceDirectory = new File(relativeTestsPath) - mojo.preserveDirertories = true + mojo.preserveDirectories = true mojo.backend = 'html5' mojo.outputDirectory = outputDir mojo.execute() @@ -1210,4 +1242,105 @@ class AsciidoctorMojoTest extends Specification { file.text.contains('Asciidoctor default stylesheet') } + def "should show message when overwriting files without outputFile"() { + setup: + def originalOut = System.out + def newOut = new ByteArrayOutputStream() + System.setOut(new PrintStream(newOut)) + def originalErr = System.err + def newErr = new ByteArrayOutputStream() + System.setErr(new PrintStream(newErr)) + + // srcDir contains 6 documents, 2 of them with the same name (HellowWorld3.adoc) + File srcDir = new File("$DEFAULT_SOURCE_DIRECTORY/relative-path-treatment/") + File outputDir = new File("target/asciidoctor-output/overlapping-outputFile/${System.currentTimeMillis()}") + if (!outputDir.exists()) + outputDir.mkdir() + when: + AsciidoctorMojo mojo = new AsciidoctorMojo() + mojo.sourceDirectory = srcDir + mojo.backend = 'html5' + mojo.outputDirectory = outputDir + mojo.execute() + then: + def asciidocs = [] + outputDir.eachFileRecurse(FileType.FILES) { + if (it.getName() ==~ /.+html/) asciidocs << it + } + asciidocs.size() == 5 + newOut.toString().count("Rendered") == 6 + newOut.toString().count("Duplicated destination found") == 1 + cleanup: + System.setOut(originalOut) + System.setErr(originalErr) + } + + def "should show message when overwriting files using outputFile"() { + setup: + def originalOut = System.out + def newOut = new ByteArrayOutputStream() + System.setOut(new PrintStream(newOut)) + def originalErr = System.err + def newErr = new ByteArrayOutputStream() + System.setErr(new PrintStream(newErr)) + + File srcDir = new File("$DEFAULT_SOURCE_DIRECTORY/relative-path-treatment/") + File outputDir = new File("target/asciidoctor-output/overlapping-outputFile/${System.currentTimeMillis()}") + if (!outputDir.exists()) + outputDir.mkdir() + when: + AsciidoctorMojo mojo = new AsciidoctorMojo() + mojo.sourceDirectory = srcDir + mojo.backend = 'html5' + mojo.outputDirectory = outputDir + mojo.outputFile = new File('single-output.html') + mojo.execute() + then: + def asciidocs = [] + outputDir.eachFileRecurse(FileType.FILES) { + if (it.getName() ==~ /.+html/) asciidocs << it + } + asciidocs.size() == 1 + newOut.toString().count("Rendered") == 6 + newOut.toString().count("Duplicated destination found") == 5 + cleanup: + System.setOut(originalOut) + System.setErr(originalErr) + } + + def "should not show message when overwriting files using outputFile and preserveDirectories"() { + setup: + def originalOut = System.out + def newOut = new ByteArrayOutputStream() + System.setOut(new PrintStream(newOut)) + def originalErr = System.err + def newErr = new ByteArrayOutputStream() + System.setErr(new PrintStream(newErr)) + + File srcDir = new File("$DEFAULT_SOURCE_DIRECTORY/relative-path-treatment/") + File outputDir = new File("target/asciidoctor-output/overlapping-outputFile/${System.currentTimeMillis()}") + if (!outputDir.exists()) + outputDir.mkdir() + when: + AsciidoctorMojo mojo = new AsciidoctorMojo() + mojo.getLog().errorEnabled + mojo.sourceDirectory = srcDir + mojo.backend = 'html5' + mojo.outputDirectory = outputDir + mojo.preserveDirectories = true + mojo.outputFile = new File('single-output.html') + mojo.execute() + then: + def asciidocs = [] + outputDir.eachFileRecurse(FileType.FILES) { + if (it.getName() ==~ /.+html/) asciidocs << it + } + asciidocs.size() == 5 + newOut.toString().count("Rendered") == 6 + newOut.toString().count("Duplicated destination found") == 1 + cleanup: + System.setOut(originalOut) + System.setErr(originalErr) + } + }