diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/lombok/core/LombokConfiguration.java | 3 | ||||
-rw-r--r-- | src/core/lombok/core/configuration/BubblingConfigurationResolver.java | 1 | ||||
-rw-r--r-- | src/core/lombok/core/configuration/ConfigurationApp.java | 14 | ||||
-rw-r--r-- | src/core/lombok/core/configuration/ConfigurationFile.java | 164 | ||||
-rw-r--r-- | src/core/lombok/core/configuration/ConfigurationParser.java | 30 | ||||
-rw-r--r-- | src/core/lombok/core/configuration/ConfigurationSource.java | 3 | ||||
-rw-r--r-- | src/core/lombok/core/configuration/FileSystemSourceCache.java | 29 | ||||
-rw-r--r-- | src/core/lombok/core/configuration/SingleConfigurationSource.java (renamed from src/core/lombok/core/configuration/StringConfigurationSource.java) | 23 |
8 files changed, 235 insertions, 32 deletions
diff --git a/src/core/lombok/core/LombokConfiguration.java b/src/core/lombok/core/LombokConfiguration.java index 4a79c797..7b4cd154 100644 --- a/src/core/lombok/core/LombokConfiguration.java +++ b/src/core/lombok/core/LombokConfiguration.java @@ -26,6 +26,7 @@ import java.util.Collections; import lombok.core.configuration.BubblingConfigurationResolver; import lombok.core.configuration.ConfigurationKey; +import lombok.core.configuration.ConfigurationParser; import lombok.core.configuration.ConfigurationProblemReporter; import lombok.core.configuration.ConfigurationResolver; import lombok.core.configuration.ConfigurationResolverFactory; @@ -74,7 +75,7 @@ public class LombokConfiguration { private static ConfigurationResolverFactory createFileSystemBubblingResolverFactory() { return new ConfigurationResolverFactory() { @Override public ConfigurationResolver createResolver(URI sourceLocation) { - return new BubblingConfigurationResolver(cache.sourcesForJavaFile(sourceLocation, ConfigurationProblemReporter.CONSOLE)); + return new BubblingConfigurationResolver(cache.sourcesForJavaFile(sourceLocation, new ConfigurationParser(ConfigurationProblemReporter.CONSOLE))); } }; } diff --git a/src/core/lombok/core/configuration/BubblingConfigurationResolver.java b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java index a5a5f1d6..20a94477 100644 --- a/src/core/lombok/core/configuration/BubblingConfigurationResolver.java +++ b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java @@ -43,6 +43,7 @@ public class BubblingConfigurationResolver implements ConfigurationResolver { List<List<ListModification>> listModificationsList = null; outer: for (ConfigurationSource source : sources) { + source.imports(); Result result = source.resolve(key); if (result == null) continue; if (isList) { diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java index e3b18408..8ff2307a 100644 --- a/src/core/lombok/core/configuration/ConfigurationApp.java +++ b/src/core/lombok/core/configuration/ConfigurationApp.java @@ -22,6 +22,7 @@ package lombok.core.configuration; import java.io.File; +import java.io.IOException; import java.io.PrintStream; import java.net.URI; import java.util.ArrayList; @@ -188,6 +189,7 @@ public class ConfigurationApp extends LombokApp { }; FileSystemSourceCache cache = new FileSystemSourceCache(); + ConfigurationParser parser = new ConfigurationParser(reporter); boolean first = true; for (Entry<URI, Set<String>> entry : sharedDirectories.entrySet()) { if (!first) { @@ -202,7 +204,7 @@ public class ConfigurationApp extends LombokApp { out.println(); } URI directory = entry.getKey(); - ConfigurationResolver resolver = new BubblingConfigurationResolver(cache.sourcesForDirectory(directory, reporter)); + ConfigurationResolver resolver = new BubblingConfigurationResolver(cache.sourcesForDirectory(directory, parser)); Map<ConfigurationKey<?>, ? extends Collection<String>> traces = trace(keys, directory); boolean printed = false; for (ConfigurationKey<?> key : keys) { @@ -257,7 +259,7 @@ public class ConfigurationApp extends LombokApp { if (!configFile.exists() || !configFile.isFile()) continue; ConfigurationFile context = ConfigurationFile.fromFile(configFile); - Map<ConfigurationKey<?>, List<String>> traces = trace(context.contents(), context, keys); + Map<ConfigurationKey<?>, List<String>> traces = trace(context, keys); stopBubbling = stopBubbling(traces.get(ConfigurationKeys.STOP_BUBBLING)); for (ConfigurationKey<?> key : keys) { @@ -286,10 +288,13 @@ public class ConfigurationApp extends LombokApp { return result; } - private Map<ConfigurationKey<?>, List<String>> trace(String content, ConfigurationFile context, final Collection<ConfigurationKey<?>> keys) { + private Map<ConfigurationKey<?>, List<String>> trace(ConfigurationFile context, final Collection<ConfigurationKey<?>> keys) throws IOException { final Map<ConfigurationKey<?>, List<String>> result = new HashMap<ConfigurationKey<?>, List<String>>(); Collector collector = new Collector() { + @Override public void addImport(ConfigurationFile importFile, ConfigurationFile context, int lineNumber) { + // TODO Trace imports + } @Override public void clear(ConfigurationKey<?> key, ConfigurationFile context, int lineNumber) { trace(key, "clear " + key.getKeyName(), lineNumber); } @@ -315,8 +320,9 @@ public class ConfigurationApp extends LombokApp { } traces.add(String.format("%4d: %s", lineNumber, message)); } + }; - new ConfigurationParser(VOID).parse(content, context, collector); + new ConfigurationParser(VOID).parse(context, collector); return result; } diff --git a/src/core/lombok/core/configuration/ConfigurationFile.java b/src/core/lombok/core/configuration/ConfigurationFile.java new file mode 100644 index 00000000..eed2e6c4 --- /dev/null +++ b/src/core/lombok/core/configuration/ConfigurationFile.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package lombok.core.configuration; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +public abstract class ConfigurationFile { + private static final ThreadLocal<byte[]> buffers = new ThreadLocal<byte[]>() { + protected byte[] initialValue() { + return new byte[65536]; + } + }; + + private final String identifier; + + public static ConfigurationFile fromFile(File file) { + return new RegularConfigurationFile(file); + } + + public static ConfigurationFile fromCharSequence(String identifier, CharSequence contents, long lastModified) { + return new CharSequenceConfigurationFile(identifier, contents, lastModified); + } + + private ConfigurationFile(String identifier) { + this.identifier = identifier; + } + + abstract long getLastModifiedOrMissing(); + abstract boolean exists(); + abstract CharSequence contents() throws IOException; + public abstract ConfigurationFile resolve(String path); + + final String description() { + return identifier; + } + + @Override public boolean equals(Object obj) { + if (!(obj instanceof ConfigurationFile)) return false; + return identifier.equals(((ConfigurationFile)obj).identifier); + } + + @Override public int hashCode() { + return identifier.hashCode(); + } + + public static long getLastModifiedOrMissing(File file) { + if (!fileExists(file)) return FileSystemSourceCache.MISSING; + return file.lastModified(); + } + + private static boolean fileExists(File file) { + return file.exists() && file.isFile(); + } + + private static String read(InputStream is) throws IOException { + byte[] b = buffers.get(); + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + while (true) { + int r = is.read(b); + if (r == -1) break; + out.write(b, 0, r); + } + return new String(out.toByteArray(), "UTF-8"); + } finally { + is.close(); + } + } + + private static class RegularConfigurationFile extends ConfigurationFile { + private final File file; + + private RegularConfigurationFile(File file) { + super(file.getPath()); + this.file = file; + } + + @Override boolean exists() { + return fileExists(file); + } + + public ConfigurationFile resolve(String path) { + File file = resolveFile(path); + return file == null ? null : fromFile(file); + } + + private File resolveFile(String path) { + boolean absolute = false; + int colon = path.indexOf(':'); + if (colon != -1) { + if (colon != 1 || path.indexOf(':', colon + 1) != -1) return null; + char firstCharacter = Character.toLowerCase(path.charAt(0)); + if (firstCharacter < 'a' || firstCharacter > 'z') return null; + absolute = true; + } + if (path.charAt(0) == '/') absolute = true; + try { + return absolute ? new File(path) : new File(file.toURI().resolve(path)); + } catch (Exception e) { + return null; + } + } + + @Override + long getLastModifiedOrMissing() { + return getLastModifiedOrMissing(file); + } + + @Override + CharSequence contents() throws IOException { + return read(new FileInputStream(file)); + } + } + + private static class CharSequenceConfigurationFile extends ConfigurationFile { + private final CharSequence contents; + private final long lastModified; + + private CharSequenceConfigurationFile(String identifier, CharSequence contents, long lastModified) { + super(identifier); + this.contents = contents; + this.lastModified = lastModified; + } + + @Override long getLastModifiedOrMissing() { + return lastModified; + } + + @Override CharSequence contents() throws IOException { + return contents; + } + + @Override boolean exists() { + return true; + } + + @Override public ConfigurationFile resolve(String path) { + return null; + } + } +}
\ No newline at end of file diff --git a/src/core/lombok/core/configuration/ConfigurationParser.java b/src/core/lombok/core/configuration/ConfigurationParser.java index a19e48d8..4b9846d9 100644 --- a/src/core/lombok/core/configuration/ConfigurationParser.java +++ b/src/core/lombok/core/configuration/ConfigurationParser.java @@ -21,6 +21,7 @@ */ package lombok.core.configuration; +import java.io.IOException; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -37,13 +38,17 @@ public class ConfigurationParser { this.reporter = reporter; } - public void parse(CharSequence content, ConfigurationFile context, Collector collector) { + public void parse(ConfigurationFile context, Collector collector) { + CharSequence contents = contents(context); + if (contents == null) { + return; + } Map<String, ConfigurationKey<?>> registeredKeys = ConfigurationKey.registeredKeys(); int lineNumber = 0; - Matcher lineMatcher = NEWLINE_FINDER.matcher(content); + Matcher lineMatcher = NEWLINE_FINDER.matcher(contents); boolean importsAllowed = true; while (lineMatcher.find()) { - CharSequence line = content.subSequence(lineMatcher.start(1), lineMatcher.end(1)); + CharSequence line = contents.subSequence(lineMatcher.start(1), lineMatcher.end(1)); lineNumber++; if (line.length() == 0 || line.charAt(0) == '#') continue; @@ -54,9 +59,16 @@ public class ConfigurationParser { continue; } String imported = importMatcher.group(1); - if (!context.importResolves(imported)) { + ConfigurationFile importFile = context.resolve(imported); + if (importFile == null) { + reporter.report(context.description(), "Import is not valid", lineNumber, line); + continue; + } + if (!importFile.exists()) { reporter.report(context.description(), "Imported file does not exist", lineNumber, line); + continue; } + collector.addImport(importFile, context, lineNumber); continue; } @@ -116,7 +128,17 @@ public class ConfigurationParser { } } + private CharSequence contents(ConfigurationFile context) { + try { + return context.contents(); + } catch (IOException e) { + reporter.report(context.description(), "Exception while reading file: " + e.getMessage(), 0, null); + } + return null; + } + public interface Collector { + void addImport(ConfigurationFile importFile, ConfigurationFile context, int lineNumber); void clear(ConfigurationKey<?> key, ConfigurationFile context, int lineNumber); void set(ConfigurationKey<?> key, Object value, ConfigurationFile context, int lineNumber); void add(ConfigurationKey<?> key, Object value, ConfigurationFile context, int lineNumber); diff --git a/src/core/lombok/core/configuration/ConfigurationSource.java b/src/core/lombok/core/configuration/ConfigurationSource.java index 1e7f9150..7fcfc0fd 100644 --- a/src/core/lombok/core/configuration/ConfigurationSource.java +++ b/src/core/lombok/core/configuration/ConfigurationSource.java @@ -21,9 +21,12 @@ */ package lombok.core.configuration; +import java.util.List; + public interface ConfigurationSource { Result resolve(ConfigurationKey<?> key); + List<ConfigurationFile> imports(); public static final class Result { private final Object value; diff --git a/src/core/lombok/core/configuration/FileSystemSourceCache.java b/src/core/lombok/core/configuration/FileSystemSourceCache.java index 0dfc54ab..e18cf9c9 100644 --- a/src/core/lombok/core/configuration/FileSystemSourceCache.java +++ b/src/core/lombok/core/configuration/FileSystemSourceCache.java @@ -57,7 +57,7 @@ public class FileSystemSourceCache { } } - public Iterable<ConfigurationSource> sourcesForJavaFile(URI javaFile, ConfigurationProblemReporter reporter) { + public Iterable<ConfigurationSource> sourcesForJavaFile(URI javaFile, ConfigurationParser parser) { if (javaFile == null) return Collections.emptyList(); cacheClear(); File dir = uriCache.get(javaFile); @@ -86,7 +86,7 @@ public class FileSystemSourceCache { if (dir != null) { try { - return sourcesForDirectory(dir, reporter); + return sourcesForDirectory(dir, parser); } catch (Exception e) { // Especially for eclipse's sake, exceptions here make eclipse borderline unusable, so let's play nice. ProblemReporter.error("Can't resolve config stack for dir: " + dir.getAbsolutePath(), e); @@ -96,11 +96,11 @@ public class FileSystemSourceCache { return Collections.emptyList(); } - public Iterable<ConfigurationSource> sourcesForDirectory(URI directory, ConfigurationProblemReporter reporter) { - return sourcesForJavaFile(directory, reporter); + public Iterable<ConfigurationSource> sourcesForDirectory(URI directory, ConfigurationParser parser) { + return sourcesForJavaFile(directory, parser); } - private Iterable<ConfigurationSource> sourcesForDirectory(final File directory, final ConfigurationProblemReporter reporter) { + private Iterable<ConfigurationSource> sourcesForDirectory(final File directory, final ConfigurationParser parser) { return new Iterable<ConfigurationSource>() { @Override public Iterator<ConfigurationSource> iterator() { @@ -127,7 +127,7 @@ public class FileSystemSourceCache { private ConfigurationSource findNext() { while (currentDirectory != null && next == null) { - next = getSourceForDirectory(currentDirectory, reporter); + next = getSourceForDirectory(currentDirectory, parser); currentDirectory = currentDirectory.getParentFile(); } if (next != null) { @@ -146,11 +146,11 @@ public class FileSystemSourceCache { }; } - ConfigurationSource getSourceForDirectory(File directory, ConfigurationProblemReporter reporter) { - return getSourceForConfigFile(ConfigurationFile.fromFile(new File(directory, LOMBOK_CONFIG_FILENAME)), reporter); + ConfigurationSource getSourceForDirectory(File directory,ConfigurationParser parser) { + return getSourceForConfigFile(ConfigurationFile.fromFile(new File(directory, LOMBOK_CONFIG_FILENAME)), parser); } - private ConfigurationSource getSourceForConfigFile(ConfigurationFile context, ConfigurationProblemReporter reporter) { + private ConfigurationSource getSourceForConfigFile(ConfigurationFile context, ConfigurationParser parser) { long now = System.currentTimeMillis(); Content content = ensureContent(context); synchronized (content) { @@ -160,7 +160,7 @@ public class FileSystemSourceCache { content.lastChecked = now; long previouslyModified = content.lastModified; content.lastModified = context.getLastModifiedOrMissing(); - if (content.lastModified != previouslyModified) content.source = content.lastModified == MISSING ? null : parse(context, reporter); + if (content.lastModified != previouslyModified) content.source = content.lastModified == MISSING ? null : parse(context, parser); return content.source; } } @@ -174,13 +174,8 @@ public class FileSystemSourceCache { return fileCache.get(context); } - private ConfigurationSource parse(ConfigurationFile context, ConfigurationProblemReporter reporter) { - try { - return StringConfigurationSource.forString(context.contents(), reporter, context); - } catch (Exception e) { - reporter.report(context.description(), "Exception while reading file: " + e.getMessage(), 0, null); - return null; - } + private ConfigurationSource parse(ConfigurationFile context, ConfigurationParser parser) { + return SingleConfigurationSource.parse(context, parser); } private static class Content { diff --git a/src/core/lombok/core/configuration/StringConfigurationSource.java b/src/core/lombok/core/configuration/SingleConfigurationSource.java index c1bd498e..a5298339 100644 --- a/src/core/lombok/core/configuration/StringConfigurationSource.java +++ b/src/core/lombok/core/configuration/SingleConfigurationSource.java @@ -30,13 +30,18 @@ import java.util.Map.Entry; import lombok.core.configuration.ConfigurationParser.Collector; -public class StringConfigurationSource implements ConfigurationSource { +public final class SingleConfigurationSource implements ConfigurationSource { private final Map<ConfigurationKey<?>, Result> values; + private final List<ConfigurationFile> imports; - public static ConfigurationSource forString(CharSequence content, ConfigurationProblemReporter reporter, ConfigurationFile context) { + public static ConfigurationSource parse(ConfigurationFile context, ConfigurationParser parser) { final Map<ConfigurationKey<?>, Result> values = new HashMap<ConfigurationKey<?>, Result>(); - + final List<ConfigurationFile> imports = new ArrayList<ConfigurationFile>(); Collector collector = new Collector() { + @Override public void addImport(ConfigurationFile importFile, ConfigurationFile context, int lineNumber) { + imports.add(importFile); + } + @Override public void clear(ConfigurationKey<?> key, ConfigurationFile context, int lineNumber) { values.put(key, new Result(null, true)); } @@ -66,11 +71,11 @@ public class StringConfigurationSource implements ConfigurationSource { list.add(new ListModification(value, add)); } }; - new ConfigurationParser(reporter).parse(content, context, collector); - return new StringConfigurationSource(values); + parser.parse(context, collector); + return new SingleConfigurationSource(values, imports); } - private StringConfigurationSource(Map<ConfigurationKey<?>, Result> values) { + private SingleConfigurationSource(Map<ConfigurationKey<?>, Result> values, List<ConfigurationFile> imports) { this.values = new HashMap<ConfigurationKey<?>, Result>(); for (Entry<ConfigurationKey<?>, Result> entry : values.entrySet()) { Result result = entry.getValue(); @@ -80,10 +85,16 @@ public class StringConfigurationSource implements ConfigurationSource { this.values.put(entry.getKey(), result); } } + this.imports = Collections.unmodifiableList(imports); } @Override public Result resolve(ConfigurationKey<?> key) { return values.get(key); } + + @Override + public List<ConfigurationFile> imports() { + return imports; + } } |