blob: 8cf2c67d4bc9990b2717a34f10963c4b07bcaaca [file] [log] [blame]
/*
* Copyright 2005 Sascha Weinreuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.intellij.lang.xpath.xslt.run;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.filters.RegexpFilter;
import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.process.ProcessEvent;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.SettingsEditor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectBundle;
import com.intellij.openapi.projectRoots.*;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ProjectFileIndex;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.openapi.vfs.pointers.VirtualFilePointerManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlDocument;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.SystemProperties;
import org.intellij.lang.xpath.xslt.XsltSupport;
import org.intellij.lang.xpath.xslt.associations.FileAssociationsManager;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public final class XsltRunConfiguration extends LocatableConfigurationBase implements ModuleRunConfiguration, RunConfigurationWithSuppressedDefaultDebugAction {
private static final String NAME = "XSLT Configuration";
private static final String STRICT_FILE_PATH_EXPR = "(file\\://?(?:/?\\p{Alpha}\\:)?(?:/\\p{Alpha}\\:)?[^:]+)";
private static final String RELAXED_FILE_PATH_EXPR = "((?:file\\://?)?(?:/?\\p{Alpha}\\:)?(?:/\\p{Alpha}\\:)?[^:]+)";
private static final String LOG_TAG = "(?:\\[[\\w ]+\\]\\:? +)?";
public enum OutputType {
CONSOLE, STDOUT, @Deprecated FILE
}
public enum JdkChoice {
FROM_MODULE, JDK
}
private List<Pair<String, String>> myParameters = new ArrayList<Pair<String, String>>();
@Nullable private VirtualFilePointer myXsltFile = null;
@Nullable private VirtualFilePointer myXmlInputFile = null;
@NotNull private OutputType myOutputType = OutputType.CONSOLE;
private boolean mySaveToFile = false;
@NotNull private JdkChoice myJdkChoice = JdkChoice.FROM_MODULE;
@Nullable private FileType myFileType = StdFileTypes.XML;
public String myOutputFile; // intentionally untracked. should it be?
public boolean myOpenOutputFile;
public boolean myOpenInBrowser;
public boolean mySmartErrorHandling = true;
@Deprecated // this is only used if the dynamic selection of a port fails
public int myRunnerPort = 34873;
public String myVmArguments;
public String myWorkingDirectory;
public String myModule;
public String myJdk;
private String mySuggestedName;
public XsltRunConfiguration(Project project, ConfigurationFactory factory) {
super(project, factory, NAME);
mySuggestedName = null;
}
@NotNull
@Override
public SettingsEditor<XsltRunConfiguration> getConfigurationEditor() {
return new XsltRunSettingsEditor(getProject());
}
@Override
public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEnvironment executionEnvironment) throws ExecutionException {
if (myXsltFile == null) throw new ExecutionException("No XSLT file selected");
final VirtualFile baseFile = myXsltFile.getFile();
final XsltCommandLineState state = new XsltCommandLineState(this, executionEnvironment);
final TextConsoleBuilder builder = TextConsoleBuilderFactory.getInstance().createBuilder(getProject());
builder.addFilter(new CustomRegexpFilter(getProject(), RegexpFilter.FILE_PATH_MACROS + "\\:" +
"(?:(?: line )?" + RegexpFilter.LINE_MACROS + ")?" +
"(?:\\:(?: column )?" + RegexpFilter.COLUMN_MACROS + ")?", baseFile, STRICT_FILE_PATH_EXPR));
builder.addFilter(new CustomRegexpFilter(getProject(), LOG_TAG +
RegexpFilter.FILE_PATH_MACROS + "\\:" +
"(?:(?: line )?" + RegexpFilter.LINE_MACROS + ")?" +
"(?:\\:(?: column )?" + RegexpFilter.COLUMN_MACROS + ")?", baseFile, RELAXED_FILE_PATH_EXPR));
builder.addFilter(new CustomRegexpFilter(getProject(), RegexpFilter.FILE_PATH_MACROS + ";" +
" \\w+ #" + RegexpFilter.LINE_MACROS +
"(?:; \\w+ #" + RegexpFilter.COLUMN_MACROS + ")?", baseFile, STRICT_FILE_PATH_EXPR));
builder.addFilter(new CustomRegexpFilter(getProject(), LOG_TAG +
RegexpFilter.FILE_PATH_MACROS + ";" +
" \\w+ #" + RegexpFilter.LINE_MACROS +
"(?:; \\w+ #" + RegexpFilter.COLUMN_MACROS + ")?", baseFile, RELAXED_FILE_PATH_EXPR));
builder.addFilter(new CustomRegexpFilter(getProject(), "(?:" + RegexpFilter.FILE_PATH_MACROS + ")?" +
" line " + RegexpFilter.LINE_MACROS +
"(?:\\:(?: column )?" + RegexpFilter.COLUMN_MACROS + ")?", baseFile, STRICT_FILE_PATH_EXPR));
state.setConsoleBuilder(builder);
return state;
}
@Override
public void createAdditionalTabComponents(final AdditionalTabComponentManager manager, ProcessHandler startedProcess) {
if (myOutputType == OutputType.CONSOLE) {
final HighlightingOutputConsole console = new HighlightingOutputConsole(getProject(), myFileType);
boolean consoleTabAdded = false;
for (XsltRunnerExtension extension : XsltRunnerExtension.getExtensions(this, false /* doesn't matter, xslt debugger uses own flag */)) {
if (extension.createTabs(getProject(), manager, console, startedProcess)) {
consoleTabAdded = true;
}
}
if (!consoleTabAdded) {
manager.addAdditionalTabComponent(console, console.getTabTitle()); // TODO: verify parameter
}
final OutputTabAdapter listener = new OutputTabAdapter(startedProcess, console);
if (startedProcess.isStartNotified()) {
listener.startNotified(new ProcessEvent(startedProcess));
}
else {
startedProcess.addProcessListener(listener);
}
}
}
@Override
public final RunConfiguration clone() {
final XsltRunConfiguration configuration = (XsltRunConfiguration)super.clone();
configuration.myParameters = new ArrayList<Pair<String, String>>(myParameters);
if (myXsltFile != null) configuration.myXsltFile = VirtualFilePointerManager.getInstance().duplicate(myXsltFile, getProject(), null);
if (myXmlInputFile != null) configuration.myXmlInputFile = VirtualFilePointerManager.getInstance().duplicate(myXmlInputFile, getProject(), null);
return configuration;
}
@Override
public void checkConfiguration() throws RuntimeConfigurationException {
if (myXsltFile == null) {
throw new RuntimeConfigurationError("No XSLT File selected");
}
if (myXsltFile.getFile() == null) {
throw new RuntimeConfigurationError("Selected XSLT File not found");
}
if (myXmlInputFile == null) {
throw new RuntimeConfigurationError("No XML Input File selected");
}
if (myXmlInputFile.getFile() == null) {
throw new RuntimeConfigurationError("Selected XML Input File not found");
}
if (mySaveToFile) {
if (isEmpty(myOutputFile)) {
throw new RuntimeConfigurationError("No output file selected");
}
final File f = new File(myOutputFile);
if (f.isDirectory()) {
throw new RuntimeConfigurationError("Selected output file points to a directory");
} else if (f.exists() && !f.canWrite()) {
throw new RuntimeConfigurationError("Selected output file is not writable");
}
}
if (getEffectiveJDK() == null) {
throw new RuntimeConfigurationError("No JDK available");
}
}
static boolean isEmpty(String file) {
return file == null || file.length() == 0;
}
// return modules to compile before run. Null or empty list to make project
@Override
@NotNull
public Module[] getModules() {
return getModule() != null ? new Module[]{ getModule() } : Module.EMPTY_ARRAY;
}
@Override
@SuppressWarnings({ "unchecked" })
public void readExternal(Element element) throws InvalidDataException {
super.readExternal(element);
DefaultJDOMExternalizer.readExternal(this, element);
Element e = element.getChild("XsltFile");
if (e != null) {
final String url = e.getAttributeValue("url");
if (url != null) {
myXsltFile = VirtualFilePointerManager.getInstance().create(url, getProject(), null);
}
}
e = element.getChild("XmlFile");
if (e != null) {
final String url = e.getAttributeValue("url");
if (url != null) {
myXmlInputFile = VirtualFilePointerManager.getInstance().create(url, getProject(), null);
}
}
final Element parameters = element.getChild("parameters");
if (parameters != null) {
myParameters.clear();
final List<Element> params = parameters.getChildren("param");
for (Element p : params) {
myParameters.add(Pair.create(p.getAttributeValue("name"), p.getAttributeValue("value")));
}
}
final Element outputType = element.getChild("OutputType");
if (outputType != null) {
final String value = outputType.getAttributeValue("value");
if (OutputType.FILE.name().equals(value)) {
myOutputType = OutputType.STDOUT;
mySaveToFile = true;
} else {
myOutputType = OutputType.valueOf(value);
mySaveToFile = Boolean.valueOf(outputType.getAttributeValue("save-to-file"));
}
}
final Element fileType = element.getChild("FileType");
if (fileType != null) {
myFileType = getFileType(fileType.getAttributeValue("name"));
}
final Element jdkChoice = element.getChild("JdkChoice");
if (jdkChoice != null) {
myJdkChoice = JdkChoice.valueOf(jdkChoice.getAttributeValue("value"));
}
}
@Nullable
private static FileType getFileType(String value) {
if (value == null) return null;
final FileType[] fileTypes = FileTypeManager.getInstance().getRegisteredFileTypes();
for (FileType fileType : fileTypes) {
if (fileType.getName().equals(value)) {
return fileType;
}
}
return null;
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
super.writeExternal(element);
DefaultJDOMExternalizer.writeExternal(this, element);
Element e = new Element("XsltFile");
if (myXsltFile != null) {
e.setAttribute("url", myXsltFile.getUrl());
element.addContent(e);
}
e = new Element("XmlFile");
if (myXmlInputFile != null) {
e.setAttribute("url", myXmlInputFile.getUrl());
element.addContent(e);
}
final Element params = new Element("parameters");
element.addContent(params);
for (Pair<String, String> pair : myParameters) {
final Element p = new Element("param");
params.addContent(p);
p.setAttribute("name", pair.getFirst());
final String value = pair.getSecond();
if (value != null) {
p.setAttribute("value", value);
}
}
final Element type = new Element("OutputType");
type.setAttribute("value", myOutputType.name());
type.setAttribute("save-to-file", String.valueOf(mySaveToFile));
element.addContent(type);
final Element fileType = new Element("FileType");
if (myFileType != null) {
fileType.setAttribute("name", myFileType.getName());
}
element.addContent(fileType);
final Element choice = new Element("JdkChoice");
choice.setAttribute("value", myJdkChoice.name());
element.addContent(choice);
}
public List<Pair<String, String>> getParameters() {
return myParameters;
}
public void setParameters(List<Pair<String, String>> params) {
myParameters.clear();
myParameters.addAll(params);
}
public String getVmArguments() {
return myVmArguments;
}
public void setVmArguments(String vmArguments) {
myVmArguments = vmArguments;
}
public void setXsltFile(@NotNull String xsltFile) {
if (isEmpty(xsltFile)) {
myXsltFile = null;
} else {
myXsltFile = VirtualFilePointerManager.getInstance().create(VfsUtilCore.pathToUrl(xsltFile).replace(File.separatorChar, '/'), getProject(), null);
}
}
private void setXsltFile(VirtualFile virtualFile) {
myXsltFile = VirtualFilePointerManager.getInstance().create(virtualFile, getProject(), null);
}
@Nullable
public String getXsltFile() {
return myXsltFile != null ? myXsltFile.getPresentableUrl() : null;
}
@Nullable
public VirtualFile findXsltFile() {
return myXsltFile != null ? myXsltFile.getFile() : null;
}
@Nullable
public VirtualFile findXmlInputFile() {
return myXmlInputFile != null ? myXmlInputFile.getFile() : null;
}
@Nullable
public String getXmlInputFile() {
return myXmlInputFile != null ? myXmlInputFile.getPresentableUrl() : null;
}
@Nullable
public FileType getFileType() {
return myFileType;
}
public void setFileType(@Nullable FileType fileType) {
myFileType = fileType;
}
@Nullable
public Module getModule() {
return myModule != null ? ModuleManager.getInstance(getProject()).findModuleByName(myModule) : null;
}
@Nullable
public Sdk getJdk() {
return myJdk != null ? ProjectJdkTable.getInstance().findJdk(myJdk) : null;
}
public void setXmlInputFile(@NotNull String xmlInputFile) {
if (isEmpty(xmlInputFile)) {
myXmlInputFile = null;
} else {
myXmlInputFile = VirtualFilePointerManager.getInstance().create(VfsUtilCore.pathToUrl(xmlInputFile).replace(File.separatorChar, '/'), getProject(), null);
}
}
public void setXmlInputFile(VirtualFile xmlInputFile) {
myXmlInputFile = VirtualFilePointerManager.getInstance().create(xmlInputFile, getProject(), null);
}
public void setModule(Module module) {
myModule = module != null ? module.getName() : null;
}
public void setJDK(Sdk projectJdk) {
myJdk = projectJdk != null ? projectJdk.getName() : null;
}
@NotNull
public OutputType getOutputType() {
return myOutputType;
}
public void setOutputType(@NotNull OutputType outputType) {
myOutputType = outputType;
}
public boolean isSaveToFile() {
return mySaveToFile;
}
public void setSaveToFile(boolean saveToFile) {
mySaveToFile = saveToFile;
}
@NotNull
public JdkChoice getJdkChoice() {
return myJdkChoice;
}
public void setJdkChoice(@NotNull JdkChoice jdkChoice) {
myJdkChoice = jdkChoice;
}
private static Sdk ourDefaultSdk;
private static synchronized Sdk getDefaultSdk() {
if (ourDefaultSdk == null) {
final String jdkHome = SystemProperties.getJavaHome();
final String versionName = ProjectBundle.message("sdk.java.name.template", SystemProperties.getJavaVersion());
Sdk sdk = ProjectJdkTable.getInstance().createSdk(versionName, new SimpleJavaSdkType());
SdkModificator modificator = sdk.getSdkModificator();
modificator.setHomePath(jdkHome);
modificator.commitChanges();
ourDefaultSdk = sdk;
}
return ourDefaultSdk;
}
@Nullable
public Sdk getEffectiveJDK() {
if (!XsltRunSettingsEditor.ALLOW_CHOOSING_SDK) {
return getDefaultSdk();
}
if (myJdkChoice == JdkChoice.JDK) {
return myJdk != null ? ProjectJdkTable.getInstance().findJdk(myJdk) : null;
}
Sdk jdk = null;
final Module module = getEffectiveModule();
if (module != null) {
jdk = ModuleRootManager.getInstance(module).getSdk();
}
if (jdk == null) {
jdk = ProjectRootManager.getInstance(getProject()).getProjectSdk();
}
// EA-33419
if (jdk == null || !(jdk.getSdkType() instanceof JavaSdkType)) {
return getDefaultSdk();
}
return jdk;
}
@Nullable
public Module getEffectiveModule() {
//assert myJdkChoice == JdkChoice.FROM_MODULE;
Module module = myJdkChoice == JdkChoice.FROM_MODULE ? getModule() : null;
if (module == null && myXsltFile != null) {
final VirtualFile file = myXsltFile.getFile();
if (file != null) {
final ProjectFileIndex index = ProjectRootManager.getInstance(getProject()).getFileIndex();
module = index.getModuleForFile(file);
}
}
return module;
}
@Override
public String suggestedName() {
return mySuggestedName;
}
public XsltRunConfiguration initFromFile(@NotNull XmlFile file) {
assert XsltSupport.isXsltFile(file) : "Not an XSLT file: " + file.getName();
mySuggestedName = file.getName();
final VirtualFile virtualFile = file.getVirtualFile();
assert virtualFile != null : "No VirtualFile for " + file.getName();
setXsltFile(virtualFile);
final PsiFile[] associations = FileAssociationsManager.getInstance(file.getProject()).getAssociationsFor(file);
if (associations.length > 0) {
final VirtualFile assoc = associations[0].getVirtualFile();
assert assoc != null;
setXmlInputFile(assoc);
}
final XmlDocument document = file.getDocument();
assert document != null : "XSLT file without document?";
final XmlTag rootTag = document.getRootTag();
assert rootTag != null : "XSLT file without root element?";
final XmlTag[] params = rootTag.findSubTags("param", XsltSupport.XSLT_NS);
for (XmlTag param : params) {
final String name = param.getAttributeValue("name");
if (name != null) {
final Pair<String, String> pair = Pair.create(name, null);
myParameters.add(pair);
}
}
final XmlTag[] outputs = rootTag.findSubTags("output", XsltSupport.XSLT_NS);
for (XmlTag output : outputs) {
final String method = output.getAttributeValue("method");
if ("xml".equals(method)) {
setFileType(StdFileTypes.XML);
} else if ("html".equals(method)) {
setFileType(StdFileTypes.HTML);
} else if ("text".equals(method)) {
setFileType(FileTypes.PLAIN_TEXT);
}
}
return this;
}
}