blob: 3078230bfbe349140140ccceb932331aa99694b8 [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* 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 com.intellij.lang.ant.config.impl;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.ide.macro.Macro;
import com.intellij.ide.macro.MacroManager;
import com.intellij.lang.ant.config.*;
import com.intellij.lang.ant.dom.AntDomFileDescription;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.impl.SimpleDataContext;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.NewInstanceFactory;
import com.intellij.util.SystemProperties;
import com.intellij.util.config.*;
import com.intellij.util.containers.HashMap;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.*;
public class AntBuildFileImpl implements AntBuildFileBase {
private static final Logger LOG = Logger.getInstance("#com.intellij.lang.ant.config.impl.AntBuildFileImpl");
@NonNls private static final String ANT_LIB = "/.ant/lib";
private volatile Map<String, String> myCachedExternalProperties;
private final Object myOptionsLock = new Object();
public static final AbstractProperty<AntInstallation> ANT_INSTALLATION = new AbstractProperty<AntInstallation>() {
public String getName() {
return "$antInstallation";
}
public AntInstallation getDefault(final AbstractPropertyContainer container) {
return GlobalAntConfiguration.INSTANCE.get(container).getBundledAnt();
}
public AntInstallation copy(final AntInstallation value) {
return value;
}
public AntInstallation get(final AbstractPropertyContainer container) {
if (container.hasProperty(ANT_REFERENCE)) {
return RUN_WITH_ANT.get(container);
}
return GlobalAntConfiguration.INSTANCE.get(container).getBundledAnt();
}
};
public static final AbstractProperty<List<File>> ALL_CLASS_PATH = new AbstractProperty<List<File>>() {
public String getName() {
return "$allClasspath";
}
public List<File> getDefault(AbstractProperty.AbstractPropertyContainer container) {
return get(container);
}
public List<File> get(AbstractProperty.AbstractPropertyContainer container) {
ArrayList<File> classpath = new ArrayList<File>();
collectClasspath(classpath, ADDITIONAL_CLASSPATH, container);
AntInstallation antInstallation = ANT_INSTALLATION.get(container);
if (antInstallation != null) {
collectClasspath(classpath, AntInstallation.CLASS_PATH, antInstallation.getProperties());
}
return classpath;
}
private void collectClasspath(ArrayList<File> files,
ListProperty<AntClasspathEntry> property,
AbstractProperty.AbstractPropertyContainer container) {
if (!container.hasProperty(property)) return;
Iterator<AntClasspathEntry> entries = property.getIterator(container);
while (entries.hasNext()) {
AntClasspathEntry entry = entries.next();
entry.addFilesTo(files);
}
}
public void set(AbstractProperty.AbstractPropertyContainer container, List<File> files) {
throw new UnsupportedOperationException(getName());
}
public List<File> copy(List<File> files) {
return files;
}
};
public static final BooleanProperty RUN_IN_BACKGROUND = new BooleanProperty("runInBackground", true);
public static final IntProperty MAX_HEAP_SIZE = new IntProperty("maximumHeapSize", 128);
public static final IntProperty MAX_STACK_SIZE = new IntProperty("maximumStackSize", 2);
public static final BooleanProperty VERBOSE = new BooleanProperty("verbose", true);
public static final BooleanProperty TREE_VIEW = new BooleanProperty("treeView", true);
public static final BooleanProperty CLOSE_ON_NO_ERRORS = new BooleanProperty("viewClosedWhenNoErrors", false);
public static final StringProperty CUSTOM_JDK_NAME = new StringProperty("customJdkName", "");
public static final ListProperty<TargetFilter> TARGET_FILTERS = ListProperty.create("targetFilters");
public static final ListProperty<BuildFileProperty> ANT_PROPERTIES = ListProperty.create("properties");
public static final StringProperty ANT_COMMAND_LINE_PARAMETERS = new StringProperty("antCommandLine", "");
public static final AbstractProperty<AntReference> ANT_REFERENCE =
new ValueProperty<AntReference>("antReference", AntReference.PROJECT_DEFAULT);
public static final ListProperty<AntClasspathEntry> ADDITIONAL_CLASSPATH = ListProperty.create("additionalClassPath");
public static final AbstractProperty<AntInstallation> RUN_WITH_ANT = new AbstractProperty<AntInstallation>() {
public String getName() {
return "$runWithAnt";
}
@Nullable
public AntInstallation getDefault(AbstractProperty.AbstractPropertyContainer container) {
return get(container);
}
@Nullable
public AntInstallation get(AbstractProperty.AbstractPropertyContainer container) {
return AntReference.findAnt(ANT_REFERENCE, container);
}
public AntInstallation copy(AntInstallation antInstallation) {
return antInstallation;
}
};
private final VirtualFile myVFile;
private final Project myProject;
private final AntConfigurationBase myAntConfiguration;
private final ExternalizablePropertyContainer myWorkspaceOptions;
private final ExternalizablePropertyContainer myProjectOptions;
private final AbstractProperty.AbstractPropertyContainer myAllOptions;
private final ClassLoaderHolder myClassloaderHolder;
private boolean myShouldExpand = true;
public AntBuildFileImpl(final XmlFile antFile, final AntConfigurationBase configuration) {
myVFile = antFile.getOriginalFile().getVirtualFile();
myProject = antFile.getProject();
myAntConfiguration = configuration;
myWorkspaceOptions = new ExternalizablePropertyContainer();
myWorkspaceOptions.registerProperty(RUN_IN_BACKGROUND);
myWorkspaceOptions.registerProperty(CLOSE_ON_NO_ERRORS);
myWorkspaceOptions.registerProperty(TREE_VIEW);
myWorkspaceOptions.registerProperty(VERBOSE);
myWorkspaceOptions.registerProperty(TARGET_FILTERS, "filter", NewInstanceFactory.fromClass(TargetFilter.class));
myWorkspaceOptions.rememberKey(RUN_WITH_ANT);
myProjectOptions = new ExternalizablePropertyContainer();
myProjectOptions.registerProperty(MAX_HEAP_SIZE);
myProjectOptions.registerProperty(MAX_STACK_SIZE);
myProjectOptions.registerProperty(CUSTOM_JDK_NAME);
myProjectOptions.registerProperty(ANT_COMMAND_LINE_PARAMETERS);
myProjectOptions.registerProperty(ANT_PROPERTIES, "property", NewInstanceFactory.fromClass(BuildFileProperty.class));
myProjectOptions.registerProperty(ADDITIONAL_CLASSPATH, "entry", SinglePathEntry.EXTERNALIZER);
myProjectOptions.registerProperty(ANT_REFERENCE, AntReference.EXTERNALIZER);
myAllOptions = new CompositePropertyContainer(new AbstractProperty.AbstractPropertyContainer[]{myWorkspaceOptions, myProjectOptions,
GlobalAntConfiguration.getInstance().getProperties(getProject())});
myClassloaderHolder = new AntBuildFileClassLoaderHolder(myAllOptions);
}
public static List<File> getUserHomeLibraries() {
ArrayList<File> classpath = new ArrayList<File>();
final String homeDir = SystemProperties.getUserHome();
new AllJarsUnderDirEntry(new File(homeDir, ANT_LIB)).addFilesTo(classpath);
return classpath;
}
@Nullable
public String getPresentableName() {
AntBuildModel model = myAntConfiguration.getModelIfRegistered(this);
String name = model != null ? model.getName() : null;
if (name == null || name.trim().length() == 0) {
name = myVFile.getName();
}
return name;
}
@Nullable
public String getName() {
final VirtualFile vFile = getVirtualFile();
return vFile != null ? vFile.getName() : null;
}
public AntBuildModelBase getModel() {
return (AntBuildModelBase)myAntConfiguration.getModel(this);
}
@Nullable
public AntBuildModelBase getModelIfRegistered() {
return (AntBuildModelBase)myAntConfiguration.getModelIfRegistered(this);
}
public boolean isRunInBackground() {
return RUN_IN_BACKGROUND.value(myAllOptions);
}
@Nullable
public XmlFile getAntFile() {
final PsiFile psiFile = myVFile.isValid() ? PsiManager.getInstance(getProject()).findFile(myVFile) : null;
if (!(psiFile instanceof XmlFile)) {
return null;
}
final XmlFile xmlFile = (XmlFile)psiFile;
return AntDomFileDescription.isAntFile(xmlFile) ? xmlFile : null;
}
public Project getProject() {
return myProject;
}
@Nullable
public VirtualFile getVirtualFile() {
return myVFile;
}
public AbstractProperty.AbstractPropertyContainer getAllOptions() {
return myAllOptions;
}
@Nullable
public String getPresentableUrl() {
final VirtualFile file = getVirtualFile();
return (file == null) ? null : file.getPresentableUrl();
}
public boolean shouldExpand() {
return myShouldExpand;
}
public void setShouldExpand(boolean expand) {
myShouldExpand = expand;
}
public boolean isTargetVisible(final AntBuildTarget target) {
final TargetFilter filter = findFilter(target.getName());
if (filter == null) {
return target.isDefault() || target.getNotEmptyDescription() != null;
}
return filter.isVisible();
}
public boolean exists() {
final VirtualFile file = getVirtualFile();
if (file == null || !(new File(file.getPath()).exists())) {
return false;
}
return true;
}
public void updateProperties() {
// do not change position
final AntBuildTarget[] targets = getModel().getTargets();
final Map<String, AntBuildTarget> targetByName = new LinkedHashMap<String, AntBuildTarget>(targets.length);
for (AntBuildTarget target : targets) {
String targetName = target.getName();
if(targetName != null) {
targetByName.put(targetName, target);
}
}
synchronized (myOptionsLock) {
myCachedExternalProperties = null;
final ArrayList<TargetFilter> filters = TARGET_FILTERS.getModifiableList(myAllOptions);
for (Iterator<TargetFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
final TargetFilter filter = iterator.next();
final String name = filter.getTargetName();
if (name == null) {
iterator.remove();
}
else {
AntBuildTarget target = targetByName.get(name);
if (target != null) {
filter.updateDescription(target);
targetByName.remove(name);
}
else {
iterator.remove();
}
}
}
// handle the rest of targets with non-null names
for (AntBuildTarget target : targetByName.values()) {
filters.add(TargetFilter.fromTarget(target));
}
}
}
public void updateConfig() {
basicUpdateConfig();
DaemonCodeAnalyzer.getInstance(getProject()).restart();
}
public void setTreeView(final boolean value) {
TREE_VIEW.primSet(myAllOptions, value);
}
public void setVerboseMode(final boolean value) {
VERBOSE.primSet(myAllOptions, value);
}
public boolean isViewClosedWhenNoErrors() {
return CLOSE_ON_NO_ERRORS.value(myAllOptions);
}
public void readWorkspaceProperties(final Element parentNode) throws InvalidDataException {
synchronized (myOptionsLock) {
myWorkspaceOptions.readExternal(parentNode);
final Element expanded = parentNode.getChild("expanded");
if (expanded != null) {
myShouldExpand = Boolean.valueOf(expanded.getAttributeValue("value"));
}
// don't lose old command line parameters
final Element antCommandLine = parentNode.getChild("antCommandLine");
if (antCommandLine != null) {
ANT_COMMAND_LINE_PARAMETERS.set(myProjectOptions, antCommandLine.getAttributeValue("value"));
}
}
}
public void writeWorkspaceProperties(final Element parentNode) throws WriteExternalException {
synchronized (myOptionsLock) {
myWorkspaceOptions.writeExternal(parentNode);
final Element expandedElem = new Element("expanded");
expandedElem.setAttribute("value", Boolean.toString(myShouldExpand));
parentNode.addContent(expandedElem);
}
}
public void readProperties(final Element parentNode) throws InvalidDataException {
synchronized (myOptionsLock) {
myProjectOptions.readExternal(parentNode);
basicUpdateConfig();
readWorkspaceProperties(parentNode); // Compatibility with old Idea
}
}
public void writeProperties(final Element parentNode) throws WriteExternalException {
synchronized (myOptionsLock) {
myProjectOptions.writeExternal(parentNode);
}
}
private void basicUpdateConfig() {
final XmlFile antFile = getAntFile();
if (antFile != null) {
bindAnt();
myClassloaderHolder.updateClasspath();
}
}
@NotNull
public Map<String, String> getExternalProperties() {
Map<String, String> result = myCachedExternalProperties;
if (result == null) {
synchronized (myOptionsLock) {
result = myCachedExternalProperties;
if (result == null) {
result = new HashMap<String, String>();
final DataContext context = SimpleDataContext.getProjectContext(myProject);
final MacroManager macroManager = MacroManager.getInstance();
Iterator<BuildFileProperty> properties = ANT_PROPERTIES.getIterator(myAllOptions);
while (properties.hasNext()) {
BuildFileProperty property = properties.next();
try {
String value = property.getPropertyValue();
value = macroManager.expandSilentMarcos(value, true, context);
value = macroManager.expandSilentMarcos(value, false, context);
result.put(property.getPropertyName(), value);
}
catch (Macro.ExecutionCancelledException e) {
LOG.debug(e);
}
}
myCachedExternalProperties = result;
}
}
}
return result;
}
private void bindAnt() {
ANT_REFERENCE.set(getAllOptions(), ANT_REFERENCE.get(getAllOptions()).bind(GlobalAntConfiguration.getInstance()));
}
@Nullable
private TargetFilter findFilter(final String targetName) {
final List<TargetFilter> filters;
synchronized (myOptionsLock) {
filters = TARGET_FILTERS.get(myAllOptions);
}
for (TargetFilter targetFilter : filters) {
if (Comparing.equal(targetName, targetFilter.getTargetName())) {
return targetFilter;
}
}
return null;
}
@NotNull
public ClassLoader getClassLoader() {
return myClassloaderHolder.getClassloader();
}
}