aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/lombok/com.zwitserloot.cmdreader.jarbin19426 -> 19507 bytes
-rw-r--r--src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java1
-rw-r--r--src/installer/lombok/installer/CorruptedIdeLocationException.java26
-rw-r--r--src/installer/lombok/installer/IdeFinder.java144
-rw-r--r--src/installer/lombok/installer/IdeLocation.java74
-rw-r--r--src/installer/lombok/installer/IdeLocationProvider.java40
-rw-r--r--src/installer/lombok/installer/InstallException.java10
-rw-r--r--src/installer/lombok/installer/Installer.java834
-rw-r--r--src/installer/lombok/installer/InstallerGUI.java796
-rw-r--r--src/installer/lombok/installer/UninstallException.java10
-rw-r--r--src/installer/lombok/installer/eclipse/EclipseFinder.java (renamed from src/installer/lombok/installer/EclipseFinder.java)179
-rw-r--r--src/installer/lombok/installer/eclipse/EclipseLocation.java (renamed from src/installer/lombok/installer/EclipseLocation.java)197
-rw-r--r--src/installer/lombok/installer/eclipse/EclipseLocationProvider.java144
-rw-r--r--src/installer/lombok/installer/eclipse/eclipse.pngbin0 -> 1328 bytes
-rw-r--r--src/installer/lombok/installer/netbeans/NetbeansFinder.java201
-rw-r--r--src/installer/lombok/installer/netbeans/NetbeansLocation.java282
-rw-r--r--src/installer/lombok/installer/netbeans/NetbeansLocationProvider.java125
-rw-r--r--src/installer/lombok/installer/netbeans/netbeans.pngbin0 -> 1705 bytes
18 files changed, 1981 insertions, 1082 deletions
diff --git a/lib/lombok/com.zwitserloot.cmdreader.jar b/lib/lombok/com.zwitserloot.cmdreader.jar
index 411f2a1f..dade537a 100644
--- a/lib/lombok/com.zwitserloot.cmdreader.jar
+++ b/lib/lombok/com.zwitserloot.cmdreader.jar
Binary files differ
diff --git a/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java b/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java
index 3a83bea1..f30ff761 100644
--- a/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java
+++ b/src/core/lombok/core/runtimeDependencies/CreateLombokRuntimeApp.java
@@ -85,7 +85,6 @@ public class CreateLombokRuntimeApp implements LombokApp {
@Requires("create")
String output;
- @Shorthand({"h", "?"})
@Description("Shows this help text")
boolean help;
}
diff --git a/src/installer/lombok/installer/CorruptedIdeLocationException.java b/src/installer/lombok/installer/CorruptedIdeLocationException.java
new file mode 100644
index 00000000..9b185d1e
--- /dev/null
+++ b/src/installer/lombok/installer/CorruptedIdeLocationException.java
@@ -0,0 +1,26 @@
+package lombok.installer;
+
+import javax.swing.JFrame;
+import javax.swing.JOptionPane;
+
+/**
+ * Represents an installation location problem.
+ * You should throw it upon creation of a {@code IdeLocation} class
+ * if the provided location looks like your kind of IDE but there's something wrong with it.
+ */
+public class CorruptedIdeLocationException extends Exception {
+ private final String ideType;
+
+ public CorruptedIdeLocationException(String message, String ideType, Throwable cause) {
+ super(message, cause);
+ this.ideType = ideType;
+ }
+
+ public String getIdeType() {
+ return ideType;
+ }
+
+ void showDialog(JFrame appWindow) {
+ JOptionPane.showMessageDialog(appWindow, getMessage(), "Cannot configure " + ideType + " installation", JOptionPane.WARNING_MESSAGE);
+ }
+}
diff --git a/src/installer/lombok/installer/IdeFinder.java b/src/installer/lombok/installer/IdeFinder.java
new file mode 100644
index 00000000..165d0768
--- /dev/null
+++ b/src/installer/lombok/installer/IdeFinder.java
@@ -0,0 +1,144 @@
+/*
+ * 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.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import lombok.core.Version;
+
+/**
+ * Implement and provide this class to add auto-finding a certain brand of IDEs to the lombok installer.
+ */
+public abstract class IdeFinder {
+ 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 = IdeFinder.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 that represent fixed disks.
+ *
+ * Floppy drives, optical drives, USB sticks, and network drives should all be excluded.
+ *
+ * @return A List of drive letters, such as ["C", "D", "X"].
+ */
+ public 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;
+ }
+
+ public static enum OS {
+ MAC_OS_X("\n"), WINDOWS("\r\n"), UNIX("\n");
+
+ private final String lineEnding;
+
+ OS(String lineEnding) {
+ this.lineEnding = lineEnding;
+ }
+
+ public String getLineEnding() {
+ return lineEnding;
+ }
+ }
+
+ public 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;
+ }
+
+ /**
+ * Look for installations of your IDE in the usual places.
+ *
+ * @param locations Add to this list any valid locations that you found.
+ * @param problems
+ * Add to this list any locations that look like installations,
+ * but have problems that prevent you from installing/uninstalling from them. DONT add to this list
+ * any common locations that have no installation at all - only add near misses.
+ */
+ public abstract void findIdes(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems);
+}
diff --git a/src/installer/lombok/installer/IdeLocation.java b/src/installer/lombok/installer/IdeLocation.java
new file mode 100644
index 00000000..e23a0033
--- /dev/null
+++ b/src/installer/lombok/installer/IdeLocation.java
@@ -0,0 +1,74 @@
+/*
+ * 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.File;
+import java.io.IOException;
+import java.net.URL;
+
+import lombok.patcher.inject.LiveInjector;
+
+/**
+ * Represents a location that contains an IDE.
+ */
+public abstract class IdeLocation {
+ /** Toggling the 'selected' checkbox in the GUI is tracked via this boolean */
+ boolean selected = true;
+
+ public abstract String install() throws InstallException;
+ public abstract void uninstall() throws UninstallException;
+ public abstract String getName();
+ public abstract boolean hasLombok();
+ public abstract URL getIdeIcon();
+
+ /**
+ * 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.
+ */
+ public static File findOurJar() {
+ return new File(LiveInjector.findPathJar(IdeFinder.class));
+ }
+
+ /**
+ * Returns a full path to the provided file.
+ * Returns the canonical path, unless that is not available, in which cae it returns the absolute path.
+ */
+ public static String canonical(File p) {
+ try {
+ return p.getCanonicalPath();
+ } catch (IOException e) {
+ String x = p.getAbsolutePath();
+ return x == null ? p.getPath() : x;
+ }
+ }
+
+ private static final String LEGAL_PATH_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_/";
+ public static String escapePath(String path) {
+ StringBuilder out = new StringBuilder();
+
+ for (char c : path.toCharArray()) {
+ if (LEGAL_PATH_CHARS.indexOf(c) == -1) out.append('\\');
+ out.append(c);
+ }
+ return out.toString();
+ }
+}
diff --git a/src/installer/lombok/installer/IdeLocationProvider.java b/src/installer/lombok/installer/IdeLocationProvider.java
new file mode 100644
index 00000000..e98e199d
--- /dev/null
+++ b/src/installer/lombok/installer/IdeLocationProvider.java
@@ -0,0 +1,40 @@
+/*
+ * 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.regex.Pattern;
+
+import lombok.installer.IdeFinder.OS;
+
+public interface IdeLocationProvider {
+ /**
+ * @throws CorruptedIdeLocationException
+ * Only throw this exception if the location seems like a proper installation except there's something wrong with it.
+ * Do not throw it (just return {@code null}) if there's nothing there or it looks absolutely nothing like your IDE.
+ */
+ public abstract IdeLocation create(String path) throws CorruptedIdeLocationException;
+
+ /**
+ * Return the usual name of the IDE executable or other obvious marker of an IDE installation on the provided platform.
+ */
+ public abstract Pattern getLocationSelectors(OS os);
+}
diff --git a/src/installer/lombok/installer/InstallException.java b/src/installer/lombok/installer/InstallException.java
new file mode 100644
index 00000000..41879604
--- /dev/null
+++ b/src/installer/lombok/installer/InstallException.java
@@ -0,0 +1,10 @@
+package lombok.installer;
+
+/**
+ * Thrown when installation of lombok into an IDE fails.
+ */
+public class InstallException extends Exception {
+ public InstallException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/installer/lombok/installer/Installer.java b/src/installer/lombok/installer/Installer.java
index d4b31251..9ed9e93a 100644
--- a/src/installer/lombok/installer/Installer.java
+++ b/src/installer/lombok/installer/Installer.java
@@ -21,55 +21,23 @@
*/
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.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
-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.Lombok;
import lombok.core.LombokApp;
+import lombok.core.SpiLoadUtil;
import lombok.core.Version;
-import lombok.installer.EclipseFinder.OS;
-import lombok.installer.EclipseLocation.InstallException;
-import lombok.installer.EclipseLocation.NotAnEclipseException;
-import lombok.installer.EclipseLocation.UninstallException;
+import lombok.installer.IdeFinder.OS;
import org.mangosdk.spi.ProviderFor;
@@ -77,6 +45,7 @@ import com.zwitserloot.cmdreader.CmdReader;
import com.zwitserloot.cmdreader.Description;
import com.zwitserloot.cmdreader.InvalidCommandLineException;
import com.zwitserloot.cmdreader.Parameterized;
+import com.zwitserloot.cmdreader.Sequential;
import com.zwitserloot.cmdreader.Shorthand;
/**
@@ -86,24 +55,49 @@ import com.zwitserloot.cmdreader.Shorthand;
* and looks in some common places on Mac OS X, Linux and Windows.
*/
public class Installer {
- private static final URI ABOUT_LOMBOK_URL = URI.create("http://projectlombok.org");
- private static final AtomicReference<Integer> exitMarker = new AtomicReference<Integer>();
+ static final URI ABOUT_LOMBOK_URL = URI.create("http://projectlombok.org");
+ static final List<IdeLocationProvider> locationProviders;
- private JFrame appWindow;
+ static {
+ List<IdeLocationProvider> list = new ArrayList<IdeLocationProvider>();
+ try {
+ for (IdeLocationProvider provider : SpiLoadUtil.findServices(IdeLocationProvider.class)) {
+ list.add(provider);
+ }
+ } catch (IOException e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ locationProviders = Collections.unmodifiableList(list);
+ }
- private JComponent loadingExpl;
-
- private Component javacArea;
- private Component eclipseArea;
- private Component uninstallArea;
- private Component howIWorkArea;
-
- private Box uninstallBox;
- private List<EclipseLocation> toUninstall;
+ static List<Pattern> getIdeExecutableNames() {
+ OS os = IdeFinder.getOS();
+ List<Pattern> list = new ArrayList<Pattern>();
+ for (IdeLocationProvider provider : locationProviders) {
+ Pattern p = provider.getLocationSelectors(os);
+ if (p != null) list.add(p);
+ }
+ return list;
+ }
+
+ static IdeLocation tryAllProviders(String location) throws CorruptedIdeLocationException {
+ for (IdeLocationProvider provider : locationProviders) {
+ IdeLocation loc = provider.create(location);
+ if (loc != null) return loc;
+ }
+
+ return null;
+ }
- private JHyperLink uninstallButton;
- private JLabel uninstallPlaceholder;
- private JButton installButton;
+ static void autoDiscover(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
+ try {
+ for (IdeFinder finder : SpiLoadUtil.findServices(IdeFinder.class)) {
+ finder.findIdes(locations, problems);
+ }
+ } catch (IOException e) {
+ throw Lombok.sneakyThrow(e);
+ }
+ }
@ProviderFor(LombokApp.class)
public static class GraphicalInstallerApp implements LombokApp {
@@ -163,7 +157,7 @@ public class Installer {
}
private static int guiInstaller() {
- if (EclipseFinder.getOS() == OS.MAC_OS_X) {
+ if (IdeFinder.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");
}
@@ -176,22 +170,22 @@ public class Installer {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ignore) {}
- new Installer().show();
+ new InstallerGUI().show();
} catch (HeadlessException e) {
printHeadlessInfo();
}
}
});
- synchronized (exitMarker) {
- while (!Thread.interrupted() && exitMarker.get() == null) {
+ synchronized (InstallerGUI.exitMarker) {
+ while (!Thread.interrupted() && InstallerGUI.exitMarker.get() == null) {
try {
- exitMarker.wait();
+ InstallerGUI.exitMarker.wait();
} catch (InterruptedException e) {
return 1;
}
}
- Integer errCode = exitMarker.get();
+ Integer errCode = InstallerGUI.exitMarker.get();
return errCode == null ? 1 : errCode;
}
} catch (HeadlessException e) {
@@ -201,12 +195,12 @@ public class Installer {
}
private static class CmdArgs {
- @Shorthand("e")
- @Description("Specify a path to an eclipse location to install/uninstall. Use 'auto' to apply to all automatically discoverable eclipse installations.")
+ @Description("Specify paths to a location to install/uninstall. Use 'auto' to apply to all automatically discoverable installations.")
@Parameterized
- List<String> eclipse = new ArrayList<String>();
+ @Sequential
+ List<String> path = new ArrayList<String>();
- @Shorthand({"?", "h"})
+ @Shorthand({"h", "?"})
@Description("Shows this help text")
boolean help;
}
@@ -228,30 +222,33 @@ public class Installer {
return 0;
}
- if (args.eclipse.isEmpty()) {
+ if (args.path.isEmpty()) {
System.err.println("ERROR: Nothing to do!");
System.err.println("--------------------------");
System.err.println(generateCliHelp(uninstall, reader));
return 1;
}
- final List<EclipseLocation> locations = new ArrayList<EclipseLocation>();
- final List<NotAnEclipseException> problems = new ArrayList<NotAnEclipseException>();
+ final List<IdeLocation> locations = new ArrayList<IdeLocation>();
+ final List<CorruptedIdeLocationException> problems = new ArrayList<CorruptedIdeLocationException>();
+
+ if (args.path.contains("auto")) autoDiscover(locations, problems);
- for (String rawPath : args.eclipse) {
- if (rawPath.equals("auto")) {
- EclipseFinder.findEclipses(locations, problems);
- } else {
+ for (String rawPath : args.path) {
+ if (!rawPath.equals("auto")) {
try {
- locations.add(EclipseLocation.create(rawPath));
- } catch (NotAnEclipseException e) {
+ IdeLocation loc = tryAllProviders(rawPath);
+ if (loc != null) locations.add(loc);
+ else problems.add(new CorruptedIdeLocationException("Can't find any IDE at: " + rawPath, null, null));
+ locations.add(tryAllProviders(rawPath));
+ } catch (CorruptedIdeLocationException e) {
problems.add(e);
}
}
}
int validLocations = locations.size();
- for (EclipseLocation loc : locations) {
+ for (IdeLocation loc : locations) {
try {
if (uninstall) {
loc.uninstall();
@@ -270,7 +267,7 @@ public class Installer {
}
}
- for (NotAnEclipseException problem : problems) {
+ for (CorruptedIdeLocationException problem : problems) {
System.err.println("WARNING: " + problem.getMessage());
}
@@ -301,695 +298,4 @@ public class Installer {
" java -cp lombok.jar MyCode.java\n",
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);
- synchronized (exitMarker) {
- exitMarker.set(0);
- exitMarker.notifyAll();
- }
- }
- });
-
- if (!success.get()) SwingUtilities.invokeLater(new Runnable() {
- @Override public void run() {
- synchronized (exitMarker) {
- exitMarker.set(1);
- exitMarker.notifyAll();
- }
- }
- });
- }
- }.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/InstallerGUI.java b/src/installer/lombok/installer/InstallerGUI.java
new file mode 100644
index 00000000..7d266546
--- /dev/null
+++ b/src/installer/lombok/installer/InstallerGUI.java
@@ -0,0 +1,796 @@
+/*
+ * 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.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.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
+
+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.filechooser.FileFilter;
+
+import lombok.core.Version;
+import lombok.installer.IdeFinder.OS;
+
+/**
+ * The lombok GUI installer.
+ * Uses swing to show a simple GUI that can add and remove the java agent to IDE installations.
+ * Also offers info on what this installer does in case people want to instrument their IDE manually.
+ */
+public class InstallerGUI {
+ static final AtomicReference<Integer> exitMarker = new AtomicReference<Integer>();
+
+ private JFrame appWindow;
+
+ private JComponent loadingExpl;
+
+ private Component javacArea;
+ private Component ideArea;
+ private Component uninstallArea;
+ private Component howIWorkArea;
+
+ private Box uninstallBox;
+ private JHyperLink uninstallButton;
+ private JLabel uninstallPlaceholder;
+ private JButton installButton;
+
+ private List<IdeLocation> toUninstall;
+ private final Set<String> installSpecificMessages = new LinkedHashSet<String>();
+
+ /**
+ * Creates a new installer that starts out invisible.
+ * Call the {@link #show()} method on a freshly created installer to render it.
+ */
+ public InstallerGUI() {
+ 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();
+ ideArea = buildIdeArea();
+ 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.separator)), 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);
+ ideArea.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);
+ ideArea.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 buildIdeArea() {
+ 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(IDE_TITLE), constraints);
+
+ constraints.gridy = 1;
+ container.add(new JLabel(IDE_EXPLANATION), constraints);
+
+ constraints.gridy = 2;
+ loadingExpl = Box.createHorizontalBox();
+ loadingExpl.add(new JLabel(new ImageIcon(Installer.class.getResource("loading.gif"))));
+ loadingExpl.add(new JLabel(IDE_LOADING_EXPLANATION));
+ container.add(loadingExpl, constraints);
+
+ constraints.weightx = 1.0;
+ constraints.gridy = 3;
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+ idesList = new IdesList();
+
+ JScrollPane idesListScroll = new JScrollPane(idesList);
+ idesListScroll.setBackground(Color.WHITE);
+ idesListScroll.getViewport().setBackground(Color.WHITE);
+ container.add(idesListScroll, constraints);
+
+ Thread findIdesThread = new Thread() {
+ @Override public void run() {
+ try {
+ final List<IdeLocation> locations = new ArrayList<IdeLocation>();
+ final List<CorruptedIdeLocationException> problems = new ArrayList<CorruptedIdeLocationException>();
+ Installer.autoDiscover(locations, problems);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ for (IdeLocation location : locations) {
+ try {
+ idesList.addLocation(location);
+ } catch (Throwable t) {
+ handleException(t);
+ }
+ }
+
+ for (CorruptedIdeLocationException problem : problems) {
+ problem.showDialog(appWindow);
+ }
+
+ loadingExpl.setVisible(false);
+
+ if (locations.size() + problems.size() == 0) {
+ JOptionPane.showMessageDialog(appWindow,
+ "I can't find any IDEs on your computer.\n" +
+ "If you have IDEs installed on this computer, please use the " +
+ "'Specify Location...' button to manually point out the \n" +
+ "location of your IDE installation to me. Thanks!",
+ "Can't find IDE", JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
+ });
+ } catch (Throwable t) {
+ handleException(t);
+ }
+ }
+ };
+
+ findIdesThread.start();
+
+ Box buttonBar = Box.createHorizontalBox();
+ JButton specifyIdeLocationButton = new JButton("Specify location...");
+ buttonBar.add(specifyIdeLocationButton);
+ specifyIdeLocationButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent event) {
+ final List<Pattern> exeNames = Installer.getIdeExecutableNames();
+ String file = null;
+
+ if (IdeFinder.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) {
+ for (Pattern exeName : exeNames) if (exeName.matcher(fileName).matches()) 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) {
+ for (Pattern exeName : exeNames) if (exeName.matcher(f.getName()).matches()) return true;
+ if (f.isDirectory()) return true;
+
+ return false;
+ }
+
+ @Override public String getDescription() {
+ return "IDE Installation";
+ }
+ });
+
+ switch (chooser.showDialog(appWindow, "Select")) {
+ case JFileChooser.APPROVE_OPTION:
+ file = chooser.getSelectedFile().getAbsolutePath();
+ }
+ }
+
+ if (file != null) {
+ try {
+ IdeLocation loc = Installer.tryAllProviders(file);
+ if (loc != null) idesList.addLocation(loc);
+ else JOptionPane.showMessageDialog(appWindow, "I can't find any IDE that lombok supports at location: " + file, "No IDE found", JOptionPane.WARNING_MESSAGE);
+ } catch (CorruptedIdeLocationException 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<IdeLocation> locationsToInstall = new ArrayList<IdeLocation>(idesList.getSelectedIdes());
+ if (locationsToInstall.isEmpty()) {
+ JOptionPane.showMessageDialog(appWindow, "You haven't selected any IDE 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 IDE 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 IDE installations.");
+ uninstallPlaceholder = new JLabel("<html>&nbsp;</html>");
+ uninstallButton.addActionListener(new ActionListener() {
+ @Override public void actionPerformed(ActionEvent e) {
+ List<IdeLocation> locationsToUninstall = new ArrayList<IdeLocation>();
+ for (IdeLocation location : idesList.getSelectedIdes()) {
+ if (location.hasLombok()) locationsToUninstall.add(location);
+ }
+
+ if (locationsToUninstall.isEmpty()) {
+ JOptionPane.showMessageDialog(appWindow, "You haven't selected any IDE 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);
+ ideArea.setVisible(false);
+ howIWorkArea.setVisible(true);
+ appWindow.pack();
+ }
+
+ private void uninstall(List<IdeLocation> locations) {
+ javacArea.setVisible(false);
+ ideArea.setVisible(false);
+
+ uninstallBox.removeAll();
+ uninstallBox.add(Box.createRigidArea(new Dimension(1, 16)));
+ for (IdeLocation 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<IdeLocation> toInstall) {
+ JPanel spinner = new JPanel();
+ spinner.setOpaque(true);
+ spinner.setLayout(new FlowLayout());
+ spinner.add(new JLabel(new ImageIcon(Installer.class.getResource("loading.gif"))));
+ appWindow.setContentPane(spinner);
+
+ final AtomicReference<Boolean> success = new AtomicReference<Boolean>(true);
+
+ new Thread() {
+ @Override public void run() {
+ for (IdeLocation loc : toInstall) {
+ try {
+ installSpecificMessages.add(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() {
+ StringBuilder installSpecific = new StringBuilder();
+ for (String installSpecificMessage : installSpecificMessages) {
+ installSpecific.append("<br>").append(installSpecificMessage);
+ }
+ JOptionPane.showMessageDialog(appWindow,
+ "<html>Lombok has been installed on the selected IDE installations.<br>" +
+ "Don't forget to add <code>lombok.jar</code> to your projects, and restart your IDE!" + installSpecific.toString() + "</html>",
+ "Install successful",
+ JOptionPane.INFORMATION_MESSAGE);
+ appWindow.setVisible(false);
+ synchronized (exitMarker) {
+ exitMarker.set(0);
+ exitMarker.notifyAll();
+ }
+ }
+ });
+
+ if (!success.get()) SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ synchronized (exitMarker) {
+ exitMarker.set(1);
+ exitMarker.notifyAll();
+ }
+ }
+ });
+ }
+ }.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 (IdeLocation 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 IDE installations.", "Uninstall successful", JOptionPane.INFORMATION_MESSAGE);
+ appWindow.setVisible(false);
+ System.exit(0);
+ }
+ });
+ }
+ }.start();
+ }
+
+ private IdesList idesList = new IdesList();
+
+ void selectedLomboksChanged(List<IdeLocation> selectedIdes) {
+ boolean uninstallAvailable = false;
+ boolean installAvailable = false;
+ for (IdeLocation loc : selectedIdes) {
+ if (loc.hasLombok()) uninstallAvailable = true;
+ installAvailable = true;
+ }
+
+ uninstallButton.setVisible(uninstallAvailable);
+ uninstallPlaceholder.setVisible(!uninstallAvailable);
+ installButton.setEnabled(installAvailable);
+ }
+
+ private class IdesList extends JPanel implements Scrollable {
+ private static final long serialVersionUID = 1L;
+
+ List<IdeLocation> locations = new ArrayList<IdeLocation>();
+
+ IdesList() {
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ setBackground(Color.WHITE);
+ }
+
+ List<IdeLocation> getSelectedIdes() {
+ List<IdeLocation> list = new ArrayList<IdeLocation>();
+ for (IdeLocation loc : locations) if (loc.selected) list.add(loc);
+ return list;
+ }
+
+ void fireSelectionChange() {
+ selectedLomboksChanged(getSelectedIdes());
+ }
+
+ void addLocation(final IdeLocation 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(new JLabel(new ImageIcon(location.getIdeIcon())));
+ 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("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.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(ideArea, 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(Installer.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, Installer.ABOUT_LOMBOK_URL);
+ } catch (Exception e) {
+ Runtime rt = Runtime.getRuntime();
+ try {
+ switch (IdeFinder.getOS()) {
+ case WINDOWS:
+ String[] cmd = new String[4];
+ cmd[0] = "cmd.exe";
+ cmd[1] = "/C";
+ cmd[2] = "start";
+ cmd[3] = Installer.ABOUT_LOMBOK_URL.toString();
+ rt.exec(cmd);
+ break;
+ case MAC_OS_X:
+ rt.exec("open " + Installer.ABOUT_LOMBOK_URL.toString());
+ break;
+ default:
+ case UNIX:
+ rt.exec("firefox " + Installer.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" + Installer.ABOUT_LOMBOK_URL +
+ " 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 (IdeFinder.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 IDE_TITLE =
+ "<html><font size=\"+1\"><b><i>IDEs</i></b></font></html>";
+
+ private static final String IDE_EXPLANATION =
+ "<html>Lombok can update your Eclipse and Netbeans to fully support all Lombok features.<br>" +
+ "Select IDE installations below and hit 'Install/Update'.</html>";
+
+ private static final String IDE_LOADING_EXPLANATION =
+ "Scanning your drives for IDE 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 IDE 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><h2>Eclipse</h2><ol>" +
+ "<li>First, I copy myself (lombok.jar) to your Eclipse install directory.</li>" +
+ "<li>Then, I edit the <i>eclipse.ini</i> file to add the following two entries:<br>" +
+ "<pre>-Xbootclasspath/a:lombok.jar<br>" +
+ "-javaagent:lombok.jar</pre></li></ol>" +
+ "On Mac OS X, eclipse.ini is hidden in<br>" +
+ "<code>Eclipse.app/Contents/MacOS</code> so that's where I place the jar files.<p>" +
+ "<h2>Netbeans</h2><ol>" +
+ "<li>First, I copy myself (lombok.jar) to your Netbeans install directory.</li>" +
+ "<lI>Then, I edit <i>etc%1$snetbeans.conf</i> to add the following argument to<br><b>netbeans_default_options</b>:<br>" +
+ "<pre>-J-javaagent:lombok.jar</pre></li></ol>" +
+ "On Mac OS X, your netbeans directory is hidden in<br>" +
+ "<code>NetBeans.app/Contents/Resources/NetBeans</code></html>";
+
+ 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));
+ }
+ }
+}
diff --git a/src/installer/lombok/installer/UninstallException.java b/src/installer/lombok/installer/UninstallException.java
new file mode 100644
index 00000000..dda6c143
--- /dev/null
+++ b/src/installer/lombok/installer/UninstallException.java
@@ -0,0 +1,10 @@
+package lombok.installer;
+
+/**
+ * Thrown when uninstallation of lombok into an IDE fails.
+ */
+public class UninstallException extends Exception {
+ public UninstallException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/src/installer/lombok/installer/EclipseFinder.java b/src/installer/lombok/installer/eclipse/EclipseFinder.java
index 8e45852c..256e6221 100644
--- a/src/installer/lombok/installer/EclipseFinder.java
+++ b/src/installer/lombok/installer/eclipse/EclipseFinder.java
@@ -19,120 +19,22 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package lombok.installer;
+package lombok.installer.eclipse;
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;
+import lombok.installer.IdeFinder;
+import lombok.installer.IdeLocation;
+import lombok.installer.CorruptedIdeLocationException;
-/** 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;
- }
-
+import org.mangosdk.spi.ProviderFor;
+
+@ProviderFor(IdeFinder.class)
+public class EclipseFinder extends IdeFinder {
/**
* Returns a list of paths of Eclipse installations.
* Eclipse installations are found by checking for the existence of 'eclipse.exe' in the following locations:
@@ -144,7 +46,7 @@ class EclipseFinder {
* 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) {
+ private static void findEclipseOnWindows(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
List<String> driveLetters = asList("C");
try {
driveLetters = getDrivesOnWindows();
@@ -165,8 +67,8 @@ class EclipseFinder {
String eclipseLocation = findEclipseOnWindows1(dir);
if (eclipseLocation != null) {
try {
- locations.add(EclipseLocation.create(eclipseLocation));
- } catch (NotAnEclipseException e) {
+ locations.add(EclipseLocationProvider.create0(eclipseLocation));
+ } catch (CorruptedIdeLocationException e) {
problems.add(e);
}
}
@@ -177,12 +79,12 @@ class EclipseFinder {
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 (dir2.getName().toLowerCase().contains("eclipse")) {
+ String eclipseLocation = findEclipseOnWindows1(dir2);
if (eclipseLocation != null) {
try {
- locations.add(EclipseLocation.create(eclipseLocation));
- } catch (NotAnEclipseException e) {
+ locations.add(EclipseLocationProvider.create0(eclipseLocation));
+ } catch (CorruptedIdeLocationException e) {
problems.add(e);
}
}
@@ -213,7 +115,8 @@ class EclipseFinder {
* eclipses that can't be installed. Provide an empty list; this
* method will fill it.
*/
- static void findEclipses(List<EclipseLocation> locations, List<NotAnEclipseException> problems) {
+ @Override
+ public void findIdes(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
switch (getOS()) {
case WINDOWS:
findEclipseOnWindows(locations, problems);
@@ -228,38 +131,8 @@ class EclipseFinder {
}
}
- 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) {
+ private void findEclipseOnUnix(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
List<String> guesses = new ArrayList<String>();
File d;
@@ -278,14 +151,14 @@ class EclipseFinder {
for (String guess : guesses) {
try {
- locations.add(EclipseLocation.create(guess));
- } catch (NotAnEclipseException e) {
+ locations.add(EclipseLocationProvider.create0(guess));
+ } catch (CorruptedIdeLocationException e) {
problems.add(e);
}
}
}
- private static void findEclipseInSubDir(String dir, List<String> guesses) {
+ private void findEclipseInSubDir(String dir, List<String> guesses) {
File d = new File(dir);
if (!d.isDirectory()) return;
for (File f : d.listFiles()) {
@@ -299,23 +172,23 @@ class EclipseFinder {
/**
* Scans /Applications for any folder named 'Eclipse'
*/
- private static void findEclipseOnMac(List<EclipseLocation> locations, List<NotAnEclipseException> problems) {
+ private void findEclipseOnMac(List<IdeLocation> locations, List<CorruptedIdeLocationException> 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) {
+ locations.add(EclipseLocationProvider.create0("/Applications"));
+ } catch (CorruptedIdeLocationException 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) {
+ locations.add(EclipseLocationProvider.create0(dir.toString()));
+ } catch (CorruptedIdeLocationException e) {
problems.add(e);
}
}
diff --git a/src/installer/lombok/installer/EclipseLocation.java b/src/installer/lombok/installer/eclipse/EclipseLocation.java
index c43c5042..7b3a5536 100644
--- a/src/installer/lombok/installer/EclipseLocation.java
+++ b/src/installer/lombok/installer/eclipse/EclipseLocation.java
@@ -19,7 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-package lombok.installer;
+package lombok.installer.eclipse;
import java.io.BufferedReader;
import java.io.File;
@@ -28,162 +28,39 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.net.URL;
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;
+import lombok.installer.CorruptedIdeLocationException;
+import lombok.installer.IdeFinder;
+import lombok.installer.IdeLocation;
+import lombok.installer.InstallException;
+import lombok.installer.UninstallException;
/**
* 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";
- }
-
+public final class EclipseLocation extends IdeLocation {
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;
+ private static final String OS_NEWLINE = IdeFinder.getOS().getLineEnding();
- /**
- * 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 {
+ EclipseLocation(String nameOfLocation, File pathToEclipseIni) throws CorruptedIdeLocationException {
this.name = nameOfLocation;
this.eclipseIniPath = pathToEclipseIni;
try {
this.hasLombok = checkForLombok(eclipseIniPath);
} catch (IOException e) {
- throw new NotAnEclipseException(
+ throw new CorruptedIdeLocationException(
"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;
+ "You may need to run this installer with root privileges if you want to modify that Eclipse.", "eclipse", e);
}
}
@@ -201,14 +78,16 @@ final class EclipseLocation {
*
* Executables: "eclipse.exe" (Windows), "Eclipse.app" (Mac OS X), "eclipse" (Linux and other unixes).
*/
- String getName() {
+ @Override
+ public String getName() {
return name;
}
/**
* @return true if the Eclipse installation has been instrumented with lombok.
*/
- boolean hasLombok() {
+ @Override
+ public boolean hasLombok() {
return hasLombok;
}
@@ -234,15 +113,6 @@ final class EclipseLocation {
}
}
- /** 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>();
@@ -263,7 +133,8 @@ final class EclipseLocation {
* installation. bugs in the uninstall code will probably throw
* other exceptions; this is intentional.
*/
- void uninstall() throws UninstallException {
+ @Override
+ public void uninstall() throws UninstallException {
for (File dir : getUninstallDirs()) {
File lombokJar = new File(dir, "lombok.jar");
if (lombokJar.exists()) {
@@ -327,19 +198,10 @@ final class EclipseLocation {
}
}
- /** 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()) {
+ switch (IdeFinder.getOS()) {
default:
case MAC_OS_X:
case UNIX:
@@ -363,21 +225,20 @@ final class EclipseLocation {
* installation. bugs in the install code will probably throw
* other exceptions; this is intentional.
*/
- void install() throws InstallException {
+ @Override
+ public String 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 fullPathRequired = IdeFinder.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();
+ File ourJar = findOurJar();
byte[] b = new byte[524288];
boolean readSucceeded = true;
try {
@@ -448,9 +309,9 @@ final class EclipseLocation {
String fullPathToLombok = fullPathRequired ? (lombokJar.getParentFile().getCanonicalPath() + File.separator) : "";
newContents.append(String.format(
- "-javaagent:%slombok.jar", fullPathToLombok)).append(OS_NEWLINE);
+ "-javaagent:%s", escapePath(fullPathToLombok + "lombok.jar"))).append(OS_NEWLINE);
newContents.append(String.format(
- "-Xbootclasspath/a:%slombok.jar", fullPathToLombok)).append(OS_NEWLINE);
+ "-Xbootclasspath/a:%s", escapePath(fullPathToLombok + "lombok.jar"))).append(OS_NEWLINE);
FileOutputStream fos = new FileOutputStream(eclipseIniPath);
try {
@@ -470,5 +331,13 @@ final class EclipseLocation {
if (!installSucceeded) {
throw new InstallException("I can't find the eclipse.ini file. Is this a real Eclipse installation?", null);
}
+
+ return "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.";
+ }
+
+ @Override public URL getIdeIcon() {
+ return EclipseLocation.class.getResource("eclipse.png");
}
}
diff --git a/src/installer/lombok/installer/eclipse/EclipseLocationProvider.java b/src/installer/lombok/installer/eclipse/EclipseLocationProvider.java
new file mode 100644
index 00000000..0cef59f4
--- /dev/null
+++ b/src/installer/lombok/installer/eclipse/EclipseLocationProvider.java
@@ -0,0 +1,144 @@
+/*
+ * 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.eclipse;
+
+import static lombok.installer.IdeLocation.canonical;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import lombok.installer.IdeLocation;
+import lombok.installer.IdeLocationProvider;
+import lombok.installer.CorruptedIdeLocationException;
+import lombok.installer.IdeFinder.OS;
+
+import org.mangosdk.spi.ProviderFor;
+
+@ProviderFor(IdeLocationProvider.class)
+public class EclipseLocationProvider implements IdeLocationProvider {
+ @Override public IdeLocation create(String path) throws CorruptedIdeLocationException {
+ return create0(path);
+ }
+
+ 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 contains the Eclipse executable, or the executable itself,
+ * or an eclipse.ini file.
+ *
+ * @throws NotAnIdeLocationException
+ * If this isn't an Eclipse executable or a directory with an
+ * Eclipse executable.
+ */
+ static EclipseLocation create0(String path) throws CorruptedIdeLocationException {
+ if (path == null) throw new NullPointerException("path");
+ File p = new File(path);
+
+ if (!p.exists()) return 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(canonical(p), f);
+ }
+
+ if (p.isFile()) {
+ if (p.getName().equalsIgnoreCase("eclipse.ini")) {
+ return new EclipseLocation(canonical(p.getParentFile()), p);
+ }
+
+ if (eclipseExecutableNames.contains(p.getName().toLowerCase())) {
+ return findEclipseIniFromExe(p, 0);
+ }
+ }
+
+ return null;
+ }
+
+ private static EclipseLocation findEclipseIniFromExe(File exePath, int loopCounter) throws CorruptedIdeLocationException {
+ /* Try looking for eclipse.ini as sibling to the executable */ {
+ File ini = new File(exePath.getParentFile(), "eclipse.ini");
+ if (ini.isFile()) return new EclipseLocation(canonical(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(canonical(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 {
+ EclipseLocation loc = findEclipseIniFromExe(new File(nPath), loopCounter + 1);
+ if (loc != null) return loc;
+ } catch (CorruptedIdeLocationException 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. */
+ return null;
+ }
+
+ @Override public Pattern getLocationSelectors(OS os) {
+ switch (os) {
+ case MAC_OS_X:
+ return Pattern.compile("^(eclipse|eclipse\\.ini|eclipse\\.app)$", Pattern.CASE_INSENSITIVE);
+ case WINDOWS:
+ return Pattern.compile("^(eclipse\\.exe|eclipse\\.ini)$", Pattern.CASE_INSENSITIVE);
+ default:
+ case UNIX:
+ return Pattern.compile("^(eclipse|eclipse\\.ini)$", Pattern.CASE_INSENSITIVE);
+ }
+ }
+}
diff --git a/src/installer/lombok/installer/eclipse/eclipse.png b/src/installer/lombok/installer/eclipse/eclipse.png
new file mode 100644
index 00000000..ba652d33
--- /dev/null
+++ b/src/installer/lombok/installer/eclipse/eclipse.png
Binary files differ
diff --git a/src/installer/lombok/installer/netbeans/NetbeansFinder.java b/src/installer/lombok/installer/netbeans/NetbeansFinder.java
new file mode 100644
index 00000000..5186d639
--- /dev/null
+++ b/src/installer/lombok/installer/netbeans/NetbeansFinder.java
@@ -0,0 +1,201 @@
+/*
+ * 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.netbeans;
+
+import static java.util.Arrays.asList;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import lombok.installer.CorruptedIdeLocationException;
+import lombok.installer.IdeFinder;
+import lombok.installer.IdeLocation;
+
+import org.mangosdk.spi.ProviderFor;
+
+/** Utility class for doing various OS-specific operations related to finding Netbeans installations. */
+@ProviderFor(IdeFinder.class)
+public class NetbeansFinder extends IdeFinder {
+ /**
+ * Returns a list of paths of Netbeans installations.
+ *
+ * Netbeans installations are found by checking for the existence of 'netbeans.exe' in the following locations:
+ * <ul>
+ * <li>X:\*Program Files*\*NetBeans*</li>
+ * <li>X:\*NetBeans*</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 void findNetbeansOnWindows(List<IdeLocation> locations, List<CorruptedIdeLocationException> 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("netbeans")) {
+ String netbeansLocation = findNetbeansOnWindows1(dir);
+ if (netbeansLocation != null) {
+ try {
+ locations.add(NetbeansLocationProvider.create0(netbeansLocation));
+ } catch (CorruptedIdeLocationException 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 (dir2.getName().toLowerCase().contains("netbeans")) {
+ String netbeansLocation = findNetbeansOnWindows1(dir2);
+ if (netbeansLocation != null) {
+ try {
+ locations.add(NetbeansLocationProvider.create0(netbeansLocation));
+ } catch (CorruptedIdeLocationException e) {
+ problems.add(e);
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception ignore) {}
+ }
+ } catch (Exception ignore) {}
+ }
+ }
+
+ /** Checks if the provided directory contains 'netbeans.exe', and if so, returns the directory, otherwise null. */
+ private String findNetbeansOnWindows1(File dir) {
+ if (new File(dir, "netbeans.exe").isFile()) return dir.getAbsolutePath();
+ return null;
+ }
+
+ /**
+ * Calls the OS-dependent 'find Netbeans' routine. If the local OS doesn't have a routine written for it,
+ * null is returned.
+ *
+ * @param locations
+ * List of valid netbeans locations - provide an empty list; this
+ * method will fill it.
+ * @param problems
+ * List of netbeans locations that seem to contain half-baked
+ * netbeanses that can't be installed. Provide an empty list; this
+ * method will fill it.
+ */
+ @Override
+ public void findIdes(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
+ switch (getOS()) {
+ case WINDOWS:
+ findNetbeansOnWindows(locations, problems);
+ break;
+ case MAC_OS_X:
+ findNetbeansOnMac(locations, problems);
+ break;
+ default:
+ case UNIX:
+ findNetbeansOnUnix(locations, problems);
+ break;
+ }
+ }
+
+ /** Scans a couple of likely locations on linux. */
+ private void findNetbeansOnUnix(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
+ List<String> guesses = new ArrayList<String>();
+
+ File d;
+
+ d = new File("/usr/bin/netbeans");
+ if (d.exists()) guesses.add(d.getPath());
+ d = new File("/usr/local/bin/netbeans");
+ if (d.exists()) guesses.add(d.getPath());
+ d = new File(System.getProperty("user.home", "."), "bin/netbeans");
+ if (d.exists()) guesses.add(d.getPath());
+
+ findNetbeansInSubDir("/usr/local/share", guesses);
+ findNetbeansInSubDir("/usr/local", guesses);
+ findNetbeansInSubDir("/usr/share", guesses);
+ findNetbeansInSubDir(System.getProperty("user.home", "."), guesses);
+
+ for (String guess : guesses) {
+ try {
+ locations.add(NetbeansLocationProvider.create0(guess));
+ } catch (CorruptedIdeLocationException e) {
+ problems.add(e);
+ }
+ }
+ }
+
+ private static void findNetbeansInSubDir(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("netbeans")) {
+ File possible = new File(f, "bin/netbeans.exe");
+ if (possible.exists()) guesses.add(possible.getAbsolutePath());
+ }
+ }
+ }
+
+ /**
+ * Scans /Applications for any folder named 'Eclipse'
+ */
+ private static void findNetbeansOnMac(List<IdeLocation> locations, List<CorruptedIdeLocationException> problems) {
+ for (File dir : new File("/Applications").listFiles()) {
+ if (!dir.isDirectory()) continue;
+ if (dir.getName().toLowerCase().startsWith("netbeans") && dir.getName().toLowerCase().endsWith(".app")) {
+ try {
+ locations.add(NetbeansLocationProvider.create0(dir.getAbsolutePath()));
+ } catch (CorruptedIdeLocationException e) {
+ problems.add(e);
+ }
+ }
+ if (dir.getName().toLowerCase().contains("netbeans")) {
+ for (File dir2 : dir.listFiles()) {
+ if (!dir2.isDirectory()) continue;
+ if (dir2.getName().toLowerCase().startsWith("netbeans") && dir2.getName().toLowerCase().endsWith(".app")) {
+ try {
+ locations.add(NetbeansLocationProvider.create0(dir2.getAbsolutePath()));
+ } catch (CorruptedIdeLocationException e) {
+ problems.add(e);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/installer/lombok/installer/netbeans/NetbeansLocation.java b/src/installer/lombok/installer/netbeans/NetbeansLocation.java
new file mode 100644
index 00000000..51acef3d
--- /dev/null
+++ b/src/installer/lombok/installer/netbeans/NetbeansLocation.java
@@ -0,0 +1,282 @@
+/*
+ * 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.netbeans;
+
+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.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import lombok.installer.CorruptedIdeLocationException;
+import lombok.installer.IdeFinder;
+import lombok.installer.IdeLocation;
+import lombok.installer.InstallException;
+import lombok.installer.UninstallException;
+
+public class NetbeansLocation extends IdeLocation {
+ private final String name;
+ private final File netbeansConfPath;
+ private volatile boolean hasLombok;
+
+ private static final String OS_NEWLINE = IdeFinder.getOS().getLineEnding();
+
+ NetbeansLocation(String nameOfLocation, File pathToNetbeansConf) throws CorruptedIdeLocationException {
+ this.name = nameOfLocation;
+ this.netbeansConfPath = pathToNetbeansConf;
+ try {
+ this.hasLombok = checkForLombok(netbeansConfPath);
+ } catch (IOException e) {
+ throw new CorruptedIdeLocationException(
+ "I can't read the configuration file of the Netbeans installed at " + name + "\n" +
+ "You may need to run this installer with root privileges if you want to modify that Netbeans.", "netbeans", e);
+ }
+ }
+
+ @Override public int hashCode() {
+ return netbeansConfPath.hashCode();
+ }
+
+ @Override public boolean equals(Object o) {
+ if (!(o instanceof NetbeansLocation)) return false;
+ return ((NetbeansLocation)o).netbeansConfPath.equals(netbeansConfPath);
+ }
+
+ /**
+ * Returns the name of this location; generally the path to the netbeans executable.
+ */
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return true if the Netbeans installation has been instrumented with lombok.
+ */
+ @Override
+ public boolean hasLombok() {
+ return hasLombok;
+ }
+
+ private final String ID_CHARS = "(?:\\\\.|[^\"\\\\])*";
+ private final String ID_CHARS_NS = "(?:\\\\.|[^\"\\\\ ])*";
+ private final Pattern JAVA_AGENT_LINE_MATCHER = Pattern.compile(
+ "^\\s*netbeans_default_options\\s*=\\s*\"\\s*" + ID_CHARS + "(?<=[ \"])(-J-javaagent:" + ID_CHARS_NS + "lombok" + ID_CHARS_NS + "\\.jar)(?=[ \"])" + ID_CHARS +"\\s*\"\\s*(?:#.*)?$", Pattern.CASE_INSENSITIVE);
+
+ private final Pattern OPTIONS_LINE_MATCHER = Pattern.compile(
+ "^\\s*netbeans_default_options\\s*=\\s*\"\\s*" + ID_CHARS + "\\s*(\")\\s*(?:#.*)?$", 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();
+ }
+ }
+
+ /**
+ * 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.
+ */
+ @Override
+ public void uninstall() throws UninstallException {
+ File dir = netbeansConfPath.getParentFile();
+ File lombokJar = new File(dir, "lombok.jar");
+ if (lombokJar.exists()) {
+ if (!lombokJar.delete()) throw new UninstallException(
+ "Can't delete " + lombokJar.getAbsolutePath() + generateWriteErrorMessage(), null);
+ }
+
+ StringBuilder newContents = new StringBuilder();
+ if (netbeansConfPath.exists()) {
+ try {
+ FileInputStream fis = new FileInputStream(netbeansConfPath);
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ String line;
+ while ((line = br.readLine()) != null) {
+ Matcher m = JAVA_AGENT_LINE_MATCHER.matcher(line);
+ if (m.matches()) {
+ newContents.append(line.substring(0, m.start(1)) + line.substring(m.end(1)));
+ } else {
+ newContents.append(line);
+ }
+ newContents.append(OS_NEWLINE);
+ }
+ } finally {
+ fis.close();
+ }
+
+ FileOutputStream fos = new FileOutputStream(netbeansConfPath);
+ try {
+ fos.write(newContents.toString().getBytes());
+ } finally {
+ fos.close();
+ }
+ } catch (IOException e) {
+ throw new UninstallException("Cannot uninstall lombok from " + name + generateWriteErrorMessage(), e);
+ }
+ }
+ }
+
+ private static String generateWriteErrorMessage() {
+ String osSpecificError;
+
+ switch (IdeFinder.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 Netbeans 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.
+ */
+ @Override
+ public String install() throws InstallException {
+ boolean installSucceeded = false;
+ StringBuilder newContents = new StringBuilder();
+
+ File lombokJar = new File(netbeansConfPath.getParentFile(), "lombok.jar");
+
+ File ourJar = 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 Netbeans directory at " + name + generateWriteErrorMessage(), e);
+ }
+
+ try {
+ FileInputStream fis = new FileInputStream(netbeansConfPath);
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis));
+ String line;
+ while ((line = br.readLine()) != null) {
+ Matcher m = JAVA_AGENT_LINE_MATCHER.matcher(line);
+ if (m.matches()) {
+ newContents.append(line.substring(0, m.start(1)));
+ newContents.append("-J-javaagent:" + escapePath(canonical(lombokJar)));
+ newContents.append(line.substring(m.end(1)));
+ newContents.append(OS_NEWLINE);
+ continue;
+ }
+
+ m = OPTIONS_LINE_MATCHER.matcher(line);
+ if (m.matches()) {
+ newContents.append(line.substring(0, m.start(1)));
+ newContents.append(" ").append("-J-javaagent:" + escapePath(canonical(lombokJar)) +"\"");
+ newContents.append(line.substring(m.end(1))).append(OS_NEWLINE);
+ continue;
+ }
+
+ newContents.append(line).append(OS_NEWLINE);
+ }
+ } finally {
+ fis.close();
+ }
+
+ FileOutputStream fos = new FileOutputStream(netbeansConfPath);
+ 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 netbeans.conf file. Is this a real Netbeans installation?", null);
+ }
+
+ return "If you start netbeans with custom parameters, you'll need to add:<br>" +
+ "<code>-J-javaagent:" + escapePath(canonical(lombokJar)) + "</code><br>" +
+ "as parameter as well.";
+ }
+
+ @Override public URL getIdeIcon() {
+ return NetbeansLocation.class.getResource("netbeans.png");
+ }
+}
diff --git a/src/installer/lombok/installer/netbeans/NetbeansLocationProvider.java b/src/installer/lombok/installer/netbeans/NetbeansLocationProvider.java
new file mode 100644
index 00000000..1bc699f1
--- /dev/null
+++ b/src/installer/lombok/installer/netbeans/NetbeansLocationProvider.java
@@ -0,0 +1,125 @@
+/*
+ * 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.netbeans;
+
+import static lombok.installer.IdeLocation.canonical;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.regex.Pattern;
+
+import lombok.installer.CorruptedIdeLocationException;
+import lombok.installer.IdeLocation;
+import lombok.installer.IdeLocationProvider;
+import lombok.installer.IdeFinder.OS;
+
+import org.mangosdk.spi.ProviderFor;
+
+@ProviderFor(IdeLocationProvider.class)
+public class NetbeansLocationProvider implements IdeLocationProvider {
+
+ @Override public IdeLocation create(String path) throws CorruptedIdeLocationException {
+ return create0(path);
+ }
+
+ /**
+ * Create a new NetbeansLocation by pointing at either the directory containing the executable, or the executable itself,
+ * or a netbeans.conf file.
+ *
+ * @throws NotAnIdeLocationException
+ * If this isn't an Eclipse executable or a directory with an
+ * Eclipse executable.
+ */
+ static NetbeansLocation create0(String path) throws CorruptedIdeLocationException {
+ if (path == null) throw new NullPointerException("path");
+ File p = new File(path);
+
+ if (!p.exists()) return null;
+ if (p.isDirectory()) {
+ String name = p.getName().toLowerCase();
+ if (name.endsWith(".app") && name.startsWith("netbeans")) {
+ File conf = new File(p, "Contents/Resources/NetBeans/etc/netbeans.conf");
+ if (conf.exists()) return new NetbeansLocation(path, conf);
+ }
+
+ File f = new File(p, "netbeans");
+ if (f.isFile()) return findNetbeansConfFromExe(f, 0);
+ f = new File(p, "netbeans.exe");
+ if (f.isFile()) return findNetbeansConfFromExe(f, 0);
+ f = new File(p, "netbeans.conf");
+ if (f.isFile()) return new NetbeansLocation(canonical(f.getParentFile().getParentFile()), f);
+ }
+
+ if (p.isFile()) {
+ if (p.getName().equalsIgnoreCase("netbeans.conf")) {
+ return new NetbeansLocation(canonical(p.getParentFile().getParentFile()), p);
+ }
+
+ if (p.getName().equalsIgnoreCase("netbeans") || p.getName().equalsIgnoreCase("netbeans.exe")) {
+ return findNetbeansConfFromExe(p, 0);
+ }
+ }
+
+ return null;
+ }
+
+ private static NetbeansLocation findNetbeansConfFromExe(File exePath, int loopCounter) throws CorruptedIdeLocationException {
+ /* Try looking for netbeans.conf as etc/netbeans.conf */ {
+ File conf = new File(exePath.getParentFile(), "etc/netbeans.conf");
+ if (conf.isFile()) return new NetbeansLocation(canonical(exePath), conf);
+ }
+
+ /* Try looking for netbeans.conf as ../etc/netbeans.conf */ {
+ File conf = new File(exePath.getParentFile().getParentFile(), "etc/netbeans.conf");
+ if (conf.isFile()) return new NetbeansLocation(canonical(exePath), conf);
+ }
+
+ /* 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 findNetbeansConfFromExe(new File(nPath), loopCounter + 1);
+ } catch (CorruptedIdeLocationException ignore) {
+ // Unlinking didn't help find a netbeans, so continue.
+ }
+ } catch (IOException ignore) { /* okay, that didn't work, assume it isn't a soft link then. */ }
+ }
+ }
+
+ /* If we get this far, we lose. */
+ return null;
+ }
+
+ @Override public Pattern getLocationSelectors(OS os) {
+ switch (os) {
+ case MAC_OS_X:
+ return Pattern.compile("^(netbeans|netbeans\\.conf|NetBeans.*\\.app)$", Pattern.CASE_INSENSITIVE);
+ case WINDOWS:
+ return Pattern.compile("^(netbeans\\.exe|netbeans\\.ini)$", Pattern.CASE_INSENSITIVE);
+ default:
+ case UNIX:
+ return Pattern.compile("^(netbeans|netbeans\\.conf)$", Pattern.CASE_INSENSITIVE);
+ }
+ }
+}
diff --git a/src/installer/lombok/installer/netbeans/netbeans.png b/src/installer/lombok/installer/netbeans/netbeans.png
new file mode 100644
index 00000000..43fe63cc
--- /dev/null
+++ b/src/installer/lombok/installer/netbeans/netbeans.png
Binary files differ