blob: 2fe914391423f0f9ebaaa69248c81b903e1843e3 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2014, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.eutils.autonature;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.statet.eutils.autonature.core.ProjectConfigurator;
public class TaskProcessor {
private class ConfigJob extends WorkspaceJob {
public ConfigJob() {
super("Auto Project Configuration");
setUser(false);
setRule(ResourcesPlugin.getWorkspace().getRoot());
}
@Override
public IStatus runInWorkspace(final IProgressMonitor monitor) throws CoreException {
return TaskProcessor.this.process(monitor);
}
}
public static void aggregateTasks(final IProject project, final List<AutoConfig> configs,
final int flags,
List<Task> configurableTasks, List<Task> alreadyConfigTasks, List<Task> notConfigTasks,
final SubMonitor m) throws CoreException {
final int l= configs.size();
if (configurableTasks == null) {
configurableTasks= new ArrayList<>(l);
}
if (alreadyConfigTasks == null) {
alreadyConfigTasks= new ArrayList<>(l);
}
if (notConfigTasks == null) {
notConfigTasks= new ArrayList<>();
}
for (int i= 0; i < l; i++) {
m.setWorkRemaining(l - i);
final AutoConfig config= configs.get(i);
if (config.isAvailable()) {
for (final Task task : config.getTasks()) {
if (!(configurableTasks.contains(task)
|| alreadyConfigTasks.contains(task)
|| notConfigTasks.contains(task) )) {
switch (task.check(project, flags, m.newChild(1))) {
case ProjectConfigurator.CONFIGURABLE:
configurableTasks.add(task);
break;
case ProjectConfigurator.ALREADY_CONFIGURED:
alreadyConfigTasks.add(task);
break;
default:
notConfigTasks.add(task);
break;
}
}
}
}
}
}
public static IStatus process(final IProject project, final Collection<Task> tasks,
final SubMonitor m) {
try {
int taskCount= 0;
for (final Task task : tasks) {
if (task instanceof ConfiguratorTask) {
taskCount++;
}
}
m.beginTask(NLS.bind("Configuring project ''{0}''", project.getName()), 3 + taskCount);
final IProjectDescription description= project.getDescription();
boolean descriptionChanged= false;
final String[] existingNatureIds= description.getNatureIds();
final List<String> natureIds= new ArrayList<>(existingNatureIds.length + tasks.size());
for (int i= 0; i < existingNatureIds.length; i++) {
natureIds.add(existingNatureIds[i]= existingNatureIds[i].intern());
}
for (final Task task : tasks) {
if (task instanceof NatureTask) {
final String natureId= ((NatureTask) task).getNatureId();
if (!contains(existingNatureIds, natureId)) {
natureIds.add(natureId);
}
}
}
m.worked(1);
if (natureIds.size() > existingNatureIds.length) {
final ConfigManager configManager= Activator.getInstance().getConfigManager();
configManager.arrangeNatures(natureIds, existingNatureIds.length);
description.setNatureIds(natureIds.toArray(new String[natureIds.size()]));
descriptionChanged= true;
}
if (descriptionChanged) {
project.setDescription(description, m.newChild(1));
}
m.setWorkRemaining(taskCount);
for (final Task task : tasks) {
if (task instanceof ConfiguratorTask) {
((ConfiguratorTask) task).configure(project, m.newChild(1));
}
}
return Status.OK_STATUS;
}
catch (final CoreException e) {
return new Status(IStatus.ERROR, Activator.BUNDLE_ID,
NLS.bind("An error occurred when configuring project ''{0}''.", project.getName()),
e );
}
}
private Map<IProject, List<Task>> projectTasks;
private ConfigJob job;
public TaskProcessor() {
this.projectTasks= new HashMap<>();
}
public synchronized void add(final IProject project, final List<Task> tasks) {
final List<Task> allTasks= this.projectTasks.get(project);
if (allTasks == null) {
this.projectTasks.put(project, new ArrayList<>(tasks));
return;
}
for (final Task task : tasks) {
if (!allTasks.contains(task)) {
allTasks.add(task);
}
}
}
public synchronized void schedule() {
if (this.projectTasks.isEmpty()) {
return;
}
if (this.job == null) {
this.job= new ConfigJob();
}
this.job.schedule();
}
private IStatus process(final IProgressMonitor monitor) {
final Map<IProject, List<Task>> tasks;
synchronized (this) {
tasks= this.projectTasks;
if (tasks.isEmpty()) {
return Status.OK_STATUS;
}
this.projectTasks= new HashMap<>();
}
final SubMonitor m= SubMonitor.convert(monitor, tasks.size());
List<IStatus> status= null;
for (final Map.Entry<IProject, List<Task>> entry : tasks.entrySet()) {
final IStatus projectStatus= process(entry.getKey(), entry.getValue(),
m.newChild(1, SubMonitor.SUPPRESS_NONE) );
if (!projectStatus.isOK()) {
if (status == null) {
status= new ArrayList<>(tasks.size());
}
status.add(projectStatus);
}
}
if (status != null) {
return new MultiStatus(Activator.BUNDLE_ID, 0, status.toArray(new IStatus[status.size()]),
(status.size() == 1) ?
"The auto project configuration failed for 1 project." :
NLS.bind("The auto project configuration failed for {0} projects.", status.size()),
null );
}
return Status.OK_STATUS;
}
private static boolean contains(final String[] array, final String s) {
for (int i= 0; i < array.length; i++) {
if (array[i] == s) {
return true;
}
}
return false;
}
}