/*******************************************************************************
*
* Copyright (c) 2004-2009 Oracle Corporation.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*
* Kohsuke Kawaguchi
*
*
*******************************************************************************/
package hudson.util;
import hudson.model.AbstractBuild;
import hudson.model.Item;
import hudson.model.Job;
import hudson.model.Node;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.View;
import java.util.AbstractList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
/**
* {@link List} of {@link Run}s, sorted in the descending date order.
*
* TODO: this should be immutable
*
* @author Kohsuke Kawaguchi
*/
public class RunList<R extends Run> extends AbstractRunList<R> {
public RunList() {
}
public RunList(Job j) {
addAll(j.getBuilds());
}
@Override
public R getFirstBuild() {
return isEmpty() ? null : get(size() - 1);
}
@Override
public R getLastBuild() {
return isEmpty() ? null : get(0);
}
public RunList(View view) {// this is a type unsafe operation
for (Item item : view.getItems()) {
for (Job<?, ?> j : item.getAllJobs()) {
addAll((Collection<R>) j.getBuilds());
}
}
Collections.sort(this, Run.ORDER_BY_DATE);
}
public RunList(Collection<? extends Job> jobs) {
for (Job j : jobs) {
addAll(j.getBuilds());
}
Collections.sort(this, Run.ORDER_BY_DATE);
}
private RunList(Collection<? extends R> c, boolean dummy) {
super(c);
}
public static <R extends Run> RunList<R> fromRuns(Collection<? extends R> runs) {
return new RunList<R>(runs, false);
}
/**
* Filter the list to non-successful builds only.
*/
@Override
public RunList<R> failureOnly() {
for (Iterator<R> itr = iterator(); itr.hasNext();) {
Run r = itr.next();
if (r.getResult() == Result.SUCCESS) {
itr.remove();
}
}
return this;
}
/**
* Filter the list to builds on a single node only
*/
@Override
public RunList<R> node(Node node) {
for (Iterator<R> itr = iterator(); itr.hasNext();) {
Run r = itr.next();
if (!(r instanceof AbstractBuild) || ((AbstractBuild) r).getBuiltOn() != node) {
itr.remove();
}
}
return this;
}
/**
* Filter the list to regression builds only.
*/
@Override
public RunList<R> regressionOnly() {
for (Iterator<R> itr = iterator(); itr.hasNext();) {
Run r = itr.next();
if (!r.getBuildStatusSummary().isWorse) {
itr.remove();
}
}
return this;
}
/**
* Filter the list by timestamp.
*
* {@code s<=;e}.
*/
@Override
public RunList<R> byTimestamp(long start, long end) {
AbstractList<Long> TIMESTAMP_ADAPTER = new AbstractList<Long>() {
public Long get(int index) {
return RunList.this.get(index).getTimeInMillis();
}
public int size() {
return RunList.this.size();
}
};
Comparator<Long> DESCENDING_ORDER = new Comparator<Long>() {
public int compare(Long o1, Long o2) {
if (o1 > o2) {
return -1;
}
if (o1 < o2) {
return +1;
}
return 0;
}
};
int s = Collections.binarySearch(TIMESTAMP_ADAPTER, start, DESCENDING_ORDER);
if (s < 0) {
s = -(s + 1); // min is inclusive
}
int e = Collections.binarySearch(TIMESTAMP_ADAPTER, end, DESCENDING_ORDER);
if (e < 0) {
e = -(e + 1);
} else {
e++; // max is exclusive, so the exact match should be excluded
}
return fromRuns(subList(e, s));
}
/**
* Reduce the size of the list by only leaving relatively new ones. This
* also removes on-going builds, as RSS cannot be used to publish
* information if it changes.
*/
@Override
public RunList<R> newBuilds() {
GregorianCalendar threshold = new GregorianCalendar();
threshold.add(Calendar.DAY_OF_YEAR, -7);
int count = 0;
for (Iterator<R> itr = iterator(); itr.hasNext();) {
R r = itr.next();
if (r.isBuilding()) {
// can't publish on-going builds
itr.remove();
continue;
}
// at least put 10 items
if (count < 10) {
count++;
continue;
}
// anything older than 7 days will be ignored
if (r.getTimestamp().before(threshold)) {
itr.remove();
}
}
return this;
}
}