blob: e2e9c4efcfb01cb2f731323bc19d94597542a961 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017,2019 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - Initial API and implementation based on org.eclipse.xtext.builder.nature.XtextNature
*******************************************************************************/
package org.eclipse.ocl.xtext.base.ui.builder;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.xtext.base.ui.BaseUIActivator;
import org.eclipse.ocl.xtext.base.ui.builder.AbstractValidatingBuilder.BuildType;
/**
* An AbstractBuildSelector performs the selection of files to be built from within a project.
* Selection is based on inclusion/exclusion of file-extensions/file-paths.
*/
public abstract class AbstractBuildSelector implements IResourceVisitor, IResourceDeltaVisitor
{
protected final @NonNull IProject project;
protected final @NonNull BuildType buildType;
private final @NonNull IProgressMonitor monitor;
private final @NonNull Map<@NonNull String, @Nullable Boolean> extension2included = new HashMap<>();
private final char[][] exclusionPatterns;
private final char[][] inclusionPatterns;
private final @NonNull Set<@NonNull IFile> removedFiles = new HashSet<>();
private final @NonNull Set<@NonNull ValidationEntry> selectedEntries = new HashSet<>();
protected AbstractBuildSelector(@NonNull IProject project, @NonNull BuildType buildType, @Nullable Map<String, String> args, @NonNull IProgressMonitor monitor) {
this.project = project;
this.buildType = buildType;
this.monitor = monitor;
String[] disabledPathArray = null;
String[] enabledPathArray = null;
if (args != null) {
String includedExtensions = args.get("enabledExtensions");
if (includedExtensions != null) {
for (@NonNull String includedExtension : includedExtensions.split(",")) {
@SuppressWarnings("unused") Boolean oldIncludes = extension2included.put(includedExtension, Boolean.TRUE);
// assert oldIncludes != null; double true is not an issue
}
}
String excludedExtensions = args.get("disabledExtensions");
if (excludedExtensions != null) {
for (@NonNull String excludedExtension : excludedExtensions.split(",")) {
@SuppressWarnings("unused") Boolean oldExcludes = extension2included.put(excludedExtension, Boolean.FALSE);
// assert oldExcludes != null; double false / conflicting false is not really an issue
}
}
String enabledPaths = args.get("enabledPaths");
if (enabledPaths != null) {
enabledPathArray = enabledPaths.split(",");
}
String disabledPaths = args.get("disabledPaths");
if (disabledPaths != null) {
disabledPathArray = disabledPaths.split(",");
}
}
if (enabledPathArray != null) {
inclusionPatterns = new char[enabledPathArray.length][];
for (int i = 0; i < enabledPathArray.length; i++) {
String enabledPath = enabledPathArray[i];
inclusionPatterns[i] = (enabledPath.length() > 0 ? enabledPath : "**").toCharArray();
}
}
else {
inclusionPatterns = null;
}
if (disabledPathArray != null) {
exclusionPatterns = new char[disabledPathArray.length][];
for (int i = 0; i < disabledPathArray.length; i++) {
String disabledPath = disabledPathArray[i];
exclusionPatterns[i] = (disabledPath.length() > 0 ? disabledPath : "**").toCharArray();
}
}
else {
exclusionPatterns = null;
}
}
public void buildResources() {
MultiValidationJob multiValidationJob = BaseUIActivator.getMultiValidationJob();
if (multiValidationJob != null) {
multiValidationJob.addValidations(selectedEntries);
}
}
protected @NonNull ValidationEntry createValidationEntry(@NonNull IFile iFile) {
return new ValidationEntry(iFile, getMarkerId(iFile));
}
/**
* Return the appropriate Problem Marked Id for the results of validating iFile.
* Defaults to "org.eclipse.emf.ecore.diagnostic". Subclasses should override.
*/
@SuppressWarnings("null")
protected @NonNull String getMarkerId(@NonNull IFile iFile) {
return EValidator.MARKER;
}
public @Nullable Boolean isSelected(@NonNull IResource resource) {
if (resource instanceof IFile) {
String fileExtension = resource.getFileExtension();
if (extension2included.get(fileExtension) != Boolean.TRUE) {
return Boolean.FALSE;
}
String filePath = resource.getProjectRelativePath().toString();
char[] path = filePath.toCharArray();
boolean isExcluded = AbstractValidatingBuilder.isExcluded(path, inclusionPatterns, exclusionPatterns, false);
// System.out.println(filePath + " isExcluded " + isExcluded);
return isExcluded ? Boolean.FALSE : Boolean.TRUE;
}
else if (resource instanceof IFolder) {
// FIXME BUG 544734 this match doesn't work for non-trivial folder paths
// String filePath = resource.getProjectRelativePath().toString();
// char[] path = filePath.toCharArray();
// boolean isExcluded = AbstractValidatingBuilder.isExcluded(path, inclusionPatterns, exclusionPatterns, true);
// System.out.println(filePath + " isExcluded " + isExcluded);
return /*isExcluded ? Boolean.FALSE :*/ null;
}
else {
return null;
}
}
public int selectResources(@Nullable IResourceDelta delta) throws CoreException {
// progress.subTask(selectingResourcesMessage);
if (delta == null) { // full
project.accept(this, IResource.DEPTH_INFINITE, IResource.NONE);
}
else { // auto / incremental
delta.accept(this);
}
return selectedEntries.size();
}
@Override
public boolean visit(IResource resource) throws CoreException {
if (monitor.isCanceled())
throw new OperationCanceledException();
assert resource != null;
// System.out.println(NameUtil.debugSimpleName(this) + " visit " + resource);
Boolean isSelected = isSelected(resource);
if (isSelected == Boolean.TRUE) {
IFile iFile = (IFile) resource;
selectedEntries.add(createValidationEntry(iFile));
return true;
}
else if (isSelected == null) {
return true;
}
else {
return false;
}
}
@Override
public boolean visit(IResourceDelta delta) throws CoreException {
if (monitor.isCanceled())
throw new OperationCanceledException();
IResource resource = delta.getResource();
if (resource instanceof IProject) {
return (resource == project) && project.isOpen();
}
if (resource instanceof IContainer) {
return true;
}
if (resource instanceof IStorage) {
if (delta.getKind() == IResourceDelta.REMOVED) {
// System.out.println(NameUtil.debugSimpleName(this) + " remove " + resource);
Boolean isSelected = isSelected(resource);
if (isSelected == Boolean.TRUE) {
// IPath fullPath = ((IFile) resource).getFullPath();
// assert fullPath != null;
removedFiles.add((IFile) resource);
return true;
}
else if (isSelected == null) {
return true;
}
else {
return false;
}
} else if (delta.getKind() == IResourceDelta.ADDED || delta.getKind() == IResourceDelta.CHANGED) {
// System.out.println(NameUtil.debugSimpleName(this) + " update " + resource);
Boolean isSelected = isSelected(resource);
if (isSelected == Boolean.TRUE) {
IFile iFile = (IFile) resource;
selectedEntries.add(createValidationEntry(iFile));
return true;
}
else if (isSelected == null) {
return true;
}
else {
return false;
}
}
}
return false;
}
public void deleteMarkers() {
for (@NonNull ValidationEntry entry : selectedEntries) {
try {
entry.deleteMarkers();
} catch (CoreException e) {
// e.printStackTrace(); -- if deleteMarkers fails we probably don't want extra noise
}
}
}
protected int deleteRemovedResourceMarkers() {
for (@NonNull IFile removedFile : removedFiles) {
try {
String markerId = getMarkerId(removedFile);
// if (AbstractValidatingBuilder.BUILDER.isActive()) {
// AbstractValidatingBuilder.BUILDER.println("Remove \"" + markerId + "\" markers from \"" + removedFile.getFullPath() + "\"");
// }
removedFile.deleteMarkers(markerId, true, IResource.DEPTH_ZERO);
} catch (CoreException e) {
// e.printStackTrace();
}
}
return removedFiles.size();
}
}