diff options
author | Roel Spilker <r.spilker@gmail.com> | 2020-01-17 02:40:10 +0100 |
---|---|---|
committer | Roel Spilker <r.spilker@gmail.com> | 2020-01-20 14:11:21 +0100 |
commit | 04523763dff98206487b2e358697226ac7b87fd7 (patch) | |
tree | 8ca871b92f6ed22b8fe843b66b3d8d7c66c1e633 /src/core | |
parent | 290edf95275f82e674952b21d27b9f485f5a2418 (diff) | |
download | lombok-04523763dff98206487b2e358697226ac7b87fd7.tar.gz lombok-04523763dff98206487b2e358697226ac7b87fd7.tar.bz2 lombok-04523763dff98206487b2e358697226ac7b87fd7.zip |
Config import: support .jar and .zip archives
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/lombok/core/configuration/ConfigurationFile.java | 154 |
1 files changed, 140 insertions, 14 deletions
diff --git a/src/core/lombok/core/configuration/ConfigurationFile.java b/src/core/lombok/core/configuration/ConfigurationFile.java index 218fa73b..bb15d177 100644 --- a/src/core/lombok/core/configuration/ConfigurationFile.java +++ b/src/core/lombok/core/configuration/ConfigurationFile.java @@ -26,6 +26,11 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public abstract class ConfigurationFile { private static final String LOMBOK_CONFIG_FILENAME = "lombok.config"; @@ -64,12 +69,12 @@ public abstract class ConfigurationFile { return identifier; } - @Override public boolean equals(Object obj) { + @Override public final boolean equals(Object obj) { if (!(obj instanceof ConfigurationFile)) return false; return identifier.equals(((ConfigurationFile)obj).identifier); } - @Override public int hashCode() { + @Override public final int hashCode() { return identifier.hashCode(); } @@ -84,17 +89,13 @@ public abstract class ConfigurationFile { 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(); + 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"); } private static class RegularConfigurationFile extends ConfigurationFile { @@ -110,7 +111,22 @@ public abstract class ConfigurationFile { } public ConfigurationFile resolve(String path) { - File file = resolveFile(path); + if (path.endsWith("!")) return null; + + String[] parts = path.split("!"); + if (parts.length > 2) return null; + + String realFileName = parts[0]; + File file = resolveFile(realFileName); + if (realFileName.endsWith(".zip") || realFileName.endsWith(".jar")) { + try { + return ArchivedConfigurationFile.create(file, URI.create(parts.length == 1 ? LOMBOK_CONFIG_FILENAME : parts[1])); + } catch (Exception e) { + return null; + } + } + + if (parts.length > 1) return null; return file == null ? null : forFile(file); } @@ -138,7 +154,12 @@ public abstract class ConfigurationFile { @Override CharSequence contents() throws IOException { - return read(new FileInputStream(file)); + FileInputStream is = new FileInputStream(file); + try { + return read(is); + } finally { + is.close(); + } } @Override ConfigurationFile parent() { @@ -147,6 +168,111 @@ public abstract class ConfigurationFile { } } + private static class ArchivedConfigurationFile extends ConfigurationFile { + private static final URI ROOT1 = URI.create("http://x.y/a/"); + private static final URI ROOT2 = URI.create("ftp://y.x/b/"); + + private static final ConcurrentMap<String, Object> locks = new ConcurrentHashMap<String, Object>(); + + private final File archive; + private final URI file; + private final Object lock; + private long lastModified = -2; + private String contents; + + public static ConfigurationFile create(File archive, URI file) { + if (!isRelative(file)) return null; + return new ArchivedConfigurationFile(archive, file, archive.getPath() + "!" + file.getPath()); + } + + static boolean isRelative(URI path) { + try { + return ROOT1.resolve(path).toString().startsWith(ROOT1.toString()) && ROOT2.resolve(path).toString().startsWith(ROOT2.toString()); + } catch (Exception e) { + return false; + } + } + + ArchivedConfigurationFile(File archive, URI file, String description) { + super(description); + this.archive = archive; + this.file = file; + locks.putIfAbsent(archive.getPath(), new Object()); + this.lock = locks.get(archive.getPath()); + } + + @Override + long getLastModifiedOrMissing() { + return getLastModifiedOrMissing(archive); + } + + @Override + boolean exists() { + if (!fileExists(archive)) return false; + synchronized (lock) { + try { + readIfNeccesary(); + return contents != null; + } catch (Exception e) { + return false; + } + } + } + + @Override + CharSequence contents() throws IOException { + synchronized (lock) { + readIfNeccesary(); + return contents; + } + } + + void readIfNeccesary() throws IOException { + long archiveModified = getLastModifiedOrMissing(); + if (archiveModified == lastModified) return; + contents = null; + lastModified = archiveModified; + if (archiveModified == FileSystemSourceCache.MISSING) return; + contents = read(); + } + + private String read() throws IOException { + FileInputStream is = new FileInputStream(archive); + try { + ZipInputStream zip = new ZipInputStream(is); + try { + while (true) { + ZipEntry entry = zip.getNextEntry(); + if (entry == null) return null; + if (entry.getName().equals(file.getPath())) { + return read(zip); + } + } + } finally { + zip.close(); + } + } finally { + is.close(); + } + } + + @Override + public ConfigurationFile resolve(String path) { + try { + URI resolved = file.resolve(path); + if (!isRelative(resolved)) return null; + return create(archive, resolved); + } catch (Exception e) { + return null; + } + } + + @Override + ConfigurationFile parent() { + return null; + } + } + private static class CharSequenceConfigurationFile extends ConfigurationFile { private final CharSequence contents; private final long lastModified; |