@Override
  public void execute() throws BuildException {
    checkMandatoryParameter("sourceDirectory", sourceDirectory);
    checkMandatoryParameter("outputDirectory", outputDirectory);

    ensureOutputExists();

    Asciidoctor asciidoctor = Asciidoctor.Factory.create(getClass().getClassLoader());

    AttributesBuilder attributesBuilder = buildAttributes();
    OptionsBuilder optionsBuilder = buildOptions();
    optionsBuilder.attributes(attributesBuilder.get());

    if (sourceDocumentName == null) {
      log(
          "Render asciidoc files from "
              + sourceDirectory
              + " to "
              + outputDirectory
              + " with backend="
              + backend);
      for (File file : scanSourceFiles()) {
        setDestinationPaths(optionsBuilder, file);
        asciidoctor.renderFile(file, optionsBuilder.get());
      }
    } else {
      log(
          "Render "
              + sourceDocumentName
              + " from "
              + sourceDirectory
              + " to "
              + outputDirectory
              + " with backend="
              + backend);
      File file = new File(sourceDirectory, sourceDocumentName);
      setDestinationPaths(optionsBuilder, file);
      asciidoctor.renderFile(file, optionsBuilder.get());
    }

    try {
      for (FileSet resource : resources) {
        File resourceDir = resource.getDir();
        String destPath =
            resourceDir
                .getCanonicalPath()
                .substring(new File(sourceDirectory).getCanonicalPath().length());
        File destResourceDir = new File(outputDirectory, destPath);
        destResourceDir.mkdirs();
        String[] includedFiles = resource.getDirectoryScanner(getProject()).getIncludedFiles();
        FileUtils.copyDirectory(
            resourceDir, destResourceDir, new ResourceFileFilter(includedFiles), false);
      }
    } catch (IOException e) {
      throw new BuildException("Error copying resources", e);
    }
  }
 private Options getAsciiDocOptionsAndAttributes(ParserContext context) {
   Configuration config = context.getConfig();
   final AttributesBuilder attributes =
       attributes(config.getStringArray(Keys.ASCIIDOCTOR_ATTRIBUTES));
   if (config.getBoolean(Keys.ASCIIDOCTOR_ATTRIBUTES_EXPORT, false)) {
     final String prefix = config.getString(Keys.ASCIIDOCTOR_ATTRIBUTES_EXPORT_PREFIX, "");
     for (final Iterator<String> it = config.getKeys(); it.hasNext(); ) {
       final String key = it.next();
       if (!key.startsWith("asciidoctor")) {
         attributes.attribute(prefix + key.replace(".", "_"), config.getProperty(key));
       }
     }
   }
   final Configuration optionsSubset = config.subset(Keys.ASCIIDOCTOR_OPTION);
   final Options options = options().attributes(attributes.get()).get();
   for (final Iterator<String> iterator = optionsSubset.getKeys(); iterator.hasNext(); ) {
     final String name = iterator.next();
     options.setOption(name, guessTypeByContent(optionsSubset.getString(name)));
   }
   options.setBaseDir(context.getFile().getParentFile().getAbsolutePath());
   options.setSafe(UNSAFE);
   return options;
 }