Config import: Allow imports in lombok.config

This commit is contained in:
Roel Spilker committed 2020-01-20 14:10:15 +01:00
1 parent 660a056240
commit 091d14bd73
6 files changed
+92 -55

No files matched your search

@@ -40,10 +40,6 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import lombok.ConfigurationKeys;
import lombok.core.LombokApp;
import lombok.core.configuration.ConfigurationParser.Collector;
import org.mangosdk.spi.ProviderFor;
import com.zwitserloot.cmdreader.CmdReader;
@@ -54,6 +50,11 @@ import com.zwitserloot.cmdreader.Mandatory;
import com.zwitserloot.cmdreader.Sequential;
import com.zwitserloot.cmdreader.Shorthand;
import lombok.ConfigurationKeys;
import lombok.core.LombokApp;
import lombok.core.configuration.ConfigurationParser.Collector;
import lombok.core.configuration.ConfigurationParser.Context;
@ProviderFor(LombokApp.class)
public class ConfigurationApp extends LombokApp {
private static final URI NO_CONFIG = URI.create("");
@@ -258,7 +259,7 @@ public class ConfigurationApp extends LombokApp {
File configFile = new File(currentDirectory, "lombok.config");
if (!configFile.exists() || !configFile.isFile()) continue;
Map<ConfigurationKey<?>, List<String>> traces = trace(fileToString(configFile), configFile.getAbsolutePath(), keys);
Map<ConfigurationKey<?>, List<String>> traces = trace(fileToString(configFile), Context.fromFile(configFile), keys);
stopBubbling = stopBubbling(traces.get(ConfigurationKeys.STOP_BUBBLING));
for (ConfigurationKey<?> key : keys) {
@@ -287,23 +288,23 @@ public class ConfigurationApp extends LombokApp {
return result;
}
private Map<ConfigurationKey<?>, List<String>> trace(String content, String contentDescription, final Collection<ConfigurationKey<?>> keys) {
private Map<ConfigurationKey<?>, List<String>> trace(String content, Context context, final Collection<ConfigurationKey<?>> keys) {
final Map<ConfigurationKey<?>, List<String>> result = new HashMap<ConfigurationKey<?>, List<String>>();
Collector collector = new Collector() {
@Override public void clear(ConfigurationKey<?> key, String contentDescription, int lineNumber) {
@Override public void clear(ConfigurationKey<?> key, Context context, int lineNumber) {
trace(key, "clear " + key.getKeyName(), lineNumber);
}
@Override public void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
@Override public void set(ConfigurationKey<?> key, Object value, Context context, int lineNumber) {
trace(key, key.getKeyName() + " = " + value, lineNumber);
}
@Override public void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
@Override public void add(ConfigurationKey<?> key, Object value, Context context, int lineNumber) {
trace(key, key.getKeyName() + " += " + value, lineNumber);
}
@Override public void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
@Override public void remove(ConfigurationKey<?> key, Object value, Context context, int lineNumber) {
trace(key, key.getKeyName() + " -= " + value, lineNumber);
}
@@ -317,7 +318,7 @@ public class ConfigurationApp extends LombokApp {
traces.add(String.format("%4d: %s", lineNumber, message));
}
};
new ConfigurationParser(VOID).parse(content, contentDescription, collector);
new ConfigurationParser(VOID).parse(content, context, collector);
return result;
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2016 The Project Lombok Authors.
* Copyright (C) 2014-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@
*/
package lombok.core.configuration;
import java.io.File;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -28,6 +29,7 @@ import java.util.regex.Pattern;
public class ConfigurationParser {
private static final Pattern LINE = Pattern.compile("(?:clear\\s+([^=]+))|(?:(\\S*?)\\s*([-+]?=)\\s*(.*?))");
private static final Pattern NEWLINE_FINDER = Pattern.compile("^[\t ]*(.*?)[\t\r ]*$", Pattern.MULTILINE);
private static final Pattern IMPORT = Pattern.compile("import\\s+(.*?)");
private ConfigurationProblemReporter reporter;
@@ -36,21 +38,33 @@ public class ConfigurationParser {
this.reporter = reporter;
}
public void parse(CharSequence content, String contentDescription, Collector collector) {
public void parse(CharSequence content, Context context, Collector collector) {
Map<String, ConfigurationKey<?>> registeredKeys = ConfigurationKey.registeredKeys();
int lineNumber = 0;
Matcher lineMatcher = NEWLINE_FINDER.matcher(content);
boolean importsAllowed = true;
while (lineMatcher.find()) {
CharSequence line = content.subSequence(lineMatcher.start(1), lineMatcher.end(1));
lineNumber++;
if (line.length() == 0 || line.charAt(0) == '#') continue;
Matcher matcher = LINE.matcher(line);
if (!matcher.matches()) {
reporter.report(contentDescription, "Invalid line", lineNumber, line);
Matcher importMatcher = IMPORT.matcher(line);
if (importMatcher.matches()) {
if (!importsAllowed) {
reporter.report(context.description(), "Imports are only allowed in the top of the file", lineNumber, line);
continue;
}
// collector.addImport(importMatcher.group(1), contentDescription, lineNumber);
continue;
}
Matcher matcher = LINE.matcher(line);
if (!matcher.matches()) {
reporter.report(context.description(), "Invalid line", lineNumber, line);
continue;
}
importsAllowed = false;
String operator = null;
String keyName = null;
String stringValue;
@@ -65,18 +79,18 @@ public class ConfigurationParser {
}
ConfigurationKey<?> key = registeredKeys.get(keyName);
if (key == null) {
reporter.report(contentDescription, "Unknown key '" + keyName + "'", lineNumber, line);
reporter.report(context.description(), "Unknown key '" + keyName + "'", lineNumber, line);
continue;
}
ConfigurationDataType type = key.getType();
boolean listOperator = operator.equals("+=") || operator.equals("-=");
if (listOperator && !type.isList()) {
reporter.report(contentDescription, "'" + keyName + "' is not a list and doesn't support " + operator + " (only = and clear)", lineNumber, line);
reporter.report(context.description(), "'" + keyName + "' is not a list and doesn't support " + operator + " (only = and clear)", lineNumber, line);
continue;
}
if (operator.equals("=") && type.isList()) {
reporter.report(contentDescription, "'" + keyName + "' is a list and cannot be assigned to (use +=, -= and clear instead)", lineNumber, line);
reporter.report(context.description(), "'" + keyName + "' is a list and cannot be assigned to (use +=, -= and clear instead)", lineNumber, line);
continue;
}
@@ -84,26 +98,42 @@ public class ConfigurationParser {
if (stringValue != null) try {
value = type.getParser().parse(stringValue);
} catch (Exception e) {
reporter.report(contentDescription, "Error while parsing the value for '" + keyName + "' value '" + stringValue + "' (should be " + type.getParser().exampleValue() + ")", lineNumber, line);
reporter.report(context.description(), "Error while parsing the value for '" + keyName + "' value '" + stringValue + "' (should be " + type.getParser().exampleValue() + ")", lineNumber, line);
continue;
}
if (operator.equals("clear")) {
collector.clear(key, contentDescription, lineNumber);
collector.clear(key, context, lineNumber);
} else if (operator.equals("=")) {
collector.set(key, value, contentDescription, lineNumber);
collector.set(key, value, context, lineNumber);
} else if (operator.equals("+=")) {
collector.add(key, value, contentDescription, lineNumber);
collector.add(key, value, context, lineNumber);
} else {
collector.remove(key, value, contentDescription, lineNumber);
collector.remove(key, value, context, lineNumber);
}
}
}
public interface Collector {
void clear(ConfigurationKey<?> key, String contentDescription, int lineNumber);
void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber);
void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber);
void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber);
void clear(ConfigurationKey<?> key, Context context, int lineNumber);
void set(ConfigurationKey<?> key, Object value, Context context, int lineNumber);
void add(ConfigurationKey<?> key, Object value, Context context, int lineNumber);
void remove(ConfigurationKey<?> key, Object value, Context context, int lineNumber);
}
public static final class Context {
private final File file;
public static Context fromFile(File file) {
return new Context(file);
}
private Context(File file) {
this.file = file;
}
public String description() {
return file.getAbsolutePath();
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 The Project Lombok Authors.
* Copyright (C) 2014-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -47,7 +47,7 @@ public interface ConfigurationSource {
}
}
public static class ListModification {
public static final class ListModification {
private final Object value;
private final boolean added;
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014-2015 The Project Lombok Authors.
* Copyright (C) 2014-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,6 +33,7 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import lombok.ConfigurationKeys;
import lombok.core.configuration.ConfigurationParser.Context;
import lombok.core.configuration.ConfigurationSource.Result;
import lombok.core.debug.ProblemReporter;
@@ -43,7 +44,7 @@ public class FileSystemSourceCache {
private static final long NEVER_CHECKED = -1;
private static final long MISSING = -88; // Magic value; any lombok.config with this exact epochmillis last modified will never be read, so, let's ensure nobody accidentally has one with that exact last modified stamp.
private final ConcurrentMap<File, Content> dirCache = new ConcurrentHashMap<File, Content>(); // caches files (representing dirs) to the content object that tracks content.
private final ConcurrentMap<File, Content> fileCache = new ConcurrentHashMap<File, Content>(); // caches files to the content object that tracks content.
private final ConcurrentMap<URI, File> uriCache = new ConcurrentHashMap<URI, File>(); // caches URIs of java source files to the dir that contains it.
private volatile long lastCacheClear = System.currentTimeMillis();
@@ -54,7 +55,7 @@ public class FileSystemSourceCache {
long delta = now - lastCacheClear;
if (delta > FULL_CACHE_CLEAR_INTERVAL) {
lastCacheClear = now;
dirCache.clear();
fileCache.clear();
uriCache.clear();
}
}
@@ -149,10 +150,13 @@ public class FileSystemSourceCache {
}
ConfigurationSource getSourceForDirectory(File directory, ConfigurationProblemReporter reporter) {
long now = System.currentTimeMillis();
File configFile = new File(directory, LOMBOK_CONFIG_FILENAME);
Content content = ensureContent(directory);
return getSourceForConfigFile(configFile, reporter);
}
private ConfigurationSource getSourceForConfigFile(File configFile, ConfigurationProblemReporter reporter) {
long now = System.currentTimeMillis();
Content content = ensureContent(configFile);
synchronized (content) {
if (content.lastChecked != NEVER_CHECKED && now - content.lastChecked < RECHECK_FILESYSTEM) {
return content.source;
@@ -165,21 +169,21 @@ public class FileSystemSourceCache {
}
}
private Content ensureContent(File directory) {
Content content = dirCache.get(directory);
private Content ensureContent(File configFile) {
Content content = fileCache.get(configFile);
if (content != null) {
return content;
}
dirCache.putIfAbsent(directory, Content.empty());
return dirCache.get(directory);
fileCache.putIfAbsent(configFile, Content.empty());
return fileCache.get(configFile);
}
private ConfigurationSource parse(File configFile, ConfigurationProblemReporter reporter) {
String contentDescription = configFile.getAbsolutePath();
Context context = Context.fromFile(configFile);
try {
return StringConfigurationSource.forString(fileToString(configFile), reporter, contentDescription);
return StringConfigurationSource.forString(fileToString(configFile), reporter, context);
} catch (Exception e) {
reporter.report(contentDescription, "Exception while reading file: " + e.getMessage(), 0, null);
reporter.report(context.description(), "Exception while reading file: " + e.getMessage(), 0, null);
return null;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 The Project Lombok Authors.
* Copyright (C) 2014-2020 The Project Lombok Authors.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -29,28 +29,28 @@ import java.util.Map;
import java.util.Map.Entry;
import lombok.core.configuration.ConfigurationParser.Collector;
import lombok.core.configuration.ConfigurationParser.Context;
public class StringConfigurationSource implements ConfigurationSource {
private final Map<ConfigurationKey<?>, Result> values;
public static ConfigurationSource forString(CharSequence content, ConfigurationProblemReporter reporter, String contentDescription) {
public static ConfigurationSource forString(CharSequence content, ConfigurationProblemReporter reporter, Context context) {
final Map<ConfigurationKey<?>, Result> values = new HashMap<ConfigurationKey<?>, Result>();
new ConfigurationParser(reporter).parse(content, contentDescription, new Collector() {
@Override public void clear(ConfigurationKey<?> key, String contentDescription, int lineNumber) {
Collector collector = new Collector() {
@Override public void clear(ConfigurationKey<?> key, Context context, int lineNumber) {
values.put(key, new Result(null, true));
}
@Override public void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
@Override public void set(ConfigurationKey<?> key, Object value, Context context, int lineNumber) {
values.put(key, new Result(value, true));
}
@Override public void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
@Override public void add(ConfigurationKey<?> key, Object value, Context context, int lineNumber) {
modifyList(key, value, true);
}
@Override public void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) {
@Override public void remove(ConfigurationKey<?> key, Object value, Context context, int lineNumber) {
modifyList(key, value, false);
}
@@ -66,7 +66,8 @@ public class StringConfigurationSource implements ConfigurationSource {
}
list.add(new ListModification(value, add));
}
});
};
new ConfigurationParser(reporter).parse(content, context, collector);
return new StringConfigurationSource(values);
}
+2 -1
View File
@@ -41,6 +41,7 @@ import org.junit.Assert;
import lombok.core.LombokImmutableList;
import lombok.core.configuration.BubblingConfigurationResolver;
import lombok.core.configuration.ConfigurationParser.Context;
import lombok.core.configuration.ConfigurationProblemReporter;
import lombok.core.configuration.ConfigurationResolver;
import lombok.core.configuration.StringConfigurationSource;
@@ -244,7 +245,7 @@ public class LombokTestSource {
}
};
this.configuration = new BubblingConfigurationResolver(Collections.singleton(StringConfigurationSource.forString(conf, reporter, file.getAbsolutePath())));
this.configuration = new BubblingConfigurationResolver(Collections.singleton(StringConfigurationSource.forString(conf, reporter, Context.fromFile(file))));
this.formatPreferences = Collections.unmodifiableMap(formats);
}