/*******************************************************************************
* Copyright (c) 2012 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package org.grails.ide.eclipse.core.internal.classpath;
import java.util.ArrayList;
import java.util.Collection;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.JavaCore;
import org.grails.ide.eclipse.commands.GrailsCommandFactory;
import org.grails.ide.eclipse.commands.GrailsCommandUtils;
import org.grails.ide.eclipse.core.GrailsCoreActivator;
import org.grails.ide.eclipse.core.workspace.GrailsWorkspace;
import org.springsource.ide.eclipse.commons.frameworks.core.internal.plugins.PluginVersion;
/**
* A helper class, to help installing and uninstalling plugins.
* <p>
* Note: old version of this lives in {@link FastGrailsPluginInstaller} but it isn't used. This version uses
* grails commands only to install and uninstall plugins. (So we are not directly responsible for reverting application.properties
*
* @author Kris De Volder
* @author Martin Lippert
* @author Andrew Eisenberg
*/
public class GrailsPluginInstaller {
private static class Canceled extends Exception {
private static final long serialVersionUID = 1L;
}
private IProject project;
private Collection<PluginVersion> uninstallPlugins;
private Collection<PluginVersion> installPlugins;
private IProgressMonitor monitor;
private IStatus status;
public static IStatus performPluginChanges(
Collection<PluginVersion> selectedUninstallPlugins,
Collection<PluginVersion> selectedInstallPlugins, IProject project,
IProgressMonitor monitor) {
return new GrailsPluginInstaller(selectedUninstallPlugins, selectedInstallPlugins, project, monitor).performChanges();
}
private GrailsPluginInstaller(
Collection<PluginVersion> selectedUninstallPlugins,
Collection<PluginVersion> selectedInstallPlugins,
IProject project,
IProgressMonitor monitor) {
if (selectedInstallPlugins==null) {
selectedInstallPlugins = new ArrayList<PluginVersion>();
}
if (selectedUninstallPlugins==null) {
selectedUninstallPlugins = new ArrayList<PluginVersion>();
}
this.uninstallPlugins = selectedUninstallPlugins;
this.installPlugins = selectedInstallPlugins;
this.project = project;
this.monitor = monitor;
this.status = Status.OK_STATUS;
}
private IStatus performChanges() {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
if (!GrailsClasspathUtils.hasClasspathContainer(JavaCore.create(project))) {
return new Status(IStatus.ERROR, GrailsCoreActivator.PLUGIN_ID, "Plugin Management requires that Grails Dependency Management is enabled for project '"+project.getName()+"'");
}
int totalWork = uninstallPlugins.size() + installPlugins.size() + 1/*refresh deps*/;
monitor.beginTask("Install and uninstall grails plugins", totalWork);
try {
uninstallPlugins();
installPlugins();
} catch (Canceled e) {
return Status.CANCEL_STATUS;
} finally {
try {
refreshDependencies();
} catch (CoreException e) {
addErrorStatus(e.getStatus());
} finally {
monitor.done();
}
}
return status;
}
private void refreshDependencies() throws CoreException {
GrailsCommandUtils.transitiveRefreshDependencies(GrailsWorkspace.get().create(project), false);
}
private void installPlugins() throws Canceled {
for (PluginVersion plugin : installPlugins) {
cancelCheck();
try {
monitor.setTaskName("Installing plugin "+plugin.getName()+" "+plugin.getVersion());
installPlugin(plugin);
}
finally {
monitor.worked(1);
}
}
}
private void installPlugin(PluginVersion plugin) {
if (plugin.getParent().isInPlace()) {
installInPlacePlugin(plugin);
} else {
try {
GrailsCommandFactory.installPlugin(project, plugin).synchExec();
} catch (CoreException e) {
addErrorStatus(e.getStatus());
}
}
}
private void cancelCheck() throws Canceled {
if (monitor.isCanceled()) {
throw new Canceled();
}
}
private void uninstallPlugins() throws Canceled {
for (PluginVersion plugin : uninstallPlugins) {
cancelCheck();
monitor.setTaskName("Uninstalling plugin "+plugin.getName());
try {
uninstallPlugin(plugin);
} finally {
monitor.worked(1);
}
}
}
private void uninstallPlugin(PluginVersion plugin) {
if (plugin.getParent().isInPlace()) {
uninstallInPlacePlugin(plugin);
} else {
try {
GrailsCommandFactory.uninstallPlugin(project, plugin).synchExec();
} catch (CoreException e) {
addErrorStatus(e.getStatus());
}
}
}
/**
* Makes modification to BuildConfig.groovy to uninstall an inplace plugin. Note that this relies
* on the refresh dependencies to run at the end of the install process to pick up on the
* changes in classpath container, project explorer plugin nodes etc.
*
* @param toUninstall
*/
private void uninstallInPlacePlugin(PluginVersion toUninstall) {
// change BuildConfig.groovy script
IProject uninstallProject = ResourcesPlugin.getWorkspace().getRoot().getProject(toUninstall.getName());
if (uninstallProject.isAccessible()) {
IStatus result;
try {
result = GrailsPluginUtil.removePluginDependency(project, uninstallProject);
if (!result.isOK()) {
addErrorStatus(result);
}
} catch (CoreException e) {
addErrorStatus(e.getStatus());
}
} else {
// add warning status
String reason;
if (uninstallProject.exists()) {
reason = " is closed. ";
} else {
reason = " does not exist. ";
}
addErrorStatus(new Status(IStatus.WARNING, GrailsCoreActivator.PLUGIN_ID,
"Project " + uninstallProject.getName() + reason + "Could not uninstall dependency. Try manually editing the BuildConfig.groovy file."));
}
}
private void addErrorStatus(IStatus error) {
if (status.isOK()) {
status = new MultiStatus(GrailsCoreActivator.PLUGIN_ID, IStatus.ERROR, "Problems occurred (un)installing plugins. See details for more information",null);
}
MultiStatus multi = (MultiStatus) status;
multi.merge(error);
}
/**
* Makes modification to BuildConfig.groovy to install an inplace plugin. Note that this relies
* on the refresh dependencies to run at the end of the install process to pick up on the
* changes in classpath container, project explorer plugin nodes etc.
*
* @param toUninstall
*/
private void installInPlacePlugin(PluginVersion toInstall) {
IProject installProject = ResourcesPlugin.getWorkspace().getRoot().getProject(toInstall.getName());
if (installProject.isAccessible()) {
try {
IStatus result = GrailsPluginUtil.addPluginDependency(project, installProject);
if (!result.isOK()) {
addErrorStatus(result);
}
} catch (CoreException e) {
addErrorStatus(e.getStatus());
}
} else {
// add project inaccessible related error message
String reason;
if (installProject.exists()) {
reason = " is closed. ";
} else {
reason = " does not exist. ";
}
addErrorStatus(new Status(IStatus.WARNING, GrailsCoreActivator.PLUGIN_ID,
"Project " + installProject.getName() + reason + "Could not install dependency. Try manually editing the BuildConfig.groovy file."));
}
}
}