ant run configuration: ability to define values for ant properties (IDEA-155270)

This commit is contained in:
Eugene Zhuravlev
2016-04-29 21:25:13 +02:00
parent afb9d3e446
commit b57a3485a8
6 changed files with 236 additions and 98 deletions
@@ -23,7 +23,7 @@ import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@Tag("build-property")
public final class BuildFileProperty implements JDOMExternalizable {
public final class BuildFileProperty implements JDOMExternalizable, Cloneable {
@NonNls private static final String NAME = "name";
@NonNls private static final String VALUE = "value";
private String myPropertyName;
@@ -80,4 +80,14 @@ public final class BuildFileProperty implements JDOMExternalizable {
return 31 * (myPropertyName != null ? myPropertyName.hashCode() : 0)
+ (myPropertyValue != null ? myPropertyValue.hashCode() : 0);
}
@Override
public BuildFileProperty clone() {
try {
return (BuildFileProperty)super.clone();
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
@@ -20,13 +20,10 @@ import com.intellij.lang.ant.AntBundle;
import com.intellij.lang.ant.config.AntBuildListener;
import com.intellij.lang.ant.config.execution.AntBuildMessageView;
import com.intellij.lang.ant.config.execution.ExecutionHandler;
import com.intellij.lang.ant.config.impl.BuildFileProperty;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.Presentation;
import java.util.Collections;
public final class RunAction extends AnAction {
private final AntBuildMessageView myAntBuildMessageView;
@@ -40,7 +37,7 @@ public final class RunAction extends AnAction {
myAntBuildMessageView.getBuildFile(),
myAntBuildMessageView.getTargets(),
myAntBuildMessageView,
e.getDataContext(), Collections.<BuildFileProperty>emptyList(), AntBuildListener.NULL);
e.getDataContext(), myAntBuildMessageView.getAdditionalProperties(), AntBuildListener.NULL);
}
public void update(AnActionEvent event){
@@ -30,6 +30,7 @@ import com.intellij.lang.ant.config.AntBuildFileBase;
import com.intellij.lang.ant.config.AntBuildListener;
import com.intellij.lang.ant.config.actions.*;
import com.intellij.lang.ant.config.impl.AntBuildFileImpl;
import com.intellij.lang.ant.config.impl.BuildFileProperty;
import com.intellij.lang.ant.config.impl.HelpID;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.*;
@@ -65,6 +66,7 @@ import java.awt.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class AntBuildMessageView extends JPanel implements DataProvider, OccurenceNavigator {
private static final Logger LOG = Logger.getInstance("#com.intellij.ant.execution.AntBuildMessageView");
@@ -92,6 +94,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
private final CardLayout myCardLayout;
private AntBuildFileBase myBuildFile;
private final String[] myTargets;
private final List<BuildFileProperty> myAdditionalProperties;
private int myPriorityThreshold = PRIORITY_BRIEF;
private volatile int myErrorCount;
private volatile int myWarningCount;
@@ -143,11 +146,12 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
};
@NonNls public static final String FILE_PREFIX = "file:";
private AntBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets) {
private AntBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets, List<BuildFileProperty> additionalProperties) {
super(new BorderLayout(2, 0));
myProject = project;
myBuildFile = buildFile;
myTargets = targets;
myAdditionalProperties = additionalProperties;
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
myPlainTextView = new PlainTextView(project);
@@ -235,7 +239,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
* @return can be null if user cancelled operation
*/
@Nullable
public static AntBuildMessageView openBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets) {
public static AntBuildMessageView openBuildMessageView(Project project, AntBuildFileBase buildFile, String[] targets, List<BuildFileProperty> additionalProperties) {
final VirtualFile antFile = buildFile.getVirtualFile();
if (!LOG.assertTrue(antFile != null)) {
return null;
@@ -278,7 +282,7 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
}
}
final AntBuildMessageView messageView = new AntBuildMessageView(project, buildFile, targets);
final AntBuildMessageView messageView = new AntBuildMessageView(project, buildFile, targets, additionalProperties);
String contentName = buildFile.getPresentableName();
contentName = BUILD_CONTENT_NAME + " (" + contentName + ")";
@@ -767,6 +771,10 @@ public final class AntBuildMessageView extends JPanel implements DataProvider, O
return myTargets;
}
public List<BuildFileProperty> getAdditionalProperties() {
return myAdditionalProperties;
}
private int getErrorCount() {
return myErrorCount;
}
@@ -19,107 +19,63 @@ import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.util.ListTableWithButtons;
import com.intellij.lang.ant.config.AntBuildTarget;
import com.intellij.lang.ant.config.AntConfiguration;
import com.intellij.lang.ant.config.impl.BuildFileProperty;
import com.intellij.lang.ant.config.impl.GlobalAntConfiguration;
import com.intellij.lang.ant.config.impl.TargetChooserDialog;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.LabeledComponent;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizable;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AntRunConfiguration extends LocatableConfigurationBase implements RunProfileWithCompileBeforeLaunchOption{
private AntSettings mySettings = new AntSettings();
public AntRunConfiguration(Project project,
ConfigurationFactory factory,
String name) {
public AntRunConfiguration(Project project, ConfigurationFactory factory, String name) {
super(project, factory, name);
}
@Override
public RunConfiguration clone() {
AntRunConfiguration configuration = (AntRunConfiguration)super.clone();
configuration.mySettings = mySettings.clone();
final AntRunConfiguration configuration = (AntRunConfiguration)super.clone();
configuration.mySettings = mySettings.copy();
return configuration;
}
@NotNull
@Override
public Module[] getModules() {
return new Module[0];
return Module.EMPTY_ARRAY;
}
@NotNull
@Override
public SettingsEditor<? extends RunConfiguration> getConfigurationEditor() {
return new SettingsEditor<RunConfiguration>() {
private String myFileUrl = null;
private String myTargetName = null;
private final JTextField myTextField = new JTextField();
private ActionListener myActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
AntBuildTarget buildTarget = getTarget();
final TargetChooserDialog dlg = new TargetChooserDialog(getProject(), buildTarget);
if (dlg.showAndGet()) {
myFileUrl = null;
myTargetName = null;
buildTarget = dlg.getSelectedTarget();
if (buildTarget != null) {
final VirtualFile vFile = buildTarget.getModel().getBuildFile().getVirtualFile();
if (vFile != null) {
myFileUrl = vFile.getUrl();
myTargetName = buildTarget.getName();
}
}
updateTextField();
}
}
};
private void updateTextField() {
myTextField.setText("");
if (myFileUrl != null && myTargetName != null) {
myTextField.setText(myTargetName);
}
fireEditorStateChanged();
}
@Override
protected void resetEditorFrom(RunConfiguration s) {
AntRunConfiguration configuration = (AntRunConfiguration)s;
myFileUrl = configuration.mySettings.myFileUrl;
myTargetName = configuration.mySettings.myTargetName;
updateTextField();
}
@Override
protected void applyEditorTo(RunConfiguration s) throws ConfigurationException {
AntRunConfiguration configuration = (AntRunConfiguration)s;
configuration.mySettings.myFileUrl = myFileUrl;
configuration.mySettings.myTargetName = myTargetName;
}
@NotNull
@Override
protected JComponent createEditor() {
myTextField.setEditable(false);
return new TextFieldWithBrowseButton(myTextField, myActionListener);
}
};
return new AntConfigurationSettingsEditor();
}
@Override
@@ -156,24 +112,34 @@ public class AntRunConfiguration extends LocatableConfigurationBase implements R
mySettings.writeExternal(element);
}
@Nullable
public AntBuildTarget getTarget() {
return GlobalAntConfiguration.getInstance().findTarget(getProject(), mySettings.myFileUrl, mySettings.myTargetName);
}
@NotNull
public List<BuildFileProperty> getProperties() {
return Collections.unmodifiableList(mySettings.myProperties);
}
public boolean acceptSettings(AntBuildTarget target) {
VirtualFile virtualFile = target.getModel().getBuildFile().getVirtualFile();
if (virtualFile == null) return false;
if (virtualFile == null) {
return false;
}
mySettings.myFileUrl = virtualFile.getUrl();
mySettings.myTargetName = target.getName();
return true;
}
public static class AntSettings implements Cloneable, JDOMExternalizable {
public static class AntSettings implements JDOMExternalizable {
private static final String SETTINGS = "antsettings";
private static final String PROPERTY = "property";
private static final String FILE = "antfile";
private static final String TARGET = "target";
private String myFileUrl = null;
private String myTargetName = null;
private final List<BuildFileProperty> myProperties = new ArrayList<>();
public AntSettings() {
}
@@ -188,9 +154,10 @@ public class AntRunConfiguration extends LocatableConfigurationBase implements R
return myTargetName + "@" + myFileUrl;
}
@Override
protected AntSettings clone() {
return new AntSettings(myFileUrl, myTargetName);
public AntSettings copy() {
final AntSettings copy = new AntSettings(myFileUrl, myTargetName);
copyProperties(myProperties, copy.myProperties);
return copy;
}
@Override
@@ -199,17 +166,181 @@ public class AntRunConfiguration extends LocatableConfigurationBase implements R
if (element != null) {
myFileUrl = element.getAttributeValue(FILE);
myTargetName = element.getAttributeValue(TARGET);
myProperties.clear();
for (Element pe : element.getChildren(PROPERTY)) {
BuildFileProperty prop = new BuildFileProperty();
prop.readExternal(pe);
myProperties.add(prop);
}
}
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
if (myFileUrl != null && myTargetName != null) {
Element child = new Element(SETTINGS);
child.setAttribute(FILE, myFileUrl);
child.setAttribute(TARGET, myTargetName);
element.addContent(child);
final Element settingsElem = new Element(SETTINGS);
settingsElem.setAttribute(FILE, myFileUrl);
settingsElem.setAttribute(TARGET, myTargetName);
for (BuildFileProperty property : myProperties) {
final Element pe = new Element(PROPERTY);
property.writeExternal(pe);
settingsElem.addContent(pe);
}
element.addContent(settingsElem);
}
}
}
private class AntConfigurationSettingsEditor extends SettingsEditor<RunConfiguration> {
private String myFileUrl = null;
private String myTargetName = null;
private final JTextField myTextField = new JTextField();
private final PropertiesTable myPropTable = new PropertiesTable();
private ActionListener myActionListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
AntBuildTarget buildTarget = getTarget();
final TargetChooserDialog dlg = new TargetChooserDialog(getProject(), buildTarget);
if (dlg.showAndGet()) {
myFileUrl = null;
myTargetName = null;
buildTarget = dlg.getSelectedTarget();
if (buildTarget != null) {
final VirtualFile vFile = buildTarget.getModel().getBuildFile().getVirtualFile();
if (vFile != null) {
myFileUrl = vFile.getUrl();
myTargetName = buildTarget.getName();
}
}
updateUI();
}
}
};
private void updateUI() {
myTextField.setText("");
if (myFileUrl != null && myTargetName != null) {
myTextField.setText(myTargetName);
}
myPropTable.refreshValues();
fireEditorStateChanged();
}
@Override
protected void resetEditorFrom(RunConfiguration s) {
final AntRunConfiguration config = (AntRunConfiguration)s;
myFileUrl = config.mySettings.myFileUrl;
myTargetName = config.mySettings.myTargetName;
myPropTable.setValues(config.mySettings.myProperties);
updateUI();
}
@Override
protected void applyEditorTo(RunConfiguration s) throws ConfigurationException {
final AntRunConfiguration config = (AntRunConfiguration)s;
config.mySettings.myFileUrl = myFileUrl;
config.mySettings.myTargetName = myTargetName;
copyProperties(ContainerUtil.filter(myPropTable.getElements(), new Condition<BuildFileProperty>() {
@Override
public boolean value(BuildFileProperty property) {
return !myPropTable.isEmpty(property);
}
}), config.mySettings.myProperties);
}
@NotNull
@Override
protected JComponent createEditor() {
myTextField.setEditable(false);
final JPanel panel = new JPanel(new BorderLayout());
panel.add(LabeledComponent.create(new TextFieldWithBrowseButton(myTextField, myActionListener), "Target name", BorderLayout.WEST), BorderLayout.NORTH);
final LabeledComponent<JComponent> tableComponent = LabeledComponent.create(myPropTable.getComponent(), "Ant Properties");
tableComponent.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));
panel.add(tableComponent, BorderLayout.CENTER);
return panel;
}
}
private static class PropertiesTable extends ListTableWithButtons<BuildFileProperty> {
@Override
protected ListTableModel createListModel() {
final ColumnInfo nameColumn = new TableColumn("Name") {
@Nullable
@Override
public String valueOf(BuildFileProperty property) {
return property.getPropertyName();
}
@Override
public void setValue(BuildFileProperty property, String value) {
property.setPropertyName(value);
}
};
final ColumnInfo valueColumn = new TableColumn("Value") {
@Nullable
@Override
public String valueOf(BuildFileProperty property) {
return property.getPropertyValue();
}
@Override
public void setValue(BuildFileProperty property, String value) {
property.setPropertyValue(value);
}
};
return new ListTableModel(nameColumn, valueColumn);
}
@Override
protected BuildFileProperty createElement() {
return new BuildFileProperty();
}
@Override
protected boolean isEmpty(BuildFileProperty element) {
return StringUtil.isEmpty(element.getPropertyName()) && StringUtil.isEmpty(element.getPropertyValue());
}
@Override
protected BuildFileProperty cloneElement(BuildFileProperty p) {
return p.clone();
}
@Override
protected boolean canDeleteElement(BuildFileProperty selection) {
return true;
}
@Override
public List<BuildFileProperty> getElements() {
return super.getElements();
}
private abstract static class TableColumn extends ElementsColumnInfoBase<BuildFileProperty> {
public TableColumn(final String name) {
super(name);
}
@Override
public boolean isCellEditable(BuildFileProperty property) {
return true;
}
@Nullable
@Override
protected String getDescription(BuildFileProperty element) {
return null;
}
}
}
private static void copyProperties(final Iterable<BuildFileProperty> from, final List<BuildFileProperty> to) {
to.clear();
for (BuildFileProperty p : from) {
to.add(p.clone());
}
}
}
@@ -25,13 +25,9 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.lang.ant.config.AntBuildListener;
import com.intellij.lang.ant.config.AntBuildTarget;
import com.intellij.lang.ant.config.impl.BuildFileProperty;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
public class AntRunProfileState implements RunProfileState {
private final ExecutionEnvironment myEnvironment;
@@ -42,20 +38,16 @@ public class AntRunProfileState implements RunProfileState {
@Nullable
@Override
public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
RunProfile profile = myEnvironment.getRunProfile();
final RunProfile profile = myEnvironment.getRunProfile();
if (profile instanceof AntRunConfiguration) {
AntRunConfiguration antRunConfiguration = (AntRunConfiguration)profile;
AntBuildTarget target = antRunConfiguration.getTarget();
if (target == null) return null;
ProcessHandler processHandler = ExecutionHandler
.executeRunConfiguration(antRunConfiguration, myEnvironment.getDataContext(), new ArrayList<BuildFileProperty>(),
new AntBuildListener() {
@Override
public void buildFinished(int state, int errorCount) {
}
});
if (processHandler == null) return null;
final AntRunConfiguration runConfig = (AntRunConfiguration)profile;
if (runConfig.getTarget() == null) {
return null;
}
final ProcessHandler processHandler = ExecutionHandler.executeRunConfiguration(runConfig, myEnvironment.getDataContext(), runConfig.getProperties(), AntBuildListener.NULL);
if (processHandler == null) {
return null;
}
return new DefaultExecutionResult(null, processHandler);
}
return null;
@@ -122,7 +122,7 @@ public final class ExecutionHandler {
builder.getCommandLine().setCharset(EncodingProjectManager.getInstance(buildFile.getProject()).getDefaultCharset());
messageView = prepareMessageView(buildMessageViewToReuse, buildFile, targets);
messageView = prepareMessageView(buildMessageViewToReuse, buildFile, targets, additionalProperties);
commandLine = CommandLineBuilder.createFromJavaParameters(builder.getCommandLine());
messageView.setBuildCommandLine(commandLine.getCommandLineString());
}
@@ -300,14 +300,14 @@ public final class ExecutionHandler {
private static AntBuildMessageView prepareMessageView(@Nullable AntBuildMessageView buildMessageViewToReuse,
AntBuildFileBase buildFile,
String[] targets) throws RunCanceledException {
String[] targets, List<BuildFileProperty> additionalProperties) throws RunCanceledException {
AntBuildMessageView messageView;
if (buildMessageViewToReuse != null) {
messageView = buildMessageViewToReuse;
messageView.emptyAll();
}
else {
messageView = AntBuildMessageView.openBuildMessageView(buildFile.getProject(), buildFile, targets);
messageView = AntBuildMessageView.openBuildMessageView(buildFile.getProject(), buildFile, targets, additionalProperties);
if (messageView == null) {
throw new RunCanceledException(AntBundle.message("canceled.by.user.error.message"));
}