Merge branch 'installer'

This commit is contained in:
Reinier Zwitserloot committed 2009-12-02 23:19:18 +01:00
commit 8ec48ec281
18 files changed
+1981 -1082

No files matched your search

Binary file not shown.
@@ -85,7 +85,6 @@ public class CreateLombokRuntimeApp implements LombokApp {
@Requires("create")
String output;
@Shorthand({"h", "?"})
@Description("Shows this help text")
boolean help;
}
@@ -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);
}
}
@@ -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);
}
@@ -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();
}
}
@@ -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);
}
@@ -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);
}
}
+70 -764
View File
@@ -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;
}
private JHyperLink uninstallButton;
private JLabel uninstallPlaceholder;
private JButton installButton;
static IdeLocation tryAllProviders(String location) throws CorruptedIdeLocationException {
for (IdeLocationProvider provider : locationProviders) {
IdeLocation loc = provider.create(location);
if (loc != null) return loc;
}
return null;
}
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>();
for (String rawPath : args.eclipse) {
if (rawPath.equals("auto")) {
EclipseFinder.findEclipses(locations, problems);
} else {
if (args.path.contains("auto")) autoDiscover(locations, problems);
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>";
}
@@ -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));
}
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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");
}
}
@@ -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);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -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);
}
}
}
}
}
}
}
@@ -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");
}
}
@@ -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);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB