aboutsummaryrefslogtreecommitdiff
path: root/src/installer/lombok
diff options
context:
space:
mode:
authorReinier Zwitserloot <reinier@tipit.to>2009-11-25 07:32:49 +0100
committerReinier Zwitserloot <reinier@tipit.to>2009-11-25 07:32:49 +0100
commit1a0e611a9c5e1ee518670647ce1a44beae559b44 (patch)
treee5ef8f671bc6688f486e874d4e2e1a7813e4f0b2 /src/installer/lombok
parent7fd947ea40c25dad9ee543ebc4b92de9a2e05efc (diff)
downloadlombok-1a0e611a9c5e1ee518670647ce1a44beae559b44.tar.gz
lombok-1a0e611a9c5e1ee518670647ce1a44beae559b44.tar.bz2
lombok-1a0e611a9c5e1ee518670647ce1a44beae559b44.zip
Refactored the source folders.
Diffstat (limited to 'src/installer/lombok')
-rw-r--r--src/installer/lombok/installer/AppleNativeLook.java43
-rw-r--r--src/installer/lombok/installer/EclipseFinder.java325
-rw-r--r--src/installer/lombok/installer/EclipseLocation.java474
-rw-r--r--src/installer/lombok/installer/Installer.java895
-rw-r--r--src/installer/lombok/installer/WindowsDriveInfo-i386.dllbin0 -> 14472 bytes
-rw-r--r--src/installer/lombok/installer/WindowsDriveInfo-x86_64.dllbin0 -> 66806 bytes
-rw-r--r--src/installer/lombok/installer/WindowsDriveInfo.java127
-rw-r--r--src/installer/lombok/installer/loading.gifbin0 -> 2248 bytes
-rw-r--r--src/installer/lombok/installer/lombok.pngbin0 -> 24994 bytes
-rw-r--r--src/installer/lombok/installer/lombok.svg181
-rw-r--r--src/installer/lombok/installer/lombokIcon.pngbin0 -> 788 bytes
-rw-r--r--src/installer/lombok/installer/lombokText.pngbin0 -> 3055 bytes
-rw-r--r--src/installer/lombok/installer/lombokText.svg67
-rw-r--r--src/installer/lombok/installer/package-info.java28
14 files changed, 2140 insertions, 0 deletions
diff --git a/src/installer/lombok/installer/AppleNativeLook.java b/src/installer/lombok/installer/AppleNativeLook.java
new file mode 100644
index 00000000..6e64032e
--- /dev/null
+++ b/src/installer/lombok/installer/AppleNativeLook.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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.installer;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Mac OS X specific code to gussy up the GUI a little bit, mostly with a nice dock icon. Well, nicer than
+ * the standard icon, at any rate.
+ */
+class AppleNativeLook {
+ public static void go() throws Exception {
+ Class<?> appClass = Class.forName("com.apple.eawt.Application");
+ Object app = appClass.getMethod("getApplication").invoke(null);
+ appClass.getMethod("removeAboutMenuItem").invoke(app);
+ appClass.getMethod("removePreferencesMenuItem").invoke(app);
+
+ BufferedImage image = ImageIO.read(AppleNativeLook.class.getResource("lombokIcon.png"));
+ appClass.getMethod("setDockIconImage", Image.class).invoke(app, image);
+ }
+}
diff --git a/src/installer/lombok/installer/EclipseFinder.java b/src/installer/lombok/installer/EclipseFinder.java
new file mode 100644
index 00000000..8e45852c
--- /dev/null
+++ b/src/installer/lombok/installer/EclipseFinder.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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.installer;
+
+import static java.util.Arrays.asList;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import lombok.Lombok;
+import lombok.core.Version;
+import lombok.installer.EclipseLocation.NotAnEclipseException;
+
+/** Utility class for doing various OS-specific operations related to finding Eclipse installations. */
+class EclipseFinder {
+ private EclipseFinder() {
+ //Prevent instantiation.
+ }
+
+ /**
+ * Returns a File object pointing to our own jar file. Will obviously fail if the installer was started via
+ * a jar that wasn't accessed via the file-system, or if its started via e.g. unpacking the jar.
+ */
+ static File findOurJar() {
+ try {
+ URI uri = EclipseFinder.class.getResource("/" + EclipseFinder.class.getName().replace('.', '/') + ".class").toURI();
+ Pattern p = Pattern.compile("^jar:file:([^\\!]+)\\!.*\\.class$");
+ Matcher m = p.matcher(uri.toString());
+ if (!m.matches()) return new File("lombok.jar");
+ String rawUri = m.group(1);
+ return new File(URLDecoder.decode(rawUri, Charset.defaultCharset().name()));
+ } catch (Exception e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ }
+
+ private static final AtomicBoolean windowsDriveInfoLibLoaded = new AtomicBoolean(false);
+ private static void loadWindowsDriveInfoLib() throws IOException {
+ if (!windowsDriveInfoLibLoaded.compareAndSet(false, true)) return;
+
+ final String prefix = "lombok-" + Version.getVersion() + "-";
+
+ File temp = File.createTempFile("lombok", ".mark");
+ File dll1 = new File(temp.getParentFile(), prefix + "WindowsDriveInfo-i386.dll");
+ File dll2 = new File(temp.getParentFile(), prefix + "WindowsDriveInfo-x86_64.dll");
+ temp.delete();
+ dll1.deleteOnExit();
+ dll2.deleteOnExit();
+ try {
+ if (unpackDLL("WindowsDriveInfo-i386.dll", dll1)) {
+ System.load(dll1.getAbsolutePath());
+ return;
+ }
+ } catch (Throwable ignore) {}
+
+ try {
+ if (unpackDLL("WindowsDriveInfo-x86_64.dll", dll2)) {
+ System.load(dll2.getAbsolutePath());
+ }
+ } catch (Throwable ignore) {}
+ }
+
+ private static boolean unpackDLL(String dllName, File target) throws IOException {
+ InputStream in = EclipseFinder.class.getResourceAsStream(dllName);
+ try {
+ try {
+ FileOutputStream out = new FileOutputStream(target);
+ try {
+ byte[] b = new byte[32000];
+ while (true) {
+ int r = in.read(b);
+ if (r == -1) break;
+ out.write(b, 0, r);
+ }
+ } finally {
+ out.close();
+ }
+ } catch (IOException e) {
+ //Fall through - if there is a file named lombok-WindowsDriveInfo-arch.dll, we'll try it.
+ return target.exists() && target.canRead();
+ }
+ } finally {
+ in.close();
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns all drive letters on windows, regardless of what kind of drive is represented.
+ *
+ * @return A List of drive letters, such as ["A", "C", "D", "X"].
+ */
+ static List<String> getDrivesOnWindows() throws Throwable {
+ loadWindowsDriveInfoLib();
+
+ List<String> drives = new ArrayList<String>();
+
+ WindowsDriveInfo info = new WindowsDriveInfo();
+ for (String drive : info.getLogicalDrives()) {
+ if (info.isFixedDisk(drive)) drives.add(drive);
+ }
+
+ return drives;
+ }
+
+ /**
+ * Returns a list of paths of Eclipse installations.
+ * Eclipse installations are found by checking for the existence of 'eclipse.exe' in the following locations:
+ * <ul>
+ * <li>X:\*Program Files*\*Eclipse*</li>
+ * <li>X:\*Eclipse*</li>
+ * </ul>
+ *
+ * Where 'X' is tried for all local disk drives, unless there's a problem calling fsutil, in which case only
+ * C: is tried.
+ */
+ private static void findEclipseOnWindows(List<EclipseLocation> locations, List<NotAnEclipseException> problems) {
+ List<String> driveLetters = asList("C");
+ try {
+ driveLetters = getDrivesOnWindows();
+ } catch (Throwable ignore) {
+ ignore.printStackTrace();
+ }
+
+ //Various try/catch/ignore statements are in this for loop. Weird conditions on the disk can cause exceptions,
+ //such as an unformatted drive causing a NullPointerException on listFiles. Best action is almost invariably to just
+ //continue onwards.
+ for (String letter : driveLetters) {
+ try {
+ File f = new File(letter + ":\\");
+ for (File dir : f.listFiles()) {
+ if (!dir.isDirectory()) continue;
+ try {
+ if (dir.getName().toLowerCase().contains("eclipse")) {
+ String eclipseLocation = findEclipseOnWindows1(dir);
+ if (eclipseLocation != null) {
+ try {
+ locations.add(EclipseLocation.create(eclipseLocation));
+ } catch (NotAnEclipseException e) {
+ problems.add(e);
+ }
+ }
+ }
+ } catch (Exception ignore) {}
+
+ try {
+ if (dir.getName().toLowerCase().contains("program files")) {
+ for (File dir2 : dir.listFiles()) {
+ if (!dir2.isDirectory()) continue;
+ if (dir.getName().toLowerCase().contains("eclipse")) {
+ String eclipseLocation = findEclipseOnWindows1(dir);
+ if (eclipseLocation != null) {
+ try {
+ locations.add(EclipseLocation.create(eclipseLocation));
+ } catch (NotAnEclipseException e) {
+ problems.add(e);
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception ignore) {}
+ }
+ } catch (Exception ignore) {}
+ }
+ }
+
+ /** Checks if the provided directory contains 'eclipse.exe', and if so, returns the directory, otherwise null. */
+ private static String findEclipseOnWindows1(File dir) {
+ if (new File(dir, "eclipse.exe").isFile()) return dir.getAbsolutePath();
+ return null;
+ }
+
+ /**
+ * Calls the OS-dependent 'find Eclipse' routine. If the local OS doesn't have a routine written for it,
+ * null is returned.
+ *
+ * @param locations
+ * List of valid eclipse locations - provide an empty list; this
+ * method will fill it.
+ * @param problems
+ * List of eclipse locations that seem to contain half-baked
+ * eclipses that can't be installed. Provide an empty list; this
+ * method will fill it.
+ */
+ static void findEclipses(List<EclipseLocation> locations, List<NotAnEclipseException> problems) {
+ switch (getOS()) {
+ case WINDOWS:
+ findEclipseOnWindows(locations, problems);
+ break;
+ case MAC_OS_X:
+ findEclipseOnMac(locations, problems);
+ break;
+ default:
+ case UNIX:
+ findEclipseOnUnix(locations, problems);
+ break;
+ }
+ }
+
+ static enum OS {
+ MAC_OS_X, WINDOWS, UNIX;
+ }
+
+ static OS getOS() {
+ String prop = System.getProperty("os.name", "").toLowerCase();
+ if (prop.matches("^.*\\bmac\\b.*$")) return OS.MAC_OS_X;
+ if (prop.matches("^.*\\bdarwin\\b.*$")) return OS.MAC_OS_X;
+ if (prop.matches("^.*\\bwin(dows)\\b.*$")) return OS.WINDOWS;
+
+ return OS.UNIX;
+ }
+
+ /**
+ * Returns the proper name of the executable for the local OS.
+ *
+ * @return 'Eclipse.app' on OS X, 'eclipse.exe' on Windows, and 'eclipse' on other OSes.
+ */
+ static String getEclipseExecutableName() {
+ switch (getOS()) {
+ case WINDOWS:
+ return "eclipse.exe";
+ case MAC_OS_X:
+ return "Eclipse.app";
+ default:
+ case UNIX:
+ return "eclipse";
+ }
+ }
+
+ /** Scans a couple of likely locations on linux. */
+ private static void findEclipseOnUnix(List<EclipseLocation> locations, List<NotAnEclipseException> problems) {
+ List<String> guesses = new ArrayList<String>();
+
+ File d;
+
+ d = new File("/usr/bin/eclipse");
+ if (d.exists()) guesses.add(d.getPath());
+ d = new File("/usr/local/bin/eclipse");
+ if (d.exists()) guesses.add(d.getPath());
+ d = new File(System.getProperty("user.home", "."), "bin/eclipse");
+ if (d.exists()) guesses.add(d.getPath());
+
+ findEclipseInSubDir("/usr/local/share", guesses);
+ findEclipseInSubDir("/usr/local", guesses);
+ findEclipseInSubDir("/usr/share", guesses);
+ findEclipseInSubDir(System.getProperty("user.home", "."), guesses);
+
+ for (String guess : guesses) {
+ try {
+ locations.add(EclipseLocation.create(guess));
+ } catch (NotAnEclipseException e) {
+ problems.add(e);
+ }
+ }
+ }
+
+ private static void findEclipseInSubDir(String dir, List<String> guesses) {
+ File d = new File(dir);
+ if (!d.isDirectory()) return;
+ for (File f : d.listFiles()) {
+ if (f.isDirectory() && f.getName().toLowerCase().contains("eclipse")) {
+ File possible = new File(f, "eclipse");
+ if (possible.exists()) guesses.add(possible.getAbsolutePath());
+ }
+ }
+ }
+
+ /**
+ * Scans /Applications for any folder named 'Eclipse'
+ */
+ private static void findEclipseOnMac(List<EclipseLocation> locations, List<NotAnEclipseException> problems) {
+ for (File dir : new File("/Applications").listFiles()) {
+ if (!dir.isDirectory()) continue;
+ if (dir.getName().toLowerCase().equals("eclipse.app")) {
+ //This would be kind of an unorthodox Eclipse installation, but if Eclipse ever
+ //moves to this more maclike installation concept, our installer can still handle it.
+ try {
+ locations.add(EclipseLocation.create("/Applications"));
+ } catch (NotAnEclipseException e) {
+ problems.add(e);
+ }
+ }
+ if (dir.getName().toLowerCase().contains("eclipse")) {
+ if (new File(dir, "Eclipse.app").exists()) {
+ try {
+ locations.add(EclipseLocation.create(dir.toString()));
+ } catch (NotAnEclipseException e) {
+ problems.add(e);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/installer/lombok/installer/EclipseLocation.java b/src/installer/lombok/installer/EclipseLocation.java
new file mode 100644
index 00000000..c43c5042
--- /dev/null
+++ b/src/installer/lombok/installer/EclipseLocation.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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.installer;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+/**
+ * Represents an Eclipse installation.
+ * An instance can figure out if an Eclipse installation has been lombok-ified, and can
+ * install and uninstall lombok from the Eclipse installation.
+ */
+final class EclipseLocation {
+ private static final String OS_NEWLINE;
+
+ static {
+ String os = System.getProperty("os.name", "");
+
+ if ("Mac OS".equals(os)) OS_NEWLINE = "\r";
+ else if (os.toLowerCase().contains("windows")) OS_NEWLINE = "\r\n";
+ else OS_NEWLINE = "\n";
+ }
+
+ private final String name;
+ private final File eclipseIniPath;
+ private volatile boolean hasLombok;
+
+ /** Toggling the 'selected' checkbox in the GUI is tracked via this boolean */
+ boolean selected = true;
+
+ /**
+ * Thrown when creating a new EclipseLocation with a path object that doesn't, in fact,
+ * point at an Eclipse installation.
+ */
+ static final class NotAnEclipseException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public NotAnEclipseException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Renders a message dialog with information about what went wrong.
+ */
+ void showDialog(JFrame appWindow) {
+ JOptionPane.showMessageDialog(appWindow, getMessage(), "Cannot configure Eclipse installation", JOptionPane.WARNING_MESSAGE);
+ }
+ }
+
+ private EclipseLocation(String nameOfLocation, File pathToEclipseIni) throws NotAnEclipseException {
+ this.name = nameOfLocation;
+ this.eclipseIniPath = pathToEclipseIni;
+ try {
+ this.hasLombok = checkForLombok(eclipseIniPath);
+ } catch (IOException e) {
+ throw new NotAnEclipseException(
+ "I can't read the configuration file of the Eclipse installed at " + name + "\n" +
+ "You may need to run this installer with root privileges if you want to modify that Eclipse.", e);
+ }
+ }
+
+ private static final List<String> eclipseExecutableNames = Collections.unmodifiableList(Arrays.asList(
+ "eclipse.app", "eclipse.exe", "eclipse"));
+
+ /**
+ * Create a new EclipseLocation by pointing at either the directory contain the Eclipse executable, or the executable itself,
+ * or an eclipse.ini file.
+ *
+ * @throws NotAnEclipseException
+ * If this isn't an Eclipse executable or a directory with an
+ * Eclipse executable.
+ */
+ public static EclipseLocation create(String path) throws NotAnEclipseException {
+ if (path == null) throw new NullPointerException("path");
+ File p = new File(path);
+
+ if (!p.exists()) throw new NotAnEclipseException("File does not exist: " + path, null);
+ if (p.isDirectory()) {
+ for (String possibleExeName : eclipseExecutableNames) {
+ File f = new File(p, possibleExeName);
+ if (f.exists()) return findEclipseIniFromExe(f, 0);
+ }
+
+ File f = new File(p, "eclipse.ini");
+ if (f.exists()) return new EclipseLocation(getFilePath(p), f);
+ }
+
+ if (p.isFile()) {
+ if (p.getName().equalsIgnoreCase("eclipse.ini")) {
+ return new EclipseLocation(getFilePath(p.getParentFile()), p);
+ }
+
+ if (eclipseExecutableNames.contains(p.getName().toLowerCase())) {
+ return findEclipseIniFromExe(p, 0);
+ }
+ }
+
+ throw new NotAnEclipseException("This path does not appear to contain an Eclipse installation: " + p, null);
+ }
+
+ private static EclipseLocation findEclipseIniFromExe(File exePath, int loopCounter) throws NotAnEclipseException {
+ /* Try looking for eclipse.ini as sibling to the executable */ {
+ File ini = new File(exePath.getParentFile(), "eclipse.ini");
+ if (ini.isFile()) return new EclipseLocation(getFilePath(exePath), ini);
+ }
+
+ /* Try looking for Eclipse/app/Contents/MacOS/eclipse.ini as sibling to executable; this works on Mac OS X. */ {
+ File ini = new File(exePath.getParentFile(), "Eclipse.app/Contents/MacOS/eclipse.ini");
+ if (ini.isFile()) return new EclipseLocation(getFilePath(exePath), ini);
+ }
+
+ /* If executable is a soft link, follow it and retry. */ {
+ if (loopCounter < 50) {
+ try {
+ String oPath = exePath.getAbsolutePath();
+ String nPath = exePath.getCanonicalPath();
+ if (!oPath.equals(nPath)) try {
+ return findEclipseIniFromExe(new File(nPath), loopCounter + 1);
+ } catch (NotAnEclipseException ignore) {
+ // Unlinking didn't help find an eclipse, so continue.
+ }
+ } catch (IOException ignore) { /* okay, that didn't work, assume it isn't a soft link then. */ }
+ }
+ }
+
+ /* If executable is a linux LSB-style path, then look in the usual places that package managers like apt-get use.*/ {
+ String path = exePath.getAbsolutePath();
+ try {
+ path = exePath.getCanonicalPath();
+ } catch (IOException ignore) { /* We'll stick with getAbsolutePath()'s result then. */ }
+
+ if (path.equals("/usr/bin/eclipse") || path.equals("/bin/eclipse") || path.equals("/usr/local/bin/eclipse")) {
+ File ini = new File("/usr/lib/eclipse/eclipse.ini");
+ if (ini.isFile()) return new EclipseLocation(path, ini);
+ ini = new File("/usr/local/lib/eclipse/eclipse.ini");
+ if (ini.isFile()) return new EclipseLocation(path, ini);
+ ini = new File("/usr/local/etc/eclipse/eclipse.ini");
+ if (ini.isFile()) return new EclipseLocation(path, ini);
+ ini = new File("/etc/eclipse.ini");
+ if (ini.isFile()) return new EclipseLocation(path, ini);
+ }
+ }
+
+ /* If we get this far, we lose. */
+ throw new NotAnEclipseException("This path does not appear to contain an eclipse installation: " + exePath, null);
+ }
+
+ public static String getFilePath(File p) {
+ try {
+ return p.getCanonicalPath();
+ } catch (IOException e) {
+ String x = p.getAbsolutePath();
+ return x == null ? p.getPath() : x;
+ }
+ }
+
+ @Override public int hashCode() {
+ return eclipseIniPath.hashCode();
+ }
+
+ @Override public boolean equals(Object o) {
+ if (!(o instanceof EclipseLocation)) return false;
+ return ((EclipseLocation)o).eclipseIniPath.equals(eclipseIniPath);
+ }
+
+ /**
+ * Returns the name of this location; generally the path to the eclipse executable.
+ *
+ * Executables: "eclipse.exe" (Windows), "Eclipse.app" (Mac OS X), "eclipse" (Linux and other unixes).
+ */
+ String getName() {
+ return name;
+ }
+
+ /**
+ * @return true if the Eclipse installation has been instrumented with lombok.
+ */
+ boolean hasLombok() {
+ return hasLombok;
+ }
+
+ private final Pattern JAVA_AGENT_LINE_MATCHER = Pattern.compile(
+ "^\\-javaagent\\:.*lombok.*\\.jar$", Pattern.CASE_INSENSITIVE);
+
+ private final Pattern BOOTCLASSPATH_LINE_MATCHER = Pattern.compile(
+ "^\\-Xbootclasspath\\/a\\:(.*lombok.*\\.jar.*)$", Pattern.CASE_INSENSITIVE);
+
+ private boolean checkForLombok(File iniFile) throws IOException {
+ if (!iniFile.exists()) return false;
+ FileInputStream fis = new FileInputStream(iniFile);
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (JAVA_AGENT_LINE_MATCHER.matcher(line.trim()).matches()) return true;
+ }
+
+ return false;
+ } finally {
+ fis.close();
+ }
+ }
+
+ /** Thrown when uninstalling lombok fails. */
+ static class UninstallException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public UninstallException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ /** Returns directories that may contain lombok.jar files that need to be deleted. */
+ private List<File> getUninstallDirs() {
+ List<File> result = new ArrayList<File>();
+ File x = new File(name);
+ if (!x.isDirectory()) x = x.getParentFile();
+ if (x.isDirectory()) result.add(x);
+ result.add(eclipseIniPath.getParentFile());
+ return result;
+ }
+
+ /**
+ * Uninstalls lombok from this location.
+ * It's a no-op if lombok wasn't there in the first place,
+ * and it will remove a half-succeeded lombok installation as well.
+ *
+ * @throws UninstallException
+ * If there's an obvious I/O problem that is preventing
+ * installation. bugs in the uninstall code will probably throw
+ * other exceptions; this is intentional.
+ */
+ void uninstall() throws UninstallException {
+ for (File dir : getUninstallDirs()) {
+ File lombokJar = new File(dir, "lombok.jar");
+ if (lombokJar.exists()) {
+ if (!lombokJar.delete()) throw new UninstallException(
+ "Can't delete " + lombokJar.getAbsolutePath() + generateWriteErrorMessage(), null);
+ }
+
+ /* legacy code - lombok at one point used to have a separate jar for the eclipse agent.
+ * Leave this code in to delete it for those upgrading from an old version. */ {
+ File agentJar = new File(dir, "lombok.eclipse.agent.jar");
+ if (agentJar.exists()) {
+ if (!agentJar.delete()) throw new UninstallException(
+ "Can't delete " + agentJar.getAbsolutePath() + generateWriteErrorMessage(), null);
+ }
+ }
+ }
+
+ StringBuilder newContents = new StringBuilder();
+ if (eclipseIniPath.exists()) {
+ try {
+ FileInputStream fis = new FileInputStream(eclipseIniPath);
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (JAVA_AGENT_LINE_MATCHER.matcher(line).matches()) continue;
+ Matcher m = BOOTCLASSPATH_LINE_MATCHER.matcher(line);
+ if (m.matches()) {
+ StringBuilder elemBuilder = new StringBuilder();
+ elemBuilder.append("-Xbootclasspath/a:");
+ boolean first = true;
+ for (String elem : m.group(1).split(Pattern.quote(File.pathSeparator))) {
+ if (elem.toLowerCase().endsWith("lombok.jar")) continue;
+ /* legacy code -see previous comment that starts with 'legacy' */ {
+ if (elem.toLowerCase().endsWith("lombok.eclipse.agent.jar")) continue;
+ }
+ if (first) first = false;
+ else elemBuilder.append(File.pathSeparator);
+ elemBuilder.append(elem);
+ }
+ if (!first) newContents.append(elemBuilder.toString()).append(OS_NEWLINE);
+ continue;
+ }
+
+ newContents.append(line).append(OS_NEWLINE);
+ }
+
+ } finally {
+ fis.close();
+ }
+
+ FileOutputStream fos = new FileOutputStream(eclipseIniPath);
+ try {
+ fos.write(newContents.toString().getBytes());
+ } finally {
+ fos.close();
+ }
+ } catch (IOException e) {
+ throw new UninstallException("Cannot uninstall lombok from " + name + generateWriteErrorMessage(), e);
+ }
+ }
+ }
+
+ /** Thrown when installing lombok fails. */
+ static class InstallException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public InstallException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+
+ private static String generateWriteErrorMessage() {
+ String osSpecificError;
+
+ switch (EclipseFinder.getOS()) {
+ default:
+ case MAC_OS_X:
+ case UNIX:
+ osSpecificError = ":\nStart terminal, go to the directory with lombok.jar, and run: sudo java -jar lombok.jar";
+ break;
+ case WINDOWS:
+ osSpecificError = ":\nStart a new cmd (dos box) with admin privileges, go to the directory with lombok.jar, and run: java -jar lombok.jar";
+ break;
+ }
+
+ return ", probably because this installer does not have the access rights.\n" +
+ "Try re-running the installer with administrative privileges" + osSpecificError;
+ }
+
+ /**
+ * Install lombok into the Eclipse at this location.
+ * If lombok is already there, it is overwritten neatly (upgrade mode).
+ *
+ * @throws InstallException
+ * If there's an obvious I/O problem that is preventing
+ * installation. bugs in the install code will probably throw
+ * other exceptions; this is intentional.
+ */
+ void install() throws InstallException {
+ // For whatever reason, relative paths in your eclipse.ini file don't work on linux, but only for -javaagent.
+ // If someone knows how to fix this, please do so, as this current hack solution (putting the absolute path
+ // to the jar files in your eclipse.ini) means you can't move your eclipse around on linux without lombok
+ // breaking it. NB: rerunning lombok.jar installer and hitting 'update' will fix it if you do that.
+ boolean fullPathRequired = EclipseFinder.getOS() == EclipseFinder.OS.UNIX;
+
+ boolean installSucceeded = false;
+ StringBuilder newContents = new StringBuilder();
+ //If 'installSucceeded' is true here, something very weird is going on, but instrumenting all of them
+ //is no less bad than aborting, and this situation should be rare to the point of non-existence.
+
+ File lombokJar = new File(eclipseIniPath.getParentFile(), "lombok.jar");
+
+ File ourJar = EclipseFinder.findOurJar();
+ byte[] b = new byte[524288];
+ boolean readSucceeded = true;
+ try {
+ FileOutputStream out = new FileOutputStream(lombokJar);
+ try {
+ readSucceeded = false;
+ InputStream in = new FileInputStream(ourJar);
+ try {
+ while (true) {
+ int r = in.read(b);
+ if (r == -1) break;
+ if (r > 0) readSucceeded = true;
+ out.write(b, 0, r);
+ }
+ } finally {
+ in.close();
+ }
+ } finally {
+ out.close();
+ }
+ } catch (IOException e) {
+ try {
+ lombokJar.delete();
+ } catch (Throwable ignore) { /* Nothing we can do about that. */ }
+ if (!readSucceeded) throw new InstallException(
+ "I can't read my own jar file. I think you've found a bug in this installer!\nI suggest you restart it " +
+ "and use the 'what do I do' link, to manually install lombok. Also, tell us about this at:\n" +
+ "http://groups.google.com/group/project-lombok - Thanks!", e);
+ throw new InstallException("I can't write to your Eclipse directory at " + name + generateWriteErrorMessage(), e);
+ }
+
+ /* legacy - delete lombok.eclipse.agent.jar if its there, which lombok no longer uses. */ {
+ new File(lombokJar.getParentFile(), "lombok.eclipse.agent.jar").delete();
+ }
+
+ try {
+ FileInputStream fis = new FileInputStream(eclipseIniPath);
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ String line;
+ while ((line = br.readLine()) != null) {
+ if (JAVA_AGENT_LINE_MATCHER.matcher(line).matches()) continue;
+ Matcher m = BOOTCLASSPATH_LINE_MATCHER.matcher(line);
+ if (m.matches()) {
+ StringBuilder elemBuilder = new StringBuilder();
+ elemBuilder.append("-Xbootclasspath/a:");
+ boolean first = true;
+ for (String elem : m.group(1).split(Pattern.quote(File.pathSeparator))) {
+ if (elem.toLowerCase().endsWith("lombok.jar")) continue;
+ /* legacy code -see previous comment that starts with 'legacy' */ {
+ if (elem.toLowerCase().endsWith("lombok.eclipse.agent.jar")) continue;
+ }
+ if (first) first = false;
+ else elemBuilder.append(File.pathSeparator);
+ elemBuilder.append(elem);
+ }
+ if (!first) newContents.append(elemBuilder.toString()).append(OS_NEWLINE);
+ continue;
+ }
+
+ newContents.append(line).append(OS_NEWLINE);
+ }
+
+ } finally {
+ fis.close();
+ }
+
+ String fullPathToLombok = fullPathRequired ? (lombokJar.getParentFile().getCanonicalPath() + File.separator) : "";
+
+ newContents.append(String.format(
+ "-javaagent:%slombok.jar", fullPathToLombok)).append(OS_NEWLINE);
+ newContents.append(String.format(
+ "-Xbootclasspath/a:%slombok.jar", fullPathToLombok)).append(OS_NEWLINE);
+
+ FileOutputStream fos = new FileOutputStream(eclipseIniPath);
+ try {
+ fos.write(newContents.toString().getBytes());
+ } finally {
+ fos.close();
+ }
+ installSucceeded = true;
+ } catch (IOException e) {
+ throw new InstallException("Cannot install lombok at " + name + generateWriteErrorMessage(), e);
+ } finally {
+ if (!installSucceeded) try {
+ lombokJar.delete();
+ } catch (Throwable ignore) {}
+ }
+
+ if (!installSucceeded) {
+ throw new InstallException("I can't find the eclipse.ini file. Is this a real Eclipse installation?", null);
+ }
+ }
+}
diff --git a/src/installer/lombok/installer/Installer.java b/src/installer/lombok/installer/Installer.java
new file mode 100644
index 00000000..e1da5d31
--- /dev/null
+++ b/src/installer/lombok/installer/Installer.java
@@ -0,0 +1,895 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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.installer;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.FileDialog;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.HeadlessException;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.font.TextAttribute;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.Scrollable;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.filechooser.FileFilter;
+
+import lombok.core.Version;
+import lombok.installer.EclipseFinder.OS;
+import lombok.installer.EclipseLocation.InstallException;
+import lombok.installer.EclipseLocation.NotAnEclipseException;
+import lombok.installer.EclipseLocation.UninstallException;
+
+/**
+ * The lombok installer proper.
+ * Uses swing to show a simple GUI that can add and remove the java agent to Eclipse installations.
+ * Also offers info on what this installer does in case people want to instrument their Eclipse manually,
+ * and looks in some common places on Mac OS X and Windows.
+ */
+public class Installer {
+ private static final URI ABOUT_LOMBOK_URL = URI.create("http://projectlombok.org");
+
+ private JFrame appWindow;
+
+ private JComponent loadingExpl;
+
+ private Component javacArea;
+ private Component eclipseArea;
+ private Component uninstallArea;
+ private Component howIWorkArea;
+
+ private Box uninstallBox;
+ private List<EclipseLocation> toUninstall;
+
+ private JHyperLink uninstallButton;
+ private JLabel uninstallPlaceholder;
+ private JButton installButton;
+
+ public static void main(String[] args) {
+ if (args.length > 0 && (args[0].equals("install") || args[0].equals("uninstall"))) {
+ boolean uninstall = args[0].equals("uninstall");
+ if (args.length < 3 || !args[1].equals("eclipse")) {
+ System.err.printf("Run java -jar lombok.jar %1$s eclipse path/to/eclipse/executable (or 'auto' to %1$s to all auto-discovered eclipse locations)\n", uninstall ? "uninstall" : "install");
+ System.exit(1);
+ }
+ String path = args[2];
+ try {
+ final List<EclipseLocation> locations = new ArrayList<EclipseLocation>();
+ final List<NotAnEclipseException> problems = new ArrayList<NotAnEclipseException>();
+ if (path.equals("auto")) {
+ EclipseFinder.findEclipses(locations, problems);
+ } else {
+ locations.add(EclipseLocation.create(path));
+ }
+ int validLocations = locations.size();
+ for (EclipseLocation loc : locations) {
+ try {
+ if (uninstall) {
+ loc.uninstall();
+ } else {
+ loc.install();
+ }
+ System.out.printf("Lombok %s %s: %s\n", uninstall ? "uninstalled" : "installed", uninstall ? "from" : "to", loc.getName());
+ } catch (InstallException e) {
+ System.err.printf("Installation at %s failed:\n", loc.getName());
+ System.err.println(e.getMessage());
+ validLocations--;
+ } catch (UninstallException e) {
+ System.err.printf("Uninstall at %s failed:\n", loc.getName());
+ System.err.println(e.getMessage());
+ validLocations--;
+ }
+ }
+ for (NotAnEclipseException problem : problems) {
+ System.err.println("WARNING: " + problem.getMessage());
+ }
+ if (validLocations == 0) {
+ System.err.println("WARNING: Zero valid locations found; so nothing was done.");
+ }
+ System.exit(0);
+ } catch (NotAnEclipseException e) {
+ System.err.println("Not a valid eclipse location:");
+ System.err.println(e.getMessage());
+ System.exit(2);
+ }
+ }
+
+ if (args.length > 0 && args[0].equals("uninstall")) {
+ if (args.length < 3 || !args[1].equals("eclipse")) {
+ System.err.println("Run java -jar lombok.jar uninstall eclipse path/to/eclipse/executable (or 'auto' to uninstall all auto-discovered eclipse locations)");
+ System.exit(1);
+ }
+ String path = args[2];
+ try {
+ EclipseLocation loc = EclipseLocation.create(path);
+ loc.uninstall();
+ System.out.println("Uninstalled from: " + loc.getName());
+ System.exit(0);
+ } catch (NotAnEclipseException e) {
+ System.err.println("Not a valid eclipse location:");
+ System.err.println(e.getMessage());
+ System.exit(2);
+ } catch (UninstallException e) {
+ System.err.println("Uninstall failed:");
+ System.err.println(e.getMessage());
+ System.exit(1);
+ }
+ }
+
+ if (EclipseFinder.getOS() == OS.MAC_OS_X) {
+ System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Lombok Installer");
+ System.setProperty("com.apple.macos.use-file-dialog-packages", "true");
+ }
+
+ try {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception ignore) {}
+
+ new Installer().show();
+ } catch (HeadlessException e) {
+ printHeadlessInfo();
+ }
+ }
+ });
+ } catch (HeadlessException e) {
+ printHeadlessInfo();
+ }
+ }
+
+ /**
+ * If run in headless mode, the installer can't show its fancy GUI. There's little point in running
+ * the installer without a GUI environment, as Eclipse doesn't run in headless mode either, so
+ * we'll make do with showing some basic info on Lombok as well as instructions for using lombok with javac.
+ */
+ private static void printHeadlessInfo() {
+ System.out.printf("About lombok v%s\n" +
+ "Lombok makes java better by providing very spicy additions to the Java programming language," +
+ "such as using @Getter to automatically generate a getter method for any field.\n\n" +
+ "Browse to %s for more information. To install lombok on Eclipse, re-run this jar file on a " +
+ "graphical computer system - this message is being shown because your terminal is not graphics capable." +
+ "If you are just using 'javac' or a tool that calls on javac, no installation is neccessary; just " +
+ "make sure lombok.jar is in the classpath when you compile. Example:\n\n" +
+ " java -cp lombok.jar MyCode.java\n\n\n" +
+ "If for whatever reason you can't run the graphical installer but you do want to install lombok into eclipse," +
+ "start this jar with the following syntax:\n\n" +
+ " java -jar lombok.jar install eclipse path/to/your/eclipse/executable", Version.getVersion(), ABOUT_LOMBOK_URL);
+ }
+
+ /**
+ * Creates a new installer that starts out invisible.
+ * Call the {@link #show()} method on a freshly created installer to render it.
+ */
+ public Installer() {
+ appWindow = new JFrame(String.format("Project Lombok v%s - Installer", Version.getVersion()));
+
+ appWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ appWindow.setResizable(false);
+ appWindow.setIconImage(Toolkit.getDefaultToolkit().getImage(Installer.class.getResource("lombokIcon.png")));
+
+ try {
+ javacArea = buildJavacArea();
+ eclipseArea = buildEclipseArea();
+ uninstallArea = buildUninstallArea();
+ uninstallArea.setVisible(false);
+ howIWorkArea = buildHowIWorkArea();
+ howIWorkArea.setVisible(false);
+ buildChrome(appWindow.getContentPane());
+ appWindow.pack();
+ } catch (Throwable t) {
+ handleException(t);
+ }
+ }
+
+ private void handleException(final Throwable t) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ JOptionPane.showMessageDialog(appWindow, "There was a problem during the installation process:\n" + t, "Uh Oh!", JOptionPane.ERROR_MESSAGE);
+ t.printStackTrace();
+ System.exit(1);
+ }
+ });
+ }
+
+ private Component buildHowIWorkArea() {
+ JPanel container = new JPanel();
+
+ container.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+
+ container.add(new JLabel(HOW_I_WORK_TITLE), constraints);
+
+ constraints.gridy = 1;
+ constraints.insets = new Insets(8, 0, 0, 16);
+ container.add(new JLabel(String.format(HOW_I_WORK_EXPLANATION, File.pathSeparator)), constraints);
+
+ Box buttonBar = Box.createHorizontalBox();
+ JButton backButton = new JButton("Okay - Good to know!");
+ buttonBar.add(Box.createHorizontalGlue());
+ buttonBar.add(backButton);
+
+ backButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ howIWorkArea.setVisible(false);
+ javacArea.setVisible(true);
+ eclipseArea.setVisible(true);
+ appWindow.pack();
+ }
+ });
+
+ constraints.gridy = 2;
+ container.add(buttonBar, constraints);
+
+ return container;
+ }
+
+ private Component buildUninstallArea() {
+ JPanel container = new JPanel();
+
+ container.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+
+ container.add(new JLabel(UNINSTALL_TITLE), constraints);
+
+ constraints.gridy = 1;
+ constraints.insets = new Insets(8, 0, 0, 16);
+ container.add(new JLabel(UNINSTALL_EXPLANATION), constraints);
+
+ uninstallBox = Box.createVerticalBox();
+ constraints.gridy = 2;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ container.add(uninstallBox, constraints);
+
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.gridy = 3;
+ container.add(new JLabel("Are you sure?"), constraints);
+
+ Box buttonBar = Box.createHorizontalBox();
+ JButton noButton = new JButton("No - Don't uninstall");
+ buttonBar.add(noButton);
+ buttonBar.add(Box.createHorizontalGlue());
+ JButton yesButton = new JButton("Yes - uninstall Lombok");
+ buttonBar.add(yesButton);
+
+ noButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ uninstallArea.setVisible(false);
+ javacArea.setVisible(true);
+ eclipseArea.setVisible(true);
+ appWindow.pack();
+ }
+ });
+
+ yesButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ doUninstall();
+ }
+ });
+
+ constraints.gridy = 4;
+ container.add(buttonBar, constraints);
+
+ return container;
+ }
+
+ private Component buildJavacArea() {
+ JPanel container = new JPanel();
+
+ container.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(8, 0, 0, 16);
+
+ container.add(new JLabel(JAVAC_TITLE), constraints);
+
+ constraints.gridy = 1;
+ constraints.weightx = 1.0;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ container.add(new JLabel(JAVAC_EXPLANATION), constraints);
+
+ JLabel example = new JLabel(JAVAC_EXAMPLE);
+
+ constraints.gridy = 2;
+ container.add(example, constraints);
+ return container;
+ }
+
+ private Component buildEclipseArea() {
+ JPanel container = new JPanel();
+
+ container.setLayout(new GridBagLayout());
+ GridBagConstraints constraints = new GridBagConstraints();
+ constraints.anchor = GridBagConstraints.WEST;
+
+ constraints.insets = new Insets(8, 0, 0, 16);
+ container.add(new JLabel(ECLIPSE_TITLE), constraints);
+
+ constraints.gridy = 1;
+ container.add(new JLabel(ECLIPSE_EXPLANATION), constraints);
+
+ constraints.gridy = 2;
+ loadingExpl = Box.createHorizontalBox();
+ loadingExpl.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/loading.gif"))));
+ loadingExpl.add(new JLabel(ECLIPSE_LOADING_EXPLANATION));
+ container.add(loadingExpl, constraints);
+
+ constraints.weightx = 1.0;
+ constraints.gridy = 3;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ eclipsesList = new EclipsesList();
+
+ JScrollPane eclipsesListScroll = new JScrollPane(eclipsesList);
+ eclipsesListScroll.setBackground(Color.WHITE);
+ eclipsesListScroll.getViewport().setBackground(Color.WHITE);
+ container.add(eclipsesListScroll, constraints);
+
+ Thread findEclipsesThread = new Thread() {
+ @Override public void run() {
+ try {
+ final List<EclipseLocation> locations = new ArrayList<EclipseLocation>();
+ final List<NotAnEclipseException> problems = new ArrayList<NotAnEclipseException>();
+ EclipseFinder.findEclipses(locations, problems);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ for (EclipseLocation location : locations) {
+ try {
+ eclipsesList.addEclipse(location);
+ } catch (Throwable t) {
+ handleException(t);
+ }
+ }
+
+ for (NotAnEclipseException problem : problems) {
+ problem.showDialog(appWindow);
+ }
+
+ loadingExpl.setVisible(false);
+
+ if (locations.size() + problems.size() == 0) {
+ JOptionPane.showMessageDialog(appWindow,
+ "I don't know how to automatically find Eclipse installations on this platform.\n" +
+ "Please use the 'Specify Eclipse Location...' button to manually point out the\n" +
+ "location of your Eclipse installation to me. Thanks!", "Can't find Eclipse", JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+ });
+ } catch (Throwable t) {
+ handleException(t);
+ }
+ }
+ };
+
+ findEclipsesThread.start();
+
+ Box buttonBar = Box.createHorizontalBox();
+ JButton specifyEclipseLocationButton = new JButton("Specify Eclipse location...");
+ buttonBar.add(specifyEclipseLocationButton);
+ specifyEclipseLocationButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent event) {
+ final String exeName = EclipseFinder.getEclipseExecutableName();
+ String file = null;
+
+ if (EclipseFinder.getOS() == OS.MAC_OS_X) {
+ FileDialog chooser = new FileDialog(appWindow);
+ chooser.setMode(FileDialog.LOAD);
+ chooser.setFilenameFilter(new FilenameFilter() {
+ @Override public boolean accept(File dir, String fileName) {
+ if (exeName.equalsIgnoreCase(fileName)) return true;
+ if (new File(dir, fileName).isDirectory()) return true;
+ return false;
+ }
+ });
+
+ chooser.setVisible(true);
+ file = new File(chooser.getDirectory(), chooser.getFile()).getAbsolutePath();
+ } else {
+ JFileChooser chooser = new JFileChooser();
+
+ chooser.setAcceptAllFileFilterUsed(false);
+ chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+ chooser.setFileFilter(new FileFilter() {
+ @Override public boolean accept(File f) {
+ if (f.getName().equalsIgnoreCase(exeName)) return true;
+ if (f.getName().equalsIgnoreCase("eclipse.ini")) return true;
+ if (f.isDirectory()) return true;
+
+ return false;
+ }
+
+ @Override public String getDescription() {
+ return "Eclipse Installation";
+ }
+ });
+
+ switch (chooser.showDialog(appWindow, "Select")) {
+ case JFileChooser.APPROVE_OPTION:
+ file = chooser.getSelectedFile().getAbsolutePath();
+ }
+ }
+
+ if (file != null) {
+ try {
+ eclipsesList.addEclipse(EclipseLocation.create(file));
+ } catch (NotAnEclipseException e) {
+ e.showDialog(appWindow);
+ } catch (Throwable t) {
+ handleException(t);
+ }
+ }
+ }
+ });
+
+ buttonBar.add(Box.createHorizontalGlue());
+ installButton = new JButton("Install / Update");
+ buttonBar.add(installButton);
+
+ installButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ List<EclipseLocation> locationsToInstall = new ArrayList<EclipseLocation>(eclipsesList.getSelectedEclipses());
+ if (locationsToInstall.isEmpty()) {
+ JOptionPane.showMessageDialog(appWindow, "You haven't selected any Eclipse installations!.", "No Selection", JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
+ install(locationsToInstall);
+ }
+ });
+
+ constraints.gridy = 4;
+ constraints.weightx = 0;
+ container.add(buttonBar, constraints);
+
+ constraints.gridy = 5;
+ constraints.fill = GridBagConstraints.NONE;
+ JHyperLink showMe = new JHyperLink("Show me what this installer will do to my Eclipse installation.");
+ container.add(showMe, constraints);
+ showMe.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ showWhatIDo();
+ }
+ });
+
+ constraints.gridy = 6;
+ uninstallButton = new JHyperLink("Uninstall lombok from selected Eclipse installations.");
+ uninstallPlaceholder = new JLabel("<html>&nbsp;</html>");
+ uninstallButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ List<EclipseLocation> locationsToUninstall = new ArrayList<EclipseLocation>();
+ for (EclipseLocation location : eclipsesList.getSelectedEclipses()) {
+ if (location.hasLombok()) locationsToUninstall.add(location);
+ }
+
+ if (locationsToUninstall.isEmpty()) {
+ JOptionPane.showMessageDialog(appWindow, "You haven't selected any Eclipse installations that have been lombok-enabled.", "No Selection", JOptionPane.WARNING_MESSAGE);
+ return;
+ }
+
+
+ uninstall(locationsToUninstall);
+ }
+ });
+ container.add(uninstallButton, constraints);
+ uninstallPlaceholder.setVisible(false);
+ container.add(uninstallPlaceholder, constraints);
+
+
+ return container;
+ }
+
+ private void showWhatIDo() {
+ javacArea.setVisible(false);
+ eclipseArea.setVisible(false);
+ howIWorkArea.setVisible(true);
+ appWindow.pack();
+ }
+
+ private void uninstall(List<EclipseLocation> locations) {
+ javacArea.setVisible(false);
+ eclipseArea.setVisible(false);
+
+ uninstallBox.removeAll();
+ uninstallBox.add(Box.createRigidArea(new Dimension(1, 16)));
+ for (EclipseLocation location : locations) {
+ JLabel label = new JLabel(location.getName());
+ label.setFont(label.getFont().deriveFont(Font.BOLD));
+ uninstallBox.add(label);
+ }
+ uninstallBox.add(Box.createRigidArea(new Dimension(1, 16)));
+
+ toUninstall = locations;
+ uninstallArea.setVisible(true);
+ appWindow.pack();
+ }
+
+ private void install(final List<EclipseLocation> toInstall) {
+ JPanel spinner = new JPanel();
+ spinner.setOpaque(true);
+ spinner.setLayout(new FlowLayout());
+ spinner.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/loading.gif"))));
+ appWindow.setContentPane(spinner);
+
+ final AtomicReference<Boolean> success = new AtomicReference<Boolean>(true);
+
+ new Thread() {
+ @Override public void run() {
+ for (EclipseLocation loc : toInstall) {
+ try {
+ loc.install();
+ } catch (final InstallException e) {
+ success.set(false);
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override public void run() {
+ JOptionPane.showMessageDialog(appWindow,
+ e.getMessage(), "Install Problem", JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ } catch (Exception e2) {
+ //Shouldn't happen.
+ throw new RuntimeException(e2);
+ }
+ }
+ }
+
+ if (success.get()) SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ JOptionPane.showMessageDialog(appWindow,
+ "<html>Lombok has been installed on the selected Eclipse installations.<br>" +
+ "Don't forget to add <code>lombok.jar</code> to your projects, and restart your eclipse!<br>" +
+ "If you start eclipse with a custom -vm parameter, you'll need to add:<br>" +
+ "<code>-vmargs -Xbootclasspath/a:lombok.jar -javaagent:lombok.jar</code><br>" +
+ "as parameter as well.</html>", "Install successful",
+ JOptionPane.INFORMATION_MESSAGE);
+ appWindow.setVisible(false);
+ System.exit(0);
+ }
+ });
+
+ if (!success.get()) SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ System.exit(0);
+ }
+ });
+ }
+ }.start();
+ }
+
+ private void doUninstall() {
+ JPanel spinner = new JPanel();
+ spinner.setOpaque(true);
+ spinner.setLayout(new FlowLayout());
+ spinner.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/loading.gif"))));
+
+ appWindow.setContentPane(spinner);
+
+ final AtomicReference<Boolean> success = new AtomicReference<Boolean>(true);
+ new Thread() {
+ @Override public void run() {
+ for (EclipseLocation loc : toUninstall) {
+ try {
+ loc.uninstall();
+ } catch (final UninstallException e) {
+ success.set(false);
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override public void run() {
+ JOptionPane.showMessageDialog(appWindow,
+ e.getMessage(), "Uninstall Problem", JOptionPane.ERROR_MESSAGE);
+ }
+ });
+ } catch (Exception e2) {
+ //Shouldn't happen.
+ throw new RuntimeException(e2);
+ }
+ }
+ }
+
+ if (success.get()) SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ JOptionPane.showMessageDialog(appWindow, "Lombok has been removed from the selected Eclipse installations.", "Uninstall successful", JOptionPane.INFORMATION_MESSAGE);
+ appWindow.setVisible(false);
+ System.exit(0);
+ }
+ });
+ }
+ }.start();
+ }
+
+ private EclipsesList eclipsesList = new EclipsesList();
+
+ private static class JHyperLink extends JButton {
+ private static final long serialVersionUID = 1L;
+
+ public JHyperLink(String text) {
+ super();
+ setFont(getFont().deriveFont(Collections.singletonMap(TextAttribute.UNDERLINE, 1)));
+ setText(text);
+ setBorder(null);
+ setContentAreaFilled(false);
+ setForeground(Color.BLUE);
+ setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
+ setMargin(new Insets(0, 0, 0, 0));
+ }
+ }
+
+ void selectedLomboksChanged(List<EclipseLocation> selectedEclipses) {
+ boolean uninstallAvailable = false;
+ boolean installAvailable = false;
+ for (EclipseLocation loc : selectedEclipses) {
+ if (loc.hasLombok()) uninstallAvailable = true;
+ installAvailable = true;
+ }
+
+ uninstallButton.setVisible(uninstallAvailable);
+ uninstallPlaceholder.setVisible(!uninstallAvailable);
+ installButton.setEnabled(installAvailable);
+ }
+
+ private class EclipsesList extends JPanel implements Scrollable {
+ private static final long serialVersionUID = 1L;
+
+ List<EclipseLocation> locations = new ArrayList<EclipseLocation>();
+
+ EclipsesList() {
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ setBackground(Color.WHITE);
+ }
+
+ List<EclipseLocation> getSelectedEclipses() {
+ List<EclipseLocation> list = new ArrayList<EclipseLocation>();
+ for (EclipseLocation loc : locations) if (loc.selected) list.add(loc);
+ return list;
+ }
+
+ void fireSelectionChange() {
+ selectedLomboksChanged(getSelectedEclipses());
+ }
+
+ void addEclipse(final EclipseLocation location) {
+ if (locations.contains(location)) return;
+ Box box = Box.createHorizontalBox();
+ box.setBackground(Color.WHITE);
+ final JCheckBox checkbox = new JCheckBox(location.getName());
+ checkbox.setBackground(Color.WHITE);
+ box.add(checkbox);
+ checkbox.setSelected(true);
+ checkbox.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ location.selected = checkbox.isSelected();
+ fireSelectionChange();
+ }
+ });
+
+ if (location.hasLombok()) {
+ box.add(new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/lombokIcon.png"))));
+ }
+ box.add(Box.createHorizontalGlue());
+ locations.add(location);
+ add(box);
+ getParent().doLayout();
+ fireSelectionChange();
+ }
+
+ @Override public Dimension getPreferredScrollableViewportSize() {
+ return new Dimension(1, 100);
+ }
+
+ @Override public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
+ return 12;
+ }
+
+ @Override public boolean getScrollableTracksViewportHeight() {
+ return false;
+ }
+
+ @Override public boolean getScrollableTracksViewportWidth() {
+ return true;
+ }
+
+ @Override public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
+ return 1;
+ }
+ }
+
+ private void buildChrome(Container appWindowContainer) {
+ JLabel leftGraphic = new JLabel(new ImageIcon(Installer.class.getResource("/lombok/installer/lombok.png")));
+
+ GridBagConstraints constraints = new GridBagConstraints();
+
+ appWindowContainer.setLayout(new GridBagLayout());
+
+ constraints.gridheight = 3;
+ constraints.gridwidth = 1;
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.insets = new Insets(8, 8, 8, 8);
+ appWindowContainer.add(leftGraphic, constraints);
+ constraints.insets = new Insets(0, 0, 0, 0);
+
+ constraints.gridx++;
+ constraints.gridy++;
+ constraints.gridheight = 1;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.ipadx = 16;
+ constraints.ipady = 14;
+ appWindowContainer.add(javacArea, constraints);
+
+ constraints.gridy++;
+ appWindowContainer.add(eclipseArea, constraints);
+
+ appWindowContainer.add(uninstallArea, constraints);
+
+ appWindowContainer.add(howIWorkArea, constraints);
+
+ constraints.gridy++;
+ constraints.gridwidth = 2;
+ constraints.gridx = 0;
+ constraints.weightx = 0;
+ constraints.weighty = 0;
+ constraints.ipadx = 0;
+ constraints.ipady = 0;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ constraints.anchor = GridBagConstraints.SOUTHEAST;
+ constraints.insets = new Insets(0, 16, 8, 8);
+ Box buttonBar = Box.createHorizontalBox();
+ JButton quitButton = new JButton("Quit Installer");
+ quitButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ appWindow.setVisible(false);
+ System.exit(0);
+ }
+ });
+ final JHyperLink hyperlink = new JHyperLink(ABOUT_LOMBOK_URL.toString());
+ hyperlink.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent event) {
+ hyperlink.setForeground(new Color(85, 145, 90));
+ try {
+ //java.awt.Desktop doesn't exist in 1.5.
+ Object desktop = Class.forName("java.awt.Desktop").getMethod("getDesktop").invoke(null);
+ Class.forName("java.awt.Desktop").getMethod("browse", URI.class).invoke(desktop, ABOUT_LOMBOK_URL);
+ } catch (Exception e) {
+ Runtime rt = Runtime.getRuntime();
+ try {
+ switch (EclipseFinder.getOS()) {
+ case WINDOWS:
+ String[] cmd = new String[4];
+ cmd[0] = "cmd.exe";
+ cmd[1] = "/C";
+ cmd[2] = "start";
+ cmd[3] = ABOUT_LOMBOK_URL.toString();
+ rt.exec(cmd);
+ break;
+ case MAC_OS_X:
+ rt.exec("open " + ABOUT_LOMBOK_URL.toString());
+ break;
+ default:
+ case UNIX:
+ rt.exec("firefox " + ABOUT_LOMBOK_URL.toString());
+ break;
+ }
+ } catch (Exception e2) {
+ JOptionPane.showMessageDialog(appWindow,
+ "Well, this is embarrassing. I don't know how to open a webbrowser.\n" +
+ "I guess you'll have to open it. Browse to:\n" +
+ "http://projectlombok.org for more information about Lombok.",
+ "I'm embarrassed", JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+ }
+ });
+ buttonBar.add(hyperlink);
+ buttonBar.add(Box.createRigidArea(new Dimension(16, 1)));
+ buttonBar.add(new JLabel("<html><font size=\"-1\">v" + Version.getVersion() + "</font></html>"));
+
+ buttonBar.add(Box.createHorizontalGlue());
+ buttonBar.add(quitButton);
+ appWindow.add(buttonBar, constraints);
+ }
+
+ /**
+ * Makes the installer window visible.
+ */
+ public void show() {
+ appWindow.setVisible(true);
+ if (EclipseFinder.getOS() == OS.MAC_OS_X) {
+ try {
+ AppleNativeLook.go();
+ } catch (Throwable ignore) {
+ //We're just prettying up the app. If it fails, meh.
+ }
+ }
+ }
+
+ private static final String ECLIPSE_TITLE =
+ "<html><font size=\"+1\"><b><i>Eclipse</i></b></font></html>";
+
+ private static final String ECLIPSE_EXPLANATION =
+ "<html>Lombok can update your Eclipse to fully support all Lombok features.<br>" +
+ "Select Eclipse installations below and hit 'Install/Update'.</html>";
+
+ private static final String ECLIPSE_LOADING_EXPLANATION =
+ "Scanning your drives for Eclipse installations...";
+
+ private static final String JAVAC_TITLE =
+ "<html><font size=\"+1\"><b><i>Javac</i></b></font> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (and tools that invoke javac such as <i>ant</i> and <i>maven</i>)</html>";
+
+ private static final String JAVAC_EXPLANATION =
+ "<html>Lombok works 'out of the box' with javac.<br>Just make sure the lombok.jar is in your classpath when you compile.";
+
+ private static final String JAVAC_EXAMPLE =
+ "<html>Example: <code>javac -cp lombok.jar MyCode.java</code></html>";
+
+ private static final String UNINSTALL_TITLE =
+ "<html><font size=\"+1\"><b><i>Uninstall</i></b></font></html>";
+
+ private static final String UNINSTALL_EXPLANATION =
+ "<html>Uninstall Lombok from the following Eclipse Installations?</html>";
+
+ private static final String HOW_I_WORK_TITLE =
+ "<html><font size=\"+1\"><b><i>What this installer does</i></b></font></html>";
+
+ private static final String HOW_I_WORK_EXPLANATION =
+ "<html><ol>" +
+ "<li>First, I copy myself (lombok.jar) to your Eclipse install directory.</li>" +
+ "<li>Then, I edit the eclipse.ini file to add the following two entries:<br>" +
+ "<pre>-Xbootclasspath/a:lombok.jar<br>" +
+ "-javaagent:lombok.jar</pre></li></ol>" +
+ "<br>" +
+ "That's all there is to it. Note that on Mac OS X, eclipse.ini is hidden in<br>" +
+ "<code>Eclipse.app%1$sContents%1$sMacOS</code> so that's where I place the jar files.</html>";
+}
diff --git a/src/installer/lombok/installer/WindowsDriveInfo-i386.dll b/src/installer/lombok/installer/WindowsDriveInfo-i386.dll
new file mode 100644
index 00000000..eb7fa49a
--- /dev/null
+++ b/src/installer/lombok/installer/WindowsDriveInfo-i386.dll
Binary files differ
diff --git a/src/installer/lombok/installer/WindowsDriveInfo-x86_64.dll b/src/installer/lombok/installer/WindowsDriveInfo-x86_64.dll
new file mode 100644
index 00000000..0b7c9a83
--- /dev/null
+++ b/src/installer/lombok/installer/WindowsDriveInfo-x86_64.dll
Binary files differ
diff --git a/src/installer/lombok/installer/WindowsDriveInfo.java b/src/installer/lombok/installer/WindowsDriveInfo.java
new file mode 100644
index 00000000..41a6b17e
--- /dev/null
+++ b/src/installer/lombok/installer/WindowsDriveInfo.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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.installer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class uses native calls on windows to figure out all drives,
+ * and, for each drive, if its a harddisk or something else.
+ *
+ * The output is essentially equivalent to running windows executable:
+ * <pre>fsutil fsinfo drives</pre>
+ * and
+ * <pre>fsutil fsinfo drivetype C:</pre>
+ *
+ * except that (A) fsutil requires privileges, (B) someone might have moved
+ * it out of the path or some such, and (C) its output is internationalized,
+ * so unless you want to include a table of how to say "Fixed Disk" in 300
+ * languages, this really is a superior solution.
+ * <p>
+ * To compile it, you'll need windows, as well as MinGW:
+ * http://sourceforge.net/projects/mingw/files/
+ * <p>
+ * Fetch gcc 4.0.4+, you don't need anything extra. Toss /c/mingw/bin in
+ * your git bash prompt's path (/etc/profile) and then run:
+ *
+ * $ gcc -c \
+ -I "/c/Program Files/Java/jdk1.6.0_14/include" \
+ -I "/c/Program Files/Java/jdk1.6.0_14/include/win32" \
+ -D__int64="long long" lombok_installer_WindowsDriveInfo.c
+ *
+ * $ dllwrap.exe --add-stdcall-alias \
+ -o WindowsDriveInfo-i386.dll \
+ lombok_installer_WindowsDriveInfo.o
+ *
+ * You may get a warning along the lines of "Creating an export definition".
+ * This is expected behaviour.
+ *
+ * <p>
+ * Now download MinGW-w64 to build the 64-bit version of the dll (you thought you were done, weren't you?)
+ * from: http://sourceforge.net/projects/mingw-w64/files/
+ * (under toolchains targetting Win64 / Release for GCC 4.4.0 (or later) / the version for your OS.)
+ *
+ * Then, do this all over again, but this time with the x86_64-w64-mingw32-gcc and
+ * x86_64-w64-mingw32-dllwrap versions that are part of the MinGW-w64 distribution.
+ * Name the dll 'WindowsDriveInfo-x86_64.dll'.
+ *
+ * Both the 32-bit and 64-bit DLLs that this produces have been checked into the git repository
+ * under src/lombok/installer so you won't need to build them again unless you make some changes to
+ * the code in the winsrc directory.
+ */
+public class WindowsDriveInfo {
+ /**
+ * Return a list of all available drive letters, such as ["A", "C", "D"].
+ */
+ public List<String> getLogicalDrives() {
+ int flags = getLogicalDrives0();
+
+ List<String> letters = new ArrayList<String>();
+ for (int i = 0; i < 26; i++) {
+ if ((flags & (1 << i)) != 0) letters.add(Character.toString((char)('A' + i)));
+ }
+
+ return letters;
+ }
+
+ /**
+ * Calls kernel32's GetLogicalDrives, which returns an int containing
+ * flags; bit 0 corresponds to drive A, bit 25 to drive Z. on = disk exists.
+ */
+ private native int getLogicalDrives0();
+
+ /**
+ * Feed it a drive letter (such as 'A') to see if it is a fixed disk.
+ */
+ public boolean isFixedDisk(String letter) {
+ if (letter.length() != 1) throw new IllegalArgumentException("Supply 1 letter, not: " + letter);
+ char drive = Character.toUpperCase(letter.charAt(0));
+ if (drive < 'A' || drive > 'Z') throw new IllegalArgumentException(
+ "A drive is indicated by a letter, so A-Z inclusive. Not " + drive);
+ return getDriveType(drive + ":\\") == 3L;
+ }
+
+ /**
+ * Mirror of kernel32's GetDriveTypeA. You must pass in 'A:\\' -
+ * so including both a colon and a backslash!
+ *
+ * 0 = error
+ * 1 = doesn't exist
+ * 2 = removable drive
+ * 3 = fixed disk
+ * 4 = remote (network) disk
+ * 5 = cd-rom
+ * 6 = ram disk
+ */
+ private native int getDriveType(String name);
+
+ public static void main(String[] args) {
+ System.loadLibrary("WindowsDriveInfo");
+ WindowsDriveInfo info = new WindowsDriveInfo();
+
+ for (String letter : info.getLogicalDrives()) {
+ System.out.printf("Drive %s: - %s\n", letter,
+ info.isFixedDisk(letter) ? "Fixed Disk" : "Not Fixed Disk");
+ }
+ }
+}
diff --git a/src/installer/lombok/installer/loading.gif b/src/installer/lombok/installer/loading.gif
new file mode 100644
index 00000000..b9fc304a
--- /dev/null
+++ b/src/installer/lombok/installer/loading.gif
Binary files differ
diff --git a/src/installer/lombok/installer/lombok.png b/src/installer/lombok/installer/lombok.png
new file mode 100644
index 00000000..d4efde04
--- /dev/null
+++ b/src/installer/lombok/installer/lombok.png
Binary files differ
diff --git a/src/installer/lombok/installer/lombok.svg b/src/installer/lombok/installer/lombok.svg
new file mode 100644
index 00000000..0d561aea
--- /dev/null
+++ b/src/installer/lombok/installer/lombok.svg
@@ -0,0 +1,181 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+This vector art image is part of the public domain. It has been updated from:
+http://www.clker.com/clipart-pepper.html
+-->
+
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="720"
+ height="256"
+ id="svg2809"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="Peperoni.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs2811">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective2817" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="404.16677"
+ inkscape:cy="196.96954"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1280"
+ inkscape:window-height="904"
+ inkscape:window-x="-4"
+ inkscape:window-y="-4" />
+ <metadata
+ id="metadata2814">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-68.690412,-361.67592)">
+ <g
+ style="display:inline"
+ id="g8198"
+ transform="matrix(1.4248201,0.1395229,-0.1500716,1.3983461,160.45389,-461.25789)">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccc"
+ id="path7056"
+ d="M 93.681663,642.08699 L 81.559832,655.72405 L 70.953231,677.44233 L 72.973535,706.73675 L 98.732426,730.47535 L 135.09792,735.5261 L 168.43295,734.01087 L 199.49514,720.37382 L 260.35683,709.26214 L 328.79467,702.69615 L 351.27057,699.66569 L 434.10307,706.23168 L 465.92287,704.71645 L 494.71222,703.7063 L 501.53075,698.90808 L 501.27822,688.04893 L 488.6513,679.96771 L 394.20205,646.1276 L 311.36954,628.95501 L 223.48627,620.87379 L 140.90629,628.44994 L 93.681663,642.08699 z"
+ style="fill:#622819;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccc"
+ id="path4133"
+ d="M 232.56696,623.89286 L 147.77232,629.61607 L 191.55994,630.13901 L 247.24726,636.90381 L 193.08716,634.57713 L 148.63497,634.83828 L 109.70889,640.35941 L 92.160714,646.14286 L 75.004464,672.39286 L 73.973214,703.70536 L 102.25446,729.95536 L 153.78571,732.98661 L 227.53571,710.76786 L 350.75446,697.64286 L 433.59821,704.70536 L 490.16071,701.67411 L 497.22321,695.61161 L 494.19196,685.51786 L 417.44196,656.23661 L 328.53571,634.01786 L 232.56696,623.89286 z"
+ style="fill:#b23b23;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccc"
+ id="path5116"
+ d="M 102.01542,659.51212 L 117.92532,656.73421 L 123.48116,666.33065 L 134.59284,660.77482 L 149.74513,656.22913 L 136.10807,663.80527 L 132.57254,672.39157 L 138.12838,677.44233 L 152.77559,679.96771 L 168.93803,676.93726 L 148.2299,688.55401 L 139.13853,689.56416 L 137.11822,701.18092 L 126.51162,713.80782 L 132.06746,724.41443 L 139.6436,726.93981 L 128.02685,727.44488 L 116.91517,715.82813 L 105.80349,714.81798 L 97.217197,719.36366 L 102.26796,710.27229 L 89.641053,702.69615 L 86.105519,690.06924 L 80.54968,679.96771 L 80.54968,671.88649 L 88.378362,681.23041 L 89.388514,669.36111 L 94.313008,661.02735 L 101.13154,648.14791 L 102.01542,659.51212 z"
+ style="opacity:0.5;fill:#76140e;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ id="path7063"
+ d="M 170.35714,628.57143 L 225.35714,626.42857 L 289.64285,632.85715 L 324.28571,638.92857 L 254.64285,632.85715 L 201.78571,629.64286 L 170.35714,628.57143 z"
+ style="opacity:0.5;fill:#f5cfce;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ id="path7065"
+ d="M 111.13075,653.29059 L 132.33216,642.9746 L 188.38383,638.59697 L 294.36063,641.41822 L 352.13548,649.71389 L 403.48175,662.65243 L 351.95691,655.2623 L 294.00349,648.9436 L 219.93315,645.02553 L 138.00529,647.64284 L 111.13075,653.29059 z"
+ style="opacity:0.65;fill:#f5cfce;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
+ <g
+ id="g7195">
+ <path
+ style="fill:#7c8f11;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 87.857143,673.57143 L 97.5,665 L 101.07143,656.07143 L 112.14286,661.07143 L 127.14286,669.64286 L 141.07143,670.00001 L 136.42857,686.07143 L 136.42857,698.57143 L 136.78571,711.42857 L 120.35714,715.35714 L 107.14286,726.07143 L 102.85714,717.14286 L 91.785714,708.57143 L 81.071428,705.35715 L 83.571428,691.07143 L 79.285714,679.28572 L 87.857143,673.57143 z"
+ id="path7067" />
+ <g
+ id="g7188">
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path7186"
+ d="M 102.96317,716.26763 L 107.54899,723.42044 L 118.24139,716.08913 L 107.75203,720.8537 L 102.96317,716.26763 z"
+ style="fill:#626e28;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path7184"
+ d="M 134.61975,687.20372 L 139.6134,671.96557 L 121.44201,669.94176 L 137.02204,673.00191 L 134.61975,687.20372 z"
+ style="opacity:0.85;fill:#626e28;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
+
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path7182"
+ d="M 113.00055,663.41369 L 103.07121,660.21836 L 97.878976,670.80219 L 103.11895,663.00885 L 113.00055,663.41369 z"
+ style="opacity:0.75;fill:#626e28;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
+ <path
+ id="path7180"
+ d="M 124.77374,713.72385 L 135.27853,709.55732 L 135.22118,694.14433 L 133.5153,708.85426 L 124.77374,713.72385 z"
+ style="opacity:0.9;fill:#626e28;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline" />
+ <path
+ sodipodi:nodetypes="cccccc"
+ id="path7178"
+ d="M 93.346449,670.33792 L 89.083939,677.49039 L 84.107143,703.03572 L 98.571429,710.53571 L 86.25,702.32143 L 93.346449,670.33792 z"
+ style="fill:#626e28;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="fill:#4c551f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 102.01037,673.90149 L 111.04259,673.65316 L 113.59948,668.62761 L 112.75953,664.10715 L 115.90934,669.94608 L 114.60963,675.40831 L 122.04984,682.38577 L 127.11825,681.31985 L 132.78792,674.7275 L 130.26806,683.39173 L 123.3838,687.15457 L 122.45598,693.99946 L 127.74547,698.63991 L 134.76015,699.32493 L 126.69828,700.20251 L 120.36164,698.39576 L 120.34022,704.03658 L 119.51736,707.59013 L 123.89164,711.72121 L 119.86814,710.34986 L 114.11689,715.13871 L 109.28719,716.64553 L 106.21012,712.06452 L 101.21021,714.56889 L 104.74021,710.06523 L 101.92803,703.84539 L 92.680284,699.70584 L 94.660804,684.6376 L 102.01037,673.90149 z"
+ id="path7140"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccc" />
+ </g>
+ <g
+ id="g7217">
+ <path
+ style="fill:#748804;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="M 110.71429,675.89286 L 119.28571,684.82143 L 120.53571,696.07143 L 113.92857,702.32143 L 105,703.39286 L 90.357143,700.17857 L 63.114938,697.69652 L 40.829403,689.60479 L 17.678571,664.28572 L 19.107142,624.46429 L 50.714286,601.96429 L 93.989847,617.23478 L 94.353336,623.08059 L 87.696519,628.47208 L 52.240029,617.80856 L 36.507794,629.66824 L 32.512691,650.73223 L 46.071429,670.35715 L 61.768856,674.86739 L 84.284813,673.31672 L 110.71429,675.89286 z"
+ id="path7144"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ style="opacity:0.5;fill:#544d25;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 19.941964,623.86161 L 19.098214,624.45536 L 17.691964,664.29911 L 40.816964,689.61161 L 63.129464,697.70536 L 90.348214,700.17411 L 105.00446,703.39286 L 113.94196,702.33036 L 120.53571,696.08036 L 119.28571,684.83036 L 115.41071,680.79911 L 117.50446,689.64286 L 113.94196,697.48661 L 79.629464,694.64286 L 45.723214,686.79911 L 22.848214,661.42411 L 19.941964,623.86161 z"
+ id="path7151" />
+
+ <path
+ style="opacity:0.75;fill:#544d25;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 66.772321,617.12946 L 48.558036,614.63393 L 34.28125,627.14732 L 34.441964,640.58036 L 36.504464,629.67411 L 52.254464,617.79911 L 87.691964,628.48661 L 88.691964,627.67411 L 66.772321,617.12946 z"
+ id="path7158"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ style="opacity:0.5;fill:#dbd4ac;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 34.254464,653.23661 L 40.910714,669.86161 L 55.035714,676.42411 L 101.00446,676.92411 L 111.97393,679.56149 L 115.98438,687.67857 L 114.53571,679.86161 L 110.72321,675.89286 L 84.285714,673.33036 L 61.754464,674.86161 L 46.066964,670.36161 L 34.254464,653.23661 z"
+ id="path7167"
+ sodipodi:nodetypes="cccccccccccc" />
+ <path
+ style="opacity:0.5;fill:#dbd4ac;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 50.723214,601.95536 L 20.410714,623.51786 L 25.723214,622.14286 L 44.098214,608.20536 L 53.941964,604.45536 L 89.473214,617.67411 L 92.316964,622.48661 L 89.160714,627.29911 L 94.348214,623.08036 L 94.004464,617.23661 L 50.723214,601.95536 z"
+ id="path7174" />
+ <path
+ style="opacity:0.19959992;fill:#ede8c7;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline"
+ d="M 29.362243,653.61621 L 28.049844,631.79912 L 35.071204,620.33609 L 45.073313,613.06741 L 62.525298,611.10202 L 87.466768,624.95988 L 63.410075,609.25123 L 43.307335,610.88104 L 25.325211,627.5252 L 25.726456,652.73228 L 42.393695,679.04205 L 73.325818,681.39721 L 108.01767,688.31438 L 75.307884,679.02475 L 43.738547,676.92791 L 29.362243,653.61621 z"
+ id="path7176"
+ sodipodi:nodetypes="cccccccccccccccc" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path7225"
+ d="M 168.69547,724.75894 L 235.87062,693.94929 L 296.98485,696.97975 L 371.23106,685.36299 L 300.52038,700.51528 L 238.90108,702.53558 L 168.69547,724.75894 z"
+ style="fill:#803311;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ sodipodi:nodetypes="ccccccc"
+ id="path8196"
+ d="M 395.47472,693.94929 L 437.64859,700.26274 L 478.81231,696.72721 L 484.87322,686.87822 L 482.60038,699.50513 L 433.60798,703.04067 L 395.47472,693.94929 z"
+ style="fill:#803311;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ </g>
+
+</svg>
diff --git a/src/installer/lombok/installer/lombokIcon.png b/src/installer/lombok/installer/lombokIcon.png
new file mode 100644
index 00000000..48fd4307
--- /dev/null
+++ b/src/installer/lombok/installer/lombokIcon.png
Binary files differ
diff --git a/src/installer/lombok/installer/lombokText.png b/src/installer/lombok/installer/lombokText.png
new file mode 100644
index 00000000..279746cb
--- /dev/null
+++ b/src/installer/lombok/installer/lombokText.png
Binary files differ
diff --git a/src/installer/lombok/installer/lombokText.svg b/src/installer/lombok/installer/lombokText.svg
new file mode 100644
index 00000000..9fd2f73b
--- /dev/null
+++ b/src/installer/lombok/installer/lombokText.svg
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ width="425.0675"
+ height="56.760002"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="lombokText.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <metadata
+ id="metadata2527">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:window-height="713"
+ inkscape:window-width="640"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="1"
+ inkscape:cx="194.15432"
+ inkscape:cy="205"
+ inkscape:window-x="365"
+ inkscape:window-y="58"
+ inkscape:current-layer="svg2" />
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 100 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="500 : 100 : 1"
+ inkscape:persp3d-origin="250 : 66.666667 : 1"
+ id="perspective2529" />
+ </defs>
+ <g
+ id="layer1"
+ transform="translate(-31.89625,-66.299366)">
+ <path
+ d="M 31.89625,123.05937 L 31.89625,66.299366 L 41.35625,66.299366 L 41.35625,115.13937 L 84.36625,115.13937 L 84.36625,123.05937 L 31.89625,123.05937 M 98.808906,87.529366 C 98.808897,83.276072 99.615562,80.379409 101.22891,78.839366 C 102.84223,77.226078 105.84889,76.419413 110.24891,76.419366 L 143.90891,76.419366 C 148.30885,76.419413 151.31551,77.226078 152.92891,78.839366 C 154.54217,80.379409 155.34884,83.276072 155.34891,87.529366 L 155.34891,112.05937 C 155.34884,116.31271 154.54217,119.20937 152.92891,120.74937 C 151.31551,122.28937 148.30885,123.05937 143.90891,123.05937 L 110.24891,123.05937 C 105.77556,123.05937 102.73223,122.32603 101.11891,120.85937 C 99.578896,119.31937 98.808897,116.38604 98.808906,112.05937 L 98.808906,87.529366 M 107.60891,116.01937 L 146.54891,116.01937 L 146.54891,83.349366 L 107.60891,83.349366 L 107.60891,116.01937 M 182.78875,85.109366 L 183.00875,91.599366 L 183.00875,123.05937 L 175.74875,123.05937 L 175.74875,76.419366 L 183.00875,76.419366 L 206.21875,106.66937 L 227.55875,76.419366 L 235.69875,76.419366 L 235.69875,123.05937 L 227.55875,123.05937 L 227.55875,91.599366 C 227.55869,89.326066 227.74202,87.162735 228.10875,85.109366 C 227.08202,88.042734 226.05536,90.206065 225.02875,91.599366 L 207.09875,115.68937 L 204.78875,115.68937 L 186.19875,91.819366 C 184.8054,90.059399 183.66873,87.822734 182.78875,85.109366 M 257.38937,123.05937 L 257.38937,76.419366 L 296.76938,76.419366 C 303.58932,76.419413 306.99931,79.462743 306.99937,85.549366 L 306.99937,90.939366 C 306.99931,95.632727 304.28598,98.309391 298.85938,98.969366 C 304.50598,99.556056 307.32931,102.56272 307.32938,107.98937 L 307.32938,113.92937 C 307.32931,120.01604 302.81932,123.05937 293.79937,123.05937 L 257.38937,123.05937 M 298.19938,91.489366 L 298.19938,87.089366 C 298.19932,84.522738 296.54933,83.239406 293.24937,83.239366 L 266.18937,83.239366 L 266.18937,95.229366 L 293.24937,95.229366 C 295.08266,95.229394 296.36599,95.009394 297.09938,94.569366 C 297.83266,94.056062 298.19932,93.029396 298.19938,91.489366 M 266.18937,102.04937 L 266.18937,116.23937 L 293.24937,116.23937 C 295.22933,116.23937 296.58599,115.87271 297.31937,115.13937 C 298.12599,114.33271 298.52932,112.93938 298.52938,110.95937 L 298.52938,107.32937 C 298.52932,103.80939 296.76932,102.04939 293.24937,102.04937 L 266.18937,102.04937 M 325.68391,87.529366 C 325.6839,83.276072 326.49056,80.379409 328.10391,78.839366 C 329.71723,77.226078 332.72389,76.419413 337.12391,76.419366 L 370.78391,76.419366 C 375.18385,76.419413 378.19051,77.226078 379.80391,78.839366 C 381.41717,80.379409 382.22384,83.276072 382.22391,87.529366 L 382.22391,112.05937 C 382.22384,116.31271 381.41717,119.20937 379.80391,120.74937 C 378.19051,122.28937 375.18385,123.05937 370.78391,123.05937 L 337.12391,123.05937 C 332.65056,123.05937 329.60723,122.32603 327.99391,120.85937 C 326.4539,119.31937 325.6839,116.38604 325.68391,112.05937 L 325.68391,87.529366 M 334.48391,116.01937 L 373.42391,116.01937 L 373.42391,83.349366 L 334.48391,83.349366 L 334.48391,116.01937 M 402.62375,123.05937 L 402.62375,76.419366 L 411.42375,76.419366 L 411.42375,96.439366 L 440.90375,76.419366 L 453.11375,76.419366 L 418.68375,98.969366 L 456.96375,123.05937 L 442.55375,123.05937 L 411.42375,102.15937 L 411.42375,123.05937 L 402.62375,123.05937"
+ id="flowRoot2383"
+ style="font-size:110px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bank Gothic;-inkscape-font-specification:Bank Gothic" />
+ </g>
+</svg>
diff --git a/src/installer/lombok/installer/package-info.java b/src/installer/lombok/installer/package-info.java
new file mode 100644
index 00000000..14b329b4
--- /dev/null
+++ b/src/installer/lombok/installer/package-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2009 Reinier Zwitserloot and Roel Spilker.
+ *
+ * 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.
+ */
+
+/**
+ * This package contains the lombok installer. It explains to any user that double-clicks the lombok.jar what
+ * lombok is about, and has the ability to instrument (or remove existing Lombok instrumentation) from any
+ * Eclipse installation. This package also contains the graphics uses in the installer in SVG format.
+ */
+package lombok.installer;