diff options
author | Roel Spilker <r.spilker@gmail.com> | 2014-01-21 22:21:58 +0100 |
---|---|---|
committer | Roel Spilker <r.spilker@gmail.com> | 2014-01-21 22:21:58 +0100 |
commit | ed061712f556161d8a6eb1400fffbaace8dd1ac0 (patch) | |
tree | 92dcf0e98b946b6f8216387df12ee61021f3d52f | |
parent | ff0157486440f74c28f96e3708ed9e958086d65b (diff) | |
download | lombok-ed061712f556161d8a6eb1400fffbaace8dd1ac0.tar.gz lombok-ed061712f556161d8a6eb1400fffbaace8dd1ac0.tar.bz2 lombok-ed061712f556161d8a6eb1400fffbaace8dd1ac0.zip |
[configuration] Extended the configuration app to display the resulting configuration for a path and have 'blame'. Removed the PrintConfiguration annotation and handlers. Separated the parsing and the interpreting.
9 files changed, 388 insertions, 308 deletions
diff --git a/src/core/lombok/core/LombokConfiguration.java b/src/core/lombok/core/LombokConfiguration.java index f2661a53..137a8a83 100644 --- a/src/core/lombok/core/LombokConfiguration.java +++ b/src/core/lombok/core/LombokConfiguration.java @@ -21,13 +21,9 @@ */ package lombok.core; -import java.io.PrintStream; -import java.util.ArrayList; -import java.util.List; - import lombok.core.configuration.BubblingConfigurationResolver; -import lombok.core.configuration.ConfigurationProblemReporter; import lombok.core.configuration.ConfigurationKey; +import lombok.core.configuration.ConfigurationProblemReporter; import lombok.core.configuration.ConfigurationResolver; import lombok.core.configuration.ConfigurationResolverFactory; import lombok.core.configuration.FileSystemSourceCache; @@ -48,35 +44,6 @@ public class LombokConfiguration { return configurationResolverFactory.createResolver(ast).resolve(key); } - public static void writeConfiguration(AST<?, ?, ?> ast, PrintStream stream) { - final List<String> problems = new ArrayList<String>(); - ConfigurationProblemReporter reporter = new ConfigurationProblemReporter() { - @Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) { - problems.add(String.format("%s (%s:%d)", problem, sourceDescription, lineNumber)); - } - }; - - stream.printf("Combined lombok configuration for '%s'\n\n", ast.getAbsoluteFileLocation()); - // create a new empty 'cache' to make sure all problems are reported - cache.reset(); - ConfigurationResolver resolver = new BubblingConfigurationResolver(cache.sourcesForJavaFile(ast.getAbsoluteFileLocation(), reporter)); - for (ConfigurationKey<?> key : ConfigurationKey.registeredKeys().values()) { - Object value = resolver.resolve(key); - if (value == null || value instanceof List<?> && ((List<?>)value).isEmpty()) continue; - stream.printf("%s: %s\n", key.getKeyName(), value); - } - - if (!problems.isEmpty()) { - stream.println(); - stream.printf("Problems encountered during parsing: %d\n", problems.size()); - int i = 1; - for (String problem : problems) { - stream.printf("%4d - %s\n", i, problem); - i++; - } - } - } - private static ConfigurationResolverFactory createFileSystemBubblingResolverFactory() { return new ConfigurationResolverFactory() { @Override public ConfigurationResolver createResolver(AST<?, ?, ?> ast) { diff --git a/src/core/lombok/core/PrintConfiguration.java b/src/core/lombok/core/PrintConfiguration.java deleted file mode 100644 index 05d4ab4d..00000000 --- a/src/core/lombok/core/PrintConfiguration.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2014 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; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Will print the combined interpreted configuration from 'lombok.config' files. - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.SOURCE) -public @interface PrintConfiguration { - /** - * Normally, the configuration is printed to standard out, but you can pick a filename instead. Useful for many IDEs - * which don't have a console unless you start them from the command line. - */ - String outfile() default ""; -} diff --git a/src/core/lombok/core/configuration/BubblingConfigurationResolver.java b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java index 623c6cc0..f96b4468 100644 --- a/src/core/lombok/core/configuration/BubblingConfigurationResolver.java +++ b/src/core/lombok/core/configuration/BubblingConfigurationResolver.java @@ -66,7 +66,7 @@ public class BubblingConfigurationResolver implements ConfigurationResolver { List<Object> listValues = new ArrayList<Object>(); Collections.reverse(listModificationsList); for (List<ListModification> listModifications : listModificationsList) { - for (ListModification modification : listModifications) { + if (listModifications != null) for (ListModification modification : listModifications) { listValues.remove(modification.getValue()); if (modification.isAdded()) { listValues.add(modification.getValue()); diff --git a/src/core/lombok/core/configuration/ConfigurationApp.java b/src/core/lombok/core/configuration/ConfigurationApp.java index e7f438d7..fe7f7ad4 100644 --- a/src/core/lombok/core/configuration/ConfigurationApp.java +++ b/src/core/lombok/core/configuration/ConfigurationApp.java @@ -21,12 +21,27 @@ */ package lombok.core.configuration; +import static lombok.core.configuration.FileSystemSourceCache.fileToString; + +import java.io.File; import java.io.PrintStream; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +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; @@ -40,6 +55,7 @@ import com.zwitserloot.cmdreader.Shorthand; @ProviderFor(LombokApp.class) public class ConfigurationApp extends LombokApp { + private static final URI NO_CONFIG = URI.create(""); @Override public String getAppName() { return "configuration"; @@ -68,6 +84,10 @@ public class ConfigurationApp extends LombokApp { @Description("Displays more information.") boolean verbose = false; + @Shorthand("k") + @Description("Limit the result to these keys.") + private List<String> key = new ArrayList<String>(); + @Shorthand({"h", "?"}) @Description("Shows this help text.") boolean help = false; @@ -89,34 +109,21 @@ public class ConfigurationApp extends LombokApp { } ConfigurationKeysLoader.LoaderLoader.loadAllConfigurationKeys(); + Collection<ConfigurationKey<?>> keys = checkKeys(args.key); + if (keys == null) return 1; if (args.generate) { - printConfiguration(System.out, args.verbose); - } else { - System.out.println("Not generating anything..."); + return generate(System.out, args.verbose, keys); } - -// List<File> filesToProcess = PostCompilerApp.cmdArgsToFiles(args.classFiles); - int filesVisited = 0; -// boolean moreThanOne = filesToProcess.size() > 1; -// for (File file : filesToProcess) { -// if (!file.exists() || !file.isFile()) { -// System.out.printf("Cannot find file '%s'\n", file.getAbsolutePath()); -// continue; -// } -// filesVisited++; -// if (moreThanOne) System.out.printf("Processing '%s'\n", file.getAbsolutePath()); -// System.out.println(new ClassFileMetaData(PostCompilerApp.readFile(file)).poolContent()); -// } -// -// if (moreThanOne) System.out.printf("Total files visited: %d\n", filesVisited); - - return filesVisited == 0 ? 1 : 0; + TreeMap<URI, Set<String>> sharedDirectories = findSharedDirectories(args.paths); + if (sharedDirectories == null) return 1; + + return display(System.out, args.verbose, sharedDirectories, keys, args.paths.size() == 1, !args.key.isEmpty()); } - private void printConfiguration(PrintStream out, boolean verbose) { - for (ConfigurationKey<?> key : ConfigurationKey.registeredKeys().values()) { + private int generate(PrintStream out, boolean verbose, Collection<ConfigurationKey<?>> keys) { + for (ConfigurationKey<?> key : keys) { String keyName = key.getKeyName(); ConfigurationDataType type = key.getType(); String description = key.getDescription(); @@ -136,20 +143,220 @@ public class ConfigurationApp extends LombokApp { } out.println("##\n## Examples:\n#"); out.printf("# clear %s\n", keyName); + String exampleValue = type.getParser().exampleValue(); if (type.isList()) { - out.printf("# %s += %s\n", keyName, exampleValue(type)); - out.printf("# %s -= %s\n", keyName, exampleValue(type)); + out.printf("# %s += %s\n", keyName, exampleValue); + out.printf("# %s -= %s\n", keyName, exampleValue); } else { - out.printf("# %s = %s\n", keyName, exampleValue(type)); + out.printf("# %s = %s\n", keyName, exampleValue); } out.println("#\n"); } if (!verbose) { out.println("Use --verbose for more information."); } + return 0; + } + + private int display(PrintStream out, boolean verbose, TreeMap<URI, Set<String>> sharedDirectories, Collection<ConfigurationKey<?>> keys, boolean onlyOne, boolean explicitKeys) throws Exception { + Set<String> none = sharedDirectories.remove(NO_CONFIG); + if (none != null) { + if (none.size() == 1) { + out.printf("No 'lombok.config' found for '%s'.\n", none.iterator().next()); + } else { + out.println("No 'lombok.config' found for: "); + for (String path : none) out.printf("- %s\n", path); + } + } + + final List<String> problems = new ArrayList<String>(); + ConfigurationProblemReporter reporter = new ConfigurationProblemReporter() { + @Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) { + problems.add(String.format("%s: %s (%s:%d)", problem, line, sourceDescription, lineNumber)); + } + }; + + FileSystemSourceCache cache = new FileSystemSourceCache(); + boolean first = true; + for (Entry<URI, Set<String>> entry : sharedDirectories.entrySet()) { + if (!first) { + out.print("\n\n"); + } + Set<String> paths = entry.getValue(); + if (paths.size() == 1) { + if (!onlyOne) out.printf("Configuration for '%s'.\n\n", paths.iterator().next()); + } else { + out.printf("Configuration for:\n", paths.iterator().next()); + for (String path : paths) out.printf("- %s\n", path); + out.println(); + } + URI directory = entry.getKey(); + ConfigurationResolver resolver = new BubblingConfigurationResolver(cache.sourcesForDirectory(directory, reporter)); + Map<ConfigurationKey<?>, ? extends Collection<String>> traces = trace(keys, directory, verbose); + boolean printed = false; + for (ConfigurationKey<?> key : keys) { + Object value = resolver.resolve(key); + if (value == null || (value instanceof List<?> && ((List<?>)value).isEmpty())) { + if (explicitKeys) { + if (printed && verbose) out.println(); + printValue(out, key, value, verbose, traces.get(key)); + printed = true; + } + } else { + if (printed && verbose) out.println(); + printValue(out, key, value, verbose, traces.get(key)); + printed = true; + } + } + if (!printed) out.println("<default>"); + first = false; + } + + if (!problems.isEmpty()) { + out.printf("\nProblems in the configuration files: \n"); + for (String problem : problems) out.printf("- %s\n", problem); + } + + return 0; + } + + private void printValue(PrintStream out, ConfigurationKey<?> key, Object value, boolean verbose, Collection<String> history) { + if (verbose) out.printf("# %s\n", key.getDescription()); + if (value == null) { + out.printf("clear %s\n", key.getKeyName()); + } else if (value instanceof List<?>) { + for (Object element : (List<?>)value) out.printf("%s += %s\n", key.getKeyName(), element); + } else { + out.printf("%s = %s\n", key.getKeyName(), value); + } + if (!verbose) return; + for (String modification : history) out.printf("# %s\n", modification); + } + + private static final ConfigurationProblemReporter VOID = new ConfigurationProblemReporter() { + @Override public void report(String sourceDescription, String problem, int lineNumber, CharSequence line) {} + }; + + private Map<ConfigurationKey<?>, ? extends Collection<String>> trace(Collection<ConfigurationKey<?>> keys, URI directory, boolean verbose) throws Exception { + if (!verbose) return Collections.emptyMap(); + + Map<ConfigurationKey<?>, List<String>> result = new HashMap<ConfigurationKey<?>, List<String>>(); + for (ConfigurationKey<?> key : keys) result.put(key, new ArrayList<String>()); + + boolean stopBubbling = false; + String previousFileName = null; + for (File currentDirectory = new File(directory); currentDirectory != null && !stopBubbling; currentDirectory = currentDirectory.getParentFile()) { + File configFile = new File(currentDirectory, "lombok.config"); + if (!configFile.exists() || !configFile.isFile()) continue; + + Map<ConfigurationKey<?>, List<String>> traces = trace(fileToString(configFile), configFile.getAbsolutePath(), keys); + + stopBubbling = stopBubbling(traces.get(ConfigurationKeys.STOP_BUBBLING)); + for (ConfigurationKey<?> key : keys) { + List<String> modifications = traces.get(key); + if (modifications == null) { + modifications = new ArrayList<String>(); + modifications.add(" <'" + key.getKeyName() + "' not mentioned>"); + } + if (previousFileName != null) { + modifications.add(""); + modifications.add(previousFileName + ":"); + } + result.get(key).addAll(0, modifications); + } + previousFileName = configFile.getAbsolutePath(); + } + for (ConfigurationKey<?> key : keys) { + result.get(key).add(0, previousFileName + (stopBubbling ? " (stop bubbling):" : " (highest found):")); + } + return result; } + + private Map<ConfigurationKey<?>, List<String>> trace(String content, String contentDescription, 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) { + trace(key, "clear " + key.getKeyName(), lineNumber); + } - private String exampleValue(ConfigurationDataType type) { - return type.getParser().exampleValue(); + @Override public void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) { + trace(key, key.getKeyName() + " = " + value, lineNumber); + } + + @Override public void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) { + trace(key, key.getKeyName() + " += " + value, lineNumber); + } + + @Override public void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) { + trace(key, key.getKeyName() + " -= " + value, lineNumber); + } + + private void trace(ConfigurationKey<?> key, String message, int lineNumber) { + if (!keys.contains(key)) return; + List<String> traces = result.get(key); + if (traces == null) { + traces = new ArrayList<String>(); + result.put(key, traces); + } + traces.add(String.format("%4d: %s", lineNumber, message)); + } + }; + new ConfigurationParser(VOID).parse(content, contentDescription, collector); + return result; + } + + private boolean stopBubbling(List<String> stops) { + return stops != null && !stops.isEmpty() && stops.get(stops.size() -1).endsWith("true"); + } + + private Collection<ConfigurationKey<?>> checkKeys(List<String> keyList) { + Map<String, ConfigurationKey<?>> registeredKeys = ConfigurationKey.registeredKeys(); + if (keyList.isEmpty()) return registeredKeys.values(); + + Collection<ConfigurationKey<?>> keys = new ArrayList<ConfigurationKey<?>>(); + for (String keyName : keyList) { + ConfigurationKey<?> key = registeredKeys.get(keyName); + if (key == null) { + System.err.printf("Unknown key '%s'\n", keyName); + return null; + } + keys.remove(key); + keys.add(key); + } + return keys; + } + + private TreeMap<URI, Set<String>> findSharedDirectories(List<String> paths) { + TreeMap<URI,Set<String>> sharedDirectories = new TreeMap<URI, Set<String>>(new Comparator<URI>() { + @Override public int compare(URI o1, URI o2) { + return o1.toString().compareTo(o2.toString()); + } + }); + for (String path : paths) { + File file = new File(path); + if (!file.exists()) { + System.err.printf("File not found: '%s'\n", path); + return null; + } + URI first = findFirstLombokDirectory(file); + Set<String> sharedBy = sharedDirectories.get(first); + if (sharedBy == null) { + sharedBy = new TreeSet<String>(); + sharedDirectories.put(first, sharedBy); + } + sharedBy.add(path); + } + return sharedDirectories; + } + + private URI findFirstLombokDirectory(File file) { + File current = new File(file.toURI().normalize()); + if (file.isFile()) current = current.getParentFile(); + while (current != null) { + if (new File(current, "lombok.config").exists()) return current.toURI(); + current = current.getParentFile(); + } + return NO_CONFIG; } } diff --git a/src/core/lombok/core/configuration/ConfigurationParser.java b/src/core/lombok/core/configuration/ConfigurationParser.java new file mode 100644 index 00000000..e11802ca --- /dev/null +++ b/src/core/lombok/core/configuration/ConfigurationParser.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 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.util.Map; +import java.util.regex.Matcher; +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("^\\s*(.*?)\\s*$", Pattern.MULTILINE); + + private ConfigurationProblemReporter reporter; + + public ConfigurationParser(ConfigurationProblemReporter reporter) { + if (reporter == null) throw new NullPointerException("reporter"); + this.reporter = reporter; + } + + public void parse(CharSequence content, String contentDescription, Collector collector) { + Map<String, ConfigurationKey<?>> registeredKeys = ConfigurationKey.registeredKeys(); + int lineNumber = 0; + Matcher lineMatcher = NEWLINE_FINDER.matcher(content); + 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); + continue; + } + + String operator = null; + String keyName = null; + String stringValue; + if (matcher.group(1) == null) { + keyName = matcher.group(2); + operator = matcher.group(3); + stringValue = matcher.group(4); + } else { + keyName = matcher.group(1); + operator = "clear"; + stringValue = null; + } + ConfigurationKey<?> key = registeredKeys.get(keyName); + if (key == null) { + reporter.report(contentDescription, "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); + continue; + } + if (operator.equals("=") && type.isList()) { + reporter.report(contentDescription, "'" + keyName + "' is a list and cannot be assigned to (use +=, -= and clear instead)", lineNumber, line); + continue; + } + + Object value = null; + 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 a " + type.getParser().description() + ")", lineNumber, line); + continue; + } + + if (operator.equals("clear")) { + collector.clear(key, contentDescription, lineNumber); + } else if (operator.equals("=")) { + collector.set(key, value, contentDescription, lineNumber); + } else if (operator.equals("+=")) { + collector.add(key, value, contentDescription, lineNumber); + } else { + collector.remove(key, value, contentDescription, 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); + } +} diff --git a/src/core/lombok/core/configuration/FileSystemSourceCache.java b/src/core/lombok/core/configuration/FileSystemSourceCache.java index 22d458b6..03e6d338 100644 --- a/src/core/lombok/core/configuration/FileSystemSourceCache.java +++ b/src/core/lombok/core/configuration/FileSystemSourceCache.java @@ -42,9 +42,17 @@ public class FileSystemSourceCache { private final ConcurrentMap<File, Content> cache = new ConcurrentHashMap<File, Content>(); - public Iterable<ConfigurationSource> sourcesForJavaFile(URI javaFile, final ConfigurationProblemReporter reporter) { + public Iterable<ConfigurationSource> sourcesForJavaFile(URI javaFile, ConfigurationProblemReporter reporter) { if (javaFile == null) return Collections.emptyList(); - final File directory = new File(javaFile.normalize()).getParentFile(); + return sourcesForDirectory(new File(javaFile.normalize()).getParentFile(), reporter); + } + + public Iterable<ConfigurationSource> sourcesForDirectory(URI directory, ConfigurationProblemReporter reporter) { + if (directory == null) return Collections.emptyList(); + return sourcesForDirectory(new File(directory.normalize()), reporter); + } + + private Iterable<ConfigurationSource> sourcesForDirectory(final File directory, final ConfigurationProblemReporter reporter) { return new Iterable<ConfigurationSource>() { @Override public Iterator<ConfigurationSource> iterator() { @@ -133,7 +141,7 @@ public class FileSystemSourceCache { } }; - private String fileToString(File configFile) throws Exception { + static String fileToString(File configFile) throws Exception { byte[] b = buffers.get(); FileInputStream fis = new FileInputStream(configFile); try { diff --git a/src/core/lombok/core/configuration/StringConfigurationSource.java b/src/core/lombok/core/configuration/StringConfigurationSource.java index aad3d0c8..dd2f0319 100644 --- a/src/core/lombok/core/configuration/StringConfigurationSource.java +++ b/src/core/lombok/core/configuration/StringConfigurationSource.java @@ -23,77 +23,57 @@ package lombok.core.configuration; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; + +import lombok.core.configuration.ConfigurationParser.Collector; public class StringConfigurationSource implements ConfigurationSource { + private final Map<ConfigurationKey<?>, Result> values; - private static final Pattern LINE = Pattern.compile("(?:clear\\s+([^=]+))|(?:(\\S*?)\\s*([-+]?=)\\s*(.*?))"); - - private final Map<String, Result> values; - - private static final Pattern NEWLINE_FINDER = Pattern.compile("^\\s*(.*?)\\s*$", Pattern.MULTILINE); public static ConfigurationSource forString(CharSequence content, ConfigurationProblemReporter reporter, String contentDescription) { - if (reporter == null) throw new NullPointerException("reporter"); - Map<String, Result> values = new TreeMap<String, Result>(String.CASE_INSENSITIVE_ORDER); + final Map<ConfigurationKey<?>, Result> values = new HashMap<ConfigurationKey<?>, Result>(); - Map<String, ConfigurationKey<?>> registeredKeys = ConfigurationKey.registeredKeys(); - int lineNumber = 0; - Matcher lineMatcher = NEWLINE_FINDER.matcher(content); - 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, "No valid line", lineNumber, line); - continue; + new ConfigurationParser(reporter).parse(content, contentDescription, new Collector() { + @Override public void clear(ConfigurationKey<?> key, String contentDescription, int lineNumber) { + values.put(key, new Result(null, true)); } - String operator = null; - String keyName = null; - String value; - if (matcher.group(1) == null) { - keyName = matcher.group(2); - operator = matcher.group(3); - value = matcher.group(4); - } else { - keyName = matcher.group(1); - operator = "clear"; - value = null; - } - ConfigurationKey<?> key = registeredKeys.get(keyName); - if (key == null) { - reporter.report(contentDescription, "Unknown key '" + keyName + "'", lineNumber, line); - continue; + @Override public void set(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) { + values.put(key, new Result(value, true)); } - 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); - continue; + @Override public void add(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) { + modifyList(key, value, true); } - if (operator.equals("=") && type.isList()) { - reporter.report(contentDescription, "'" + keyName + "' is a list and cannot be assigned to (use +=, -= and clear instead)", lineNumber, line); - continue; + + @Override public void remove(ConfigurationKey<?> key, Object value, String contentDescription, int lineNumber) { + modifyList(key, value, false); } - processResult(values, keyName, operator, value, type, reporter, contentDescription, lineNumber, line); - } + @SuppressWarnings("unchecked") + private void modifyList(ConfigurationKey<?> key, Object value, boolean add) { + Result result = values.get(key); + List<ListModification> list; + if (result == null || result.getValue() == null) { + list = new ArrayList<ConfigurationSource.ListModification>(); + values.put(key, new Result(list, result != null)); + } else { + list = (List<ListModification>) result.getValue(); + } + list.add(new ListModification(value, add)); + } + }); return new StringConfigurationSource(values); } - private StringConfigurationSource(Map<String, Result> values) { - this.values = new TreeMap<String, Result>(String.CASE_INSENSITIVE_ORDER); - for (Entry<String, Result> entry : values.entrySet()) { + private StringConfigurationSource(Map<ConfigurationKey<?>, Result> values) { + this.values = new HashMap<ConfigurationKey<?>, Result>(); + for (Entry<ConfigurationKey<?>, Result> entry : values.entrySet()) { Result result = entry.getValue(); if (result.getValue() instanceof List<?>) { this.values.put(entry.getKey(), new Result(Collections.unmodifiableList((List<?>) result.getValue()), result.isAuthoritative())); @@ -103,31 +83,8 @@ public class StringConfigurationSource implements ConfigurationSource { } } - private static void processResult(Map<String, Result> values, String keyName, String operator, String value, ConfigurationDataType type, ConfigurationProblemReporter reporter, String contentDescription, int lineNumber, CharSequence line) { - Object element = null; - if (value != null) try { - element = type.getParser().parse(value); - } catch (Exception e) { - reporter.report(contentDescription, "Error while parsing the value for '" + keyName + "' value '" + value + "' (should be a " + type.getParser().description() + ")", lineNumber, line); - return; - } - - if (operator.equals("clear") || operator.equals("=")) { - if (element == null && type.isList()) { - element = new ArrayList<ListModification>(); - } - values.put(keyName, new Result(element, true)); - } else { - Result result = values.get(keyName); - @SuppressWarnings("unchecked") - List<ListModification> list = result == null ? new ArrayList<ListModification>() : (List<ListModification>) result.getValue(); - if (result == null) values.put(keyName, new Result(list, false)); - list.add(new ListModification(element, operator.equals("+="))); - } - } - @Override public Result resolve(ConfigurationKey<?> key) { - return values.get(key.getKeyName()); + return values.get(key); } } diff --git a/src/core/lombok/eclipse/handlers/HandlePrintConfiguration.java b/src/core/lombok/eclipse/handlers/HandlePrintConfiguration.java deleted file mode 100644 index e2bae525..00000000 --- a/src/core/lombok/eclipse/handlers/HandlePrintConfiguration.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2014 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.eclipse.handlers; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintStream; - -import lombok.Lombok; -import lombok.core.AnnotationValues; -import lombok.core.LombokConfiguration; -import lombok.core.PrintConfiguration; -import lombok.eclipse.EclipseAnnotationHandler; -import lombok.eclipse.EclipseNode; - -import org.eclipse.jdt.internal.compiler.ast.Annotation; -import org.mangosdk.spi.ProviderFor; - -/** - * Handles the {@code lombok.core.PrintConfiguration} annotation for eclipse. - */ -@ProviderFor(EclipseAnnotationHandler.class) -public class HandlePrintConfiguration extends EclipseAnnotationHandler<PrintConfiguration> { - public void handle(AnnotationValues<PrintConfiguration> annotation, Annotation ast, EclipseNode annotationNode) { - PrintStream stream = System.out; - String fileName = annotation.getInstance().outfile(); - if (fileName.length() > 0) try { - stream = new PrintStream(new File(fileName)); - } catch (FileNotFoundException e) { - Lombok.sneakyThrow(e); - } - try { - LombokConfiguration.writeConfiguration(annotationNode.getAst(), stream); - } finally { - if (stream != System.out) { - try { - stream.close(); - } catch (Exception e) { - Lombok.sneakyThrow(e); - } - } - } - } -} diff --git a/src/core/lombok/javac/handlers/HandlePrintConfiguration.java b/src/core/lombok/javac/handlers/HandlePrintConfiguration.java deleted file mode 100644 index dd0ef839..00000000 --- a/src/core/lombok/javac/handlers/HandlePrintConfiguration.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2014 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.javac.handlers; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintStream; - -import lombok.Lombok; -import lombok.core.AnnotationValues; -import lombok.core.LombokConfiguration; -import lombok.core.PrintConfiguration; -import lombok.javac.JavacAnnotationHandler; -import lombok.javac.JavacNode; - -import org.mangosdk.spi.ProviderFor; - -import com.sun.tools.javac.tree.JCTree.JCAnnotation; - -/** - * Handles the {@code lombok.core.PrintConfiguration} annotation for javac. - */ -@ProviderFor(JavacAnnotationHandler.class) -public class HandlePrintConfiguration extends JavacAnnotationHandler<PrintConfiguration> { - @Override public void handle(AnnotationValues<PrintConfiguration> annotation, JCAnnotation ast, JavacNode annotationNode) { - PrintStream stream = System.out; - String fileName = annotation.getInstance().outfile(); - if (fileName.length() > 0) try { - stream = new PrintStream(new File(fileName)); - } catch (FileNotFoundException e) { - Lombok.sneakyThrow(e); - } - - try { - LombokConfiguration.writeConfiguration(annotationNode.getAst(), stream); - } finally { - if (stream != System.out) { - try { - stream.close(); - } catch (Exception e) { - Lombok.sneakyThrow(e); - } - } - } - } -} |