/*
* Copyright 2010 the original author or authors.
*
* 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.gradle.api.internal.tasks;
import com.google.common.collect.Sets;
import groovy.lang.Closure;
import org.gradle.api.Buildable;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.Task;
import org.gradle.api.tasks.TaskDependency;
import org.gradle.api.tasks.TaskReference;
import org.gradle.internal.typeconversion.UnsupportedNotationException;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.RandomAccess;
import java.util.Set;
import java.util.concurrent.Callable;
import static com.google.common.collect.Iterables.toArray;
import static org.gradle.util.GUtil.uncheckedCall;
public class DefaultTaskDependency extends AbstractTaskDependency {
private Set<Object> values;
private final TaskResolver resolver;
public DefaultTaskDependency() {
this(null);
}
public DefaultTaskDependency(TaskResolver resolver) {
this.resolver = resolver;
}
@Override
public void visitDependencies(TaskDependencyResolveContext context) {
if (getValues().isEmpty()) {
return;
}
Deque<Object> queue = new ArrayDeque<Object>(getValues());
while (!queue.isEmpty()) {
Object dependency = queue.removeFirst();
if (dependency instanceof Buildable) {
context.add(dependency);
} else if (dependency instanceof Task) {
context.add(dependency);
} else if (dependency instanceof TaskDependency) {
context.add(dependency);
} else if (dependency instanceof Closure) {
Closure closure = (Closure) dependency;
Object closureResult = closure.call(context.getTask());
if (closureResult != null) {
queue.addFirst(closureResult);
}
} else if (dependency instanceof RealizableTaskCollection) {
RealizableTaskCollection realizableTaskCollection = (RealizableTaskCollection) dependency;
realizableTaskCollection.realizeRuleTaskTypes();
addAllFirst(queue, realizableTaskCollection.toArray());
} else if (dependency instanceof List) {
List<?> list = (List) dependency;
if (list instanceof RandomAccess) {
for (int i = list.size() - 1; i >= 0; i--) {
queue.addFirst(list.get(i));
}
} else {
ListIterator<?> iterator = list.listIterator(list.size());
while (iterator.hasPrevious()) {
Object item = iterator.previous();
queue.addFirst(item);
}
}
} else if (dependency instanceof Iterable) {
Iterable<?> iterable = (Iterable) dependency;
addAllFirst(queue, toArray(iterable, Object.class));
} else if (dependency instanceof Map) {
Map<?, ?> map = (Map) dependency;
addAllFirst(queue, map.values().toArray());
} else if (dependency instanceof Object[]) {
Object[] array = (Object[]) dependency;
addAllFirst(queue, array);
} else if (dependency instanceof Callable) {
Callable callable = (Callable) dependency;
Object callableResult = uncheckedCall(callable);
if (callableResult != null) {
queue.addFirst(callableResult);
}
} else if (resolver != null && dependency instanceof TaskReference) {
context.add(resolver.resolveTask((TaskReference) dependency));
} else if (resolver != null && dependency instanceof CharSequence) {
context.add(resolver.resolveTask(dependency.toString()));
} else {
List<String> formats = new ArrayList<String>();
if (resolver != null) {
formats.add("A String or CharSequence task name or path");
formats.add("A TaskReference instance");
}
formats.add("A Task instance");
formats.add("A Buildable instance");
formats.add("A TaskDependency instance");
formats.add("A Closure instance that returns any of the above types");
formats.add("A Callable instance that returns any of the above types");
formats.add("An Iterable, Collection, Map or array instance that contains any of the above types");
throw new UnsupportedNotationException(dependency, String.format("Cannot convert %s to a task.", dependency), null, formats);
}
}
}
private static void addAllFirst(Deque<Object> queue, Object[] items) {
for (int i = items.length - 1; i >= 0; i--) {
queue.addFirst(items[i]);
}
}
public Set<Object> getValues() {
if (values == null) {
values = Sets.newHashSet();
}
return values;
}
public void setValues(Iterable<?> values) {
getValues().clear();
for (Object value : values) {
addValue(value);
}
}
public DefaultTaskDependency add(Object... values) {
for (Object value : values) {
addValue(value);
}
return this;
}
private void addValue(Object dependency) {
if (dependency == null) {
throw new InvalidUserDataException("A dependency must not be empty");
}
getValues().add(dependency);
}
}