/*******************************************************************************
* Copyright (c) 2012 VMWare, 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:
* VMWare, Inc. - initial API and implementation
*******************************************************************************/
package org.grails.ide.eclipse.ui.internal.importfixes;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.codehaus.groovy.eclipse.GroovyPlugin;
import org.codehaus.groovy.eclipse.core.preferences.PreferenceConstants;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.grails.ide.eclipse.commands.GrailsCommandUtils;
import org.grails.ide.eclipse.core.GrailsCoreActivator;
import org.grails.ide.eclipse.core.internal.GrailsNature;
import org.grails.ide.eclipse.core.internal.IgnoredProjectsList;
import org.grails.ide.eclipse.core.internal.classpath.GrailsClasspathContainer;
import org.grails.ide.eclipse.core.internal.classpath.GrailsClasspathContainerUpdateJob;
import org.grails.ide.eclipse.core.internal.model.GrailsInstallWorkspaceConfigurator;
import org.grails.ide.eclipse.core.model.GrailsVersion;
import org.grails.ide.eclipse.core.model.IGrailsInstall;
import org.grails.ide.eclipse.core.model.IGrailsInstallListener;
import org.grails.ide.eclipse.ui.internal.utils.Answer;
import org.springsource.ide.eclipse.commons.frameworks.core.legacyconversion.LegacyProjectConverter;
/**
* This class provides listeners that detect problems in Grails projects because of
* a discrepancy between their application.properties "grails version" and the
* version of the Grails install the project is configured to use in STS.
* <p>
* The most common case it targets is the case where
* a user imported an existing project into Eclipse. The project may have been
* created inside or outside Eclipse with older versions of Grails.
* <p>
* Another case it covers is discrepancies that arise because a user changes the
* default grails install of their workspace. This may cause problems for projects
* that implicitly use the default install.
* <p>
* Another case it covers is a discrepancy arrissing because a user changes the
* project specific settings of a project to use a specific grails install.
* <p>
* Whenever a problem is detected, appropriate action should be taken by the fixer
* based on the project's state and/or grails version, to help the user as much as
* possible to get this project correctly configured in the workspace.
* @author Kris De Volder
* @author Andy Clement
* @since 2.5.2
*/
public class GrailsProjectVersionFixer {
//TODO: The GrailsProjectVersionFixer contains a 'new grails project listener which may be useful as
// a reusable component to which parties interested in the appearance of new grails projects could
// subscribe. It already has two clients (this version fixer and also the output folder fixer).
public static boolean DEBUG = false;
/**
* For testing purposes. If the value is set to a non-null value this value will be
* used to automatically answer questions rather than popup a dialog.
*/
public static Boolean globalAskToConfigureAnswer = null;
public static Boolean globalAskToConvertToGrailsProjectAnswer = null;
/**
* For testing purposes. Some tests may not want the version fixer to interfere with changing
* versions in projects or the workspace at all, this flag is there so those tests can
* temporarily disable the fixer completely.
*/
private static boolean isEnabled = true;
/**
* Listener that detects new projects in the workspace and fixes them.
*/
private IResourceChangeListener newProjectListener = new IResourceChangeListener() {
public void resourceChanged(IResourceChangeEvent event) {
// debug(""+event);
int type = event.getType();
switch (type) {
case IResourceChangeEvent.POST_CHANGE:
IResourceDelta delta = event.getDelta();
//Note: getAffected children cannot be used to get "open" events. Probably need to
// use visitor style if we want to respond to projects being opened in the workspace.
new ProjectChangeHandler().projectsChanged(delta.getAffectedChildren());
break;
default:
// debug("evenType = "+type);
//Not interesting
break;
}
}
};
/**
* Listener that reacts to changes to the default grails install (when this happens will need to check
* projects that may be affected by the change.
*/
private IGrailsInstallListener installListener = new IGrailsInstallListener() {
public void defaultInstallChanged(IGrailsInstall oldDefault, IGrailsInstall newDefault) {
if (installListenerEnabled
&& !GrailsInstallWorkspaceConfigurator.isBusy()) {
// GIWC.isBusy: avoids bug STS-1819: double migration dialog.
// It is 'safe' to ignore chnages to grails installs caused by the workspace configurator because
// it only adds new install but this shouldn't affect existing projects (unless they are already broken).
new ProjectChangeHandler().defaultGrailsVersionChanged();
}
}
public void installsChanged(Set<IGrailsInstall> newInstalls) {
//We only care about the default install. Ignore!
}
};
/**
* To avoid funny interactions between the two listeners, we disable the installListener while processing
* in response to the newProjectListener (reason for the interactions is that newProjectListener may
* ask user to configure a grails install which tends to change the default Grails install).
*/
private boolean installListenerEnabled = true;
private GrailsOutputFolderFixer grailsOutputFolderFixer = null;
public GrailsProjectVersionFixer() {
//Disable Groovy legacy project conversion, we'll take care of it for grails projects and don't want to
//have two convert dialog boxes popup at once.
GroovyPlugin.getDefault().getPreferenceStore().setValue(PreferenceConstants.GROOVY_ASK_TO_CONVERT_LEGACY_PROJECTS, false);
ResourcesPlugin.getWorkspace().addResourceChangeListener(newProjectListener);
GrailsCoreActivator.getDefault().getInstallManager().addGrailsInstallListener(installListener);
debug("Added resource change listener: "+newProjectListener);
}
public void dispose() {
ResourcesPlugin.getWorkspace().removeResourceChangeListener(newProjectListener);
GrailsCoreActivator.getDefault().getInstallManager().removeGrailsInstallListener(installListener);
debug("Removed resource change listener: "+this);
}
/**
* Called after a new installation with the correct version has been provided for a project.
* Ensures eclipse metadatas set up correctly etc.
*/
public static void eclipsify(final IProject project, final IGrailsInstall install) {
WorkspaceJob job = new WorkspaceJob("Configure project '"+project.getName()+"' to use Grails "+install.getVersionString()) {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor)
throws CoreException {
GrailsCommandUtils.eclipsifyProject(install, project);
return Status.OK_STATUS;
}
};
job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
job.setPriority(Job.INTERACTIVE);
job.schedule();
}
private class ProjectChangeHandler {
/**
* To avoid asking the user multiple times to install some version of Grails, remember the answers
* they gave for a particular install and don't ask them again about the same install.
* <p>
* These answers are remembered for the duration of a "batch" of project fixes triggered by a single
* resource change event, since this is mostly to avoid users having do decline to install some
* version of Grails over and over again when importing projects in "bulk" from some old workspace
* or a zip archive.
*/
private Map<GrailsVersion, Answer<Boolean> > askToConfigureAnswers = new HashMap<GrailsVersion, Answer<Boolean>>();
/**
* When set will to non-null value will answer any subsequent "conver to Grails project?" questions automatically without
* popping up a dialog. This variable's 'scope' is the handling of a single resource change event.
* <p>
* Thus it will help when user does a "bulk" import of many projects, but will reset at the end of
* the import.
*/
private Answer<Boolean> askToConvertToGrailsProjectAnswer = new Answer<Boolean>(globalAskToConvertToGrailsProjectAnswer);
public void defaultGrailsVersionChanged() {
//TODO: obsolete? Project now no longer follow the default install (only used on project creation).
// So projects are no longer affected by changes to the default install?
GrailsVersion defaultVersion = GrailsVersion.getDefault();
if (defaultVersion!=null) {
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
for (IProject p : projects) {
if (defaultVersion.equals(GrailsVersion.getEclipseGrailsVersion(p))) {
//Only projects that are configured with the default install in eclipse should be considered for fixing
// (other projects shouldn't be affected by changing the defaul grails version).
fix(p);
}
}
}
}
private void projectsChanged(IResourceDelta[] projectDeltas) {
boolean saveEnabledState = installListenerEnabled;
GrailsVersion orgDefault = GrailsVersion.getDefault();
try {
installListenerEnabled = false;
for (IResourceDelta projectDelta : projectDeltas) {
//debug(""+projectDelta+" kind:"+deltaKindString(projectDelta.getKind()));
int kind = projectDelta.getKind();
if (0 != (kind & (IResourceDelta.ADDED | IResourceDelta.CHANGED))) {
IProject project = (IProject) projectDelta.getResource();
IResourceDelta[] children = projectDelta.getAffectedChildren(IResourceDelta.ADDED);
//Check for added grails-app folder:
for (IResourceDelta child : children) {
if (child.getResource().getName().equals("grails-app")) {
debug("Seeing a new 'grails-app' folder in '"+project+"'");
grailsOutputFolderFixer.fix(project);
fix(project);
}
}
//Check for modified 'application.properties' file:
children = projectDelta.getAffectedChildren(IResourceDelta.CHANGED);
for (IResourceDelta child : children) {
if (child.getResource().getName().equals("application.properties")) {
debug("Seeing a changed 'application.properties' file in '"+project+"'");
fix(project);
}
}
}
}
} finally {
installListenerEnabled = saveEnabledState;
if (installListenerEnabled) {
// if the default install has changed as result of our handling, we still need to consider the
// effects of this on our projects, even though the installListener was temporarily disabled
GrailsVersion currentDefault = GrailsVersion.getDefault();
if (currentDefault!=null && !currentDefault.equals(orgDefault)) {
new ProjectChangeHandler().defaultGrailsVersionChanged();
}
}
}
}
private void fix(IProject project) {
if (!IgnoredProjectsList.isIgnorable(project) && isEnabled && GrailsNature.looksLikeGrailsProject(project)) {
debug("Project to fix? "+project);
GrailsVersion grailsVersion = GrailsVersion.getGrailsVersion(project);
debug("grails version = "+grailsVersion);
GrailsVersion eclipseGrailsVersion = GrailsVersion.getEclipseGrailsVersion(project);
debug("eclipse grails version = "+eclipseGrailsVersion);
if (GrailsVersion.UNKNOWN.equals(eclipseGrailsVersion)) {
//Imported project is configured to use an install not known in this workspace.
handleUnknownEclipseVersion(project, grailsVersion);
} else if (grailsVersion.compareTo(GrailsVersion.SMALLEST_SUPPORTED_VERSION)<0) {
// These grails version aren't supported anymore in STS.
handleUnsuportedVersion(project, grailsVersion);
} else if (!grailsVersion.equals(eclipseGrailsVersion)) {
// The project's grails version is different from the Eclipse STS install associated with the project
handleMismatchingVersions(project, grailsVersion, eclipseGrailsVersion);
} else if (!GrailsNature.isGrailsProject(project)) {
// The project 'looked right' when based on versions, but this is accidental. It doesn't have Grails nature so we
// need to convert it to a Grails project.
handleNoGrailsNature(project, grailsVersion);
} else if (GrailsNature.hasOldGrailsNature(project)) {
// has both the new nature and the old nature
handleHasOldGrailsNature(project, grailsVersion);
} else if (!GrailsClasspathContainer.isVersionSynched(project)){
// classpath currently has libs of a different Grails version... so must refresh
GrailsClasspathContainerUpdateJob.scheduleClasspathContainerUpdateJob(project, true);
}
}
}
/**
* This method handles the case where a project looks like a Grails project but doesn't
* have grails nature.
*/
private void handleNoGrailsNature(final IProject project, GrailsVersion grailsVersion) {
debug("Grails project without grails nature detected: "+project);
final IGrailsInstall install = GrailsCoreActivator.getDefault().getInstallManager().getGrailsInstall(project);
// We are relying on previouse logic to check for matching installs etc. This means we should only be getting
// here if the following assert is true.
Assert.isTrue(install.getVersion().equals(grailsVersion));
boolean convert = askConvertToGrailsProject(project, grailsVersion);
if (convert) {
debug("Converting to Grails project");
WorkspaceJob job = new WorkspaceJob("Convert to Grails project '"+project.getName()+"'") {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
//This case is also where we will end up if we are importing a legacy Grails project
//I.e. the project has a 'old' Grails nature, but not a new one, so looks like a 'no grails nature' project.
monitor.beginTask("Converting to Grails project", 2);
try {
performLegacyConversion(project, new SubProgressMonitor(monitor, 1));
GrailsCommandUtils.eclipsifyProject(install, project);
monitor.worked(1);
return Status.OK_STATUS;
} finally {
monitor.done();
}
}
};
job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
job.setPriority(Job.INTERACTIVE);
job.schedule();
}
}
private void performLegacyConversion(IProject project, IProgressMonitor monitor) {
if (GrailsNature.hasOldGrailsNature(project)) {
LegacyProjectConverter converter = new LegacyProjectConverter(Collections.singletonList(project));
converter.setSelectedLegacyProjects(new IProject[] {project});
converter.convert(monitor);
}
}
/**
* This method handles the case where a project has both the old and the new grails nature
*/
private void handleHasOldGrailsNature(final IProject project, GrailsVersion grailsVersion) {
debug("Grails project with old and new nature detected: "+project);
final IGrailsInstall install = GrailsCoreActivator.getDefault().getInstallManager().getDefaultGrailsInstall();
// We are relying on the normal fixer to run upgrade etc. when the workspace default install doesn't match the declared version.
// This means we should only be getting here if the following assert is true.
Assert.isTrue(install.getVersion().equals(grailsVersion));
boolean convert = askConvertToGrailsProject(project, grailsVersion);
if (convert) {
debug("Removing old grails nature");
WorkspaceJob job = new WorkspaceJob("Removing legacy Grails nature on project '"+project.getName()+"'") {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
GrailsCommandUtils.eclipsifyProject(install, project);
return Status.OK_STATUS;
}
};
job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
job.setPriority(Job.INTERACTIVE);
job.schedule();
}
}
private void handleMismatchingVersions(final IProject project, GrailsVersion grailsVersion, GrailsVersion eclipseGrailsVersion) {
final IGrailsInstall matchingInstall = grailsVersion.getInstall();
if (matchingInstall!=null) {
debug("Matching grails install exists");
boolean upgrade = askToUpgradeFromSupportedInstalled(project, grailsVersion, eclipseGrailsVersion.getInstall());
if (upgrade) {
debug("Upgrading to newer version");
upgradeProject(project, grailsVersion, eclipseGrailsVersion.getInstall());
} else {
debug("Configuring project to use older version");
eclipsify(project, matchingInstall);
}
} else {
// No matching grails install for this project's grails version
debug("Matching grails install DOES NOT exist");
if (grailsVersion.compareTo(eclipseGrailsVersion)<0) {
// a project upgrade could fix it
IGrailsInstall newInstall = eclipseGrailsVersion.getInstall();
boolean upgrade = askToUpgradeFromSupportedNotInstalled(project, grailsVersion, newInstall);
if (upgrade) {
debug("upgrading project to newer version");
upgradeProject(project, grailsVersion, newInstall);
} else {
askAndConfigureGrails(project, grailsVersion);
}
} else {
debug("Either there is no Grails install, or the default install is too old for the project");
askAndConfigureGrails(project, grailsVersion);
}
}
}
public void handleUnknownEclipseVersion(IProject project, GrailsVersion grailsVersion) {
//Gets called if an imported project has eclipse settings pointing to an unknown install.
IGrailsInstall install = grailsVersion.getInstall();
if (install!=null) {
//Silently try to use the install configured in application.properties
eclipsify(project, install);
} else {
GrailsVersion defaultVersion = GrailsVersion.getDefault();
handleMismatchingVersions(project, grailsVersion, defaultVersion);
}
}
/**
* Called when the 'fix' is to configure a given grails version in the workspace and
* make the project use that install.
*/
private void askAndConfigureGrails(final IProject project,
GrailsVersion grailsVersion) {
boolean configureGrails = askToConfigureGrails(project, grailsVersion);
if (configureGrails) {
IGrailsInstall configured = configureGrails(grailsVersion);
while (configured == null && askRetryConfigure(grailsVersion)) {
configured = configureGrails(grailsVersion);
}
if (configured!=null) {
eclipsify(project, grailsVersion.getInstall());
}
}
}
private boolean askRetryConfigure(GrailsVersion grailsVersion) {
return yesNoQuestion("Configure Grails "+grailsVersion,
"You did not configure a version "+grailsVersion+" install.\n\n"+
"Do you want to try again?");
}
/**
* Gets active Shell. Warning this method should only be called from the UI thread.
*/
private Shell getShell() {
return PlatformUI.getWorkbench().getDisplay().getActiveShell();
}
/**
* Opens the dialog box that lets a user define a grails install. Hoping that the user will
* select the right version of Grails.
*
* @return a Grails install of the correct version if the user has configured one, null otherwise.
*/
private IGrailsInstall configureGrails(GrailsVersion grailsVersion) {
Display.getDefault().syncExec(new Runnable() {
public void run() {
String id = "org.grails.ide.eclipse.ui.preferencePage";
PreferencesUtil.createPreferenceDialogOn(getShell(), id, new String[] { id }, Collections.EMPTY_MAP).open();
}
});
return grailsVersion.getInstall();
}
/**
* Called when we find a Grails project that as a very old version number.
*/
private void handleUnsuportedVersion(IProject project, GrailsVersion oldVersion) {
debug("Unsupported version detected");
//Two cases: depending on default grails install
IGrailsInstall defaultInstall = getDefaultInstall();
if (defaultInstall!=null && GrailsVersion.SMALLEST_SUPPORTED_VERSION.isSatisfiedBy(defaultInstall.getVersionString())) {
// Case 1: we have an acceptable default grails install...
boolean upgrade = askToUpgradeFromUnsupported(project, oldVersion, defaultInstall);
if (upgrade) {
debug("Scheduling upgrade job...");
upgradeProject(project, oldVersion, defaultInstall);
debug("Scheduling upgrade job DONE");
}
} else {
// Case 2: we don't have an acceptable default grails install...
//TODO: implement something to handle this case?
}
}
private boolean askToUpgradeFromUnsupported(IProject project, GrailsVersion oldVersion, IGrailsInstall newInstall) {
//TODO: remove this method and any code that is invoked when it returns true.
return false;
}
private boolean askToUpgradeFromSupportedNotInstalled(IProject project,
GrailsVersion oldVersion, IGrailsInstall newInstall) {
//TODO: remove this method and any code that is invoked when it returns true.
return false;
}
private boolean askToUpgradeFromSupportedInstalled(IProject project,
GrailsVersion oldVersion, IGrailsInstall newInstall) {
//TODO: remove this method and any code that is invoked when it returns true.
return false;
}
private boolean askConvertToGrailsProject(IProject project, GrailsVersion grailsVersion) {
if (GrailsNature.hasOldGrailsNature(project)) {
//Make the message more appropriate for the migration of Legacy (pre STS 3.0.0) project
return yesNoAllQuestion("Migrate Legacy STS Grails Project?",
"The project "+project.getName()+" looks like a Grails project but...\n"+
"It is configured for use in an older version of STS.\n"+
"The project won't compile unless the project is migrated.\n" +
"\n"+
"Do you want to migrate the project now?",
askToConvertToGrailsProjectAnswer);
} else {
return yesNoAllQuestion("Convert to Grails Project?",
"The project "+project.getName()+" looks like a Grails project but...\n"+
"is not configured for use with the STS Grails tools.\n"+
"To fix this problem, the project needs to be converted to an STS Grails Project.\n" +
"\n"+
"Do you want to convert the project now?",
askToConvertToGrailsProjectAnswer);
}
}
/**
* Called when user elects to keep using an older grails version for their project,
* and this older version isn't currently configured in the workspace.
*/
private boolean askToConfigureGrails(IProject project, GrailsVersion oldVersion) {
Assert.isLegal(oldVersion.compareTo(GrailsVersion.SMALLEST_SUPPORTED_VERSION)>=0, "GrailsVersion: "+oldVersion);
Answer<Boolean> answer = askToConfigureAnswers.get(oldVersion);
if (answer==null) {
answer = new Answer<Boolean>(globalAskToConfigureAnswer);
askToConfigureAnswers.put(oldVersion, answer);
}
if (answer.value!=null) {
return answer.value;
}
answer.value = yesNoQuestion("Configure Grails "+oldVersion+"?",
"The project '"+project.getName()+"' requires Grails " + oldVersion +" " +
"but a corresponding install is not configured in your workspace.\n" +
"\n" +
"If you configure the install now, I will also configure your project \n" +
"'"+project.getName()+"' to use that install.\n" +
"\n"+
"Do you want to configure a Grails "+oldVersion+" install now?");
return answer.value;
}
private void upgradeProject(final IProject project, GrailsVersion oldVersion, final IGrailsInstall newInstall) {
WorkspaceJob job = new WorkspaceJob("Upgrade project '"+project.getName()+"'") {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
monitor.beginTask("Upgrade project", 10);
try {
performLegacyConversion(project, new SubProgressMonitor(monitor, 1));
debug("upgrade job starting...");
GrailsCommandUtils.upgradeProject(project, newInstall);
debug("upgrade job finished");
} finally {
monitor.done();
}
return Status.OK_STATUS;
}
};
job.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule());
job.setPriority(Job.INTERACTIVE);
job.schedule();
}
private boolean yesNoAllQuestion(final String title, final String message, final Answer<Boolean> autoAnswer) {
if (autoAnswer.value!=null) {
return autoAnswer.value;
}
final boolean[] result = new boolean[1];
Display.getDefault().syncExec(new Runnable() {
public void run() {
result[0] = openUpgradeQuestion(title, message, autoAnswer);
}
});
return result[0];
}
private boolean yesNoQuestion(final String title, final String message) {
final Answer<Boolean> result = new Answer<Boolean>();
Display.getDefault().syncExec(new Runnable() {
public void run() {
result.value = MessageDialog.openQuestion(null, title, message);
}
});
return result.value;
}
protected boolean openUpgradeQuestion(String title, String message, Answer<Boolean> autoAnswer) {
MessageDialog dialog = new MessageDialog(null, title, null, message,
MessageDialog.QUESTION, new String[] { "No to All" , "Yes to All", "No", "Yes" }, 3);
int button = dialog.open();
switch (button) {
case 3: /* yes */
return true;
case 2: /* no */
return false;
case 1: /* yes to all */
autoAnswer.value = true;
return true;
case 0: /* no to all */
autoAnswer.value = false;
return false;
}
//Shouldn't reach here ever
return false;
}
private IGrailsInstall getDefaultInstall() {
return GrailsCoreActivator.getDefault().getInstallManager().getDefaultGrailsInstall();
}
}
////////////////////////////////////////////////////
// Debugging code
private void debug(String string) {
if (DEBUG) {
System.out.println("GrailsImportedProjectFixer: "+string);
}
}
private String deltaKindString(int kind) {
switch (kind) {
case IResourceDelta.ADDED:
return "added";
case IResourceDelta.OPEN:
return "open";
default:
return ""+kind;
}
}
/**
* Prevents popup dialogs from the fixer, automatically answering 'no' to all questions.
* The fixer is however still active! To completely disable the fixer, use the setEnabled()
* method instead.
*/
public static void testMode() {
GrailsProjectVersionFixer.globalAskToConvertToGrailsProjectAnswer = false;
GrailsProjectVersionFixer.globalAskToConfigureAnswer = false;
}
/**
* For testing purposes only. Allows tests to disable the fixer to avoid the tests from
* being affected by popping up dialogs or making changes to projects in background at
* unpredictabled times, making the tests behave eratic.
*/
public static void setEnabled(boolean enabled) {
isEnabled = enabled;
}
/**
* For testing purposes only. In production, this should always be true.
*/
public static boolean isEnabled() {
return isEnabled;
}
public void setGrailsOutputFolderFixer(GrailsOutputFolderFixer grailsOutputFolderFixer) {
this.grailsOutputFolderFixer = grailsOutputFolderFixer;
}
}