/**
* Copyright 2013-2015 John Ericksen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.asciidoctor.asciidoclet;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.sun.javadoc.DocErrorReporter;
import org.asciidoctor.Asciidoctor;
import org.asciidoctor.Attributes;
import org.asciidoctor.OptionsBuilder;
import org.asciidoctor.SafeMode;
import java.io.File;
import java.io.Reader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
class AttributesLoader {
private final Asciidoctor asciidoctor;
private final DocletOptions docletOptions;
private final DocErrorReporter errorReporter;
AttributesLoader(Asciidoctor asciidoctor, DocletOptions docletOptions, DocErrorReporter errorReporter) {
this.asciidoctor = asciidoctor;
this.docletOptions = docletOptions;
this.errorReporter = errorReporter;
}
Map<String, Object> load() {
List<String> attributeArgs = docletOptions.attributes();
Set<String> unset = getUnsetAttributes(attributeArgs);
// Parse command-line attrs first, if any
Map<String, Object> cmdlineAttrs = parseCmdLineAttributes(attributeArgs);
// Parse the attributes file, passing in any command-line attrs already set
Map<String, Object> attrs = parseAttributesFile(docletOptions.attributesFile(), cmdlineAttrs);
// Remove any attributes that were set in the file but removed by the -attributes option
attrs.keySet().removeAll(unset);
// Put unset attribute names back into the map as "key!", so Asciidoctor will unset
// those attributes in the document.
for (String key : unset) {
attrs.put(key + "!", "");
}
return attrs;
}
private Map<String, Object> parseCmdLineAttributes(List<String> attributeArgs) {
return new Attributes(attributeArgs.toArray(new String[attributeArgs.size()])).map();
}
private Map<String, Object> parseAttributesFile(Optional<File> attrsFile, Map<String, Object> cmdlineAttrs) {
if (attrsFile.isPresent()) {
try {
return parseAttributes(Files.newReader(attrsFile.get(), docletOptions.encoding()), cmdlineAttrs);
} catch (Exception e) {
errorReporter.printWarning("Cannot read attributes file: " + e);
}
}
return cmdlineAttrs;
}
private Map<String, Object> parseAttributes(Reader in, Map<String, Object> existingAttrs) {
OptionsBuilder options = OptionsBuilder.options()
.safe(SafeMode.SAFE)
.attributes(existingAttrs);
if (docletOptions.baseDir().isPresent()) {
options.baseDir(docletOptions.baseDir().get());
}
Map<String, Object> parsed = asciidoctor.readDocumentStructure(in, options.get().map()).getHeader().getAttributes();
// workaround for https://github.com/asciidoctor/asciidoctorj/pull/169
return new HashMap<String, Object>(parsed);
}
private Set<String> getUnsetAttributes(List<String> args) {
ImmutableSet.Builder<String> removed = ImmutableSet.builder();
for (String arg : args) {
String key = getKey(arg);
if (key.startsWith("!") || key.endsWith("!")) {
removed.add(normalizeAttrName(key));
}
}
return removed.build();
}
private String getKey(String arg) {
int idx = arg.indexOf('=');
if (idx == 0) {
throw new IllegalArgumentException("Invalid attribute arg: \"" + arg + "\"");
}
return idx == -1 ? arg : arg.substring(0, idx);
}
// remove non-word chars in name as asciidoctor would
private String normalizeAttrName(String name) {
return name.replaceAll("\\W", "").toLowerCase();
}
}