提交 3c992383 编写于 作者: K kohsuke

use RunList in Job.getBuilds() as well, since it's making a copy.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@34041 71c3de6d-444a-0410-be80-ed276b4c234a
上级 c9ab4c04
...@@ -26,6 +26,7 @@ package hudson.model; ...@@ -26,6 +26,7 @@ package hudson.model;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT; import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import hudson.ExtensionPoint; import hudson.ExtensionPoint;
import hudson.Util; import hudson.Util;
import hudson.XmlFile; import hudson.XmlFile;
...@@ -67,10 +68,10 @@ import java.io.StringWriter; ...@@ -67,10 +68,10 @@ import java.io.StringWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.AbstractList; import java.util.AbstractList;
import java.text.ParseException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -585,13 +586,14 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R ...@@ -585,13 +586,14 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
public abstract boolean isBuildable(); public abstract boolean isBuildable();
/** /**
* Gets all the builds. * Gets the read-only view of all the builds.
* *
* @return never null. The first entry is the latest build. * @return never null. The first entry is the latest build.
*/ */
@Exported @Exported
public List<RunT> getBuilds() { @WithBridgeMethods(List.class)
return new ArrayList<RunT>(_getRuns().values()); public RunList<JobT,RunT> getBuilds() {
return RunList.fromRuns(_getRuns().values());
} }
/** /**
...@@ -643,32 +645,12 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R ...@@ -643,32 +645,12 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
* Obtains a list of builds, in the descending order, that are within the specified time range [start,end). * Obtains a list of builds, in the descending order, that are within the specified time range [start,end).
* *
* @return can be empty but never null. * @return can be empty but never null.
* @deprecated
* as of 1.372. Should just do {@code getBuilds().byTimestamp(s,e)} to avoid code bloat in {@link Job}.
*/ */
public List<RunT> getBuildsByTimestamp(long start, long end) { @WithBridgeMethods(List.class)
final List<RunT> builds = getBuilds(); public RunList<JobT,RunT> getBuildsByTimestamp(long start, long end) {
AbstractList<Long> TIMESTAMP_ADAPTER = new AbstractList<Long>() { return getBuilds().byTimestamp(start,end);
public Long get(int index) {
return builds.get(index).timestamp;
}
public int size() {
return builds.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 builds.subList(e,s);
} }
@CLIResolver @CLIResolver
...@@ -1364,12 +1346,12 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R ...@@ -1364,12 +1346,12 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
public void doRssAll(StaplerRequest req, StaplerResponse rsp) public void doRssAll(StaplerRequest req, StaplerResponse rsp)
throws IOException, ServletException { throws IOException, ServletException {
rss(req, rsp, " all builds", new RunList(this)); rss(req, rsp, " all builds", getBuilds());
} }
public void doRssFailed(StaplerRequest req, StaplerResponse rsp) public void doRssFailed(StaplerRequest req, StaplerResponse rsp)
throws IOException, ServletException { throws IOException, ServletException {
rss(req, rsp, " failed builds", new RunList(this).failureOnly()); rss(req, rsp, " failed builds", getBuilds().failureOnly());
} }
private void rss(StaplerRequest req, StaplerResponse rsp, String suffix, private void rss(StaplerRequest req, StaplerResponse rsp, String suffix,
......
...@@ -31,52 +31,56 @@ import hudson.model.Result; ...@@ -31,52 +31,56 @@ import hudson.model.Result;
import hudson.model.Run; import hudson.model.Run;
import hudson.model.View; import hudson.model.View;
import java.util.AbstractList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
/** /**
* {@link List} of {@link Run}s. * {@link List} of {@link Run}s, sorted in the date order.
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
public class RunList extends ArrayList<Run> { public class RunList<J extends Job<J,R>, R extends Run<J,R>> extends ArrayList<R> {
public RunList() { public RunList() {
} }
public RunList(Job<?,?> j) { public RunList(J j) {
addAll(j.getBuilds()); addAll(j.getBuilds());
} }
public RunList(View view) { public RunList(View view) {// this is a type unsafe operation
for (Item item : view.getItems()) for (Item item : view.getItems())
for (Job<?,?> j : item.getAllJobs()) for (Job<?,?> j : item.getAllJobs())
addAll(j.getBuilds()); addAll((Collection<R>)j.getBuilds());
Collections.sort(this,Run.ORDER_BY_DATE); Collections.sort(this,Run.ORDER_BY_DATE);
} }
public RunList(Collection<? extends Job> jobs) { public RunList(Collection<? extends J> jobs) {
for (Job<?,?> j : jobs) for (J j : jobs)
addAll(j.getBuilds()); addAll(j.getBuilds());
Collections.sort(this,Run.ORDER_BY_DATE); Collections.sort(this,Run.ORDER_BY_DATE);
} }
public static RunList fromRuns(Collection<? extends Run> runs) { private RunList(Collection<? extends R> c, boolean hack) {
RunList r = new RunList(); super(c);
r.addAll(runs); }
return r;
public static <J extends Job<J,R>,R extends Run<J,R>>
RunList<J,R> fromRuns(Collection<? extends R> runs) {
return new RunList<J,R>(runs,false);
} }
/** /**
* Filter the list to non-successful builds only. * Filter the list to non-successful builds only.
*/ */
public RunList failureOnly() { public RunList<J,R> failureOnly() {
for (Iterator<Run> itr = iterator(); itr.hasNext();) { for (Iterator<R> itr = iterator(); itr.hasNext();) {
Run r = itr.next(); Run r = itr.next();
if(r.getResult()==Result.SUCCESS) if(r.getResult()==Result.SUCCESS)
itr.remove(); itr.remove();
...@@ -87,8 +91,8 @@ public class RunList extends ArrayList<Run> { ...@@ -87,8 +91,8 @@ public class RunList extends ArrayList<Run> {
/** /**
* Filter the list to builds on a single node only * Filter the list to builds on a single node only
*/ */
public RunList node(Node node) { public RunList<J,R> node(Node node) {
for (Iterator<Run> itr = iterator(); itr.hasNext();) { for (Iterator<R> itr = iterator(); itr.hasNext();) {
Run r = itr.next(); Run r = itr.next();
if (!(r instanceof AbstractBuild) || ((AbstractBuild)r).getBuiltOn()!=node) { if (!(r instanceof AbstractBuild) || ((AbstractBuild)r).getBuiltOn()!=node) {
itr.remove(); itr.remove();
...@@ -100,8 +104,8 @@ public class RunList extends ArrayList<Run> { ...@@ -100,8 +104,8 @@ public class RunList extends ArrayList<Run> {
/** /**
* Filter the list to regression builds only. * Filter the list to regression builds only.
*/ */
public RunList regressionOnly() { public RunList<J,R> regressionOnly() {
for (Iterator<Run> itr = iterator(); itr.hasNext();) { for (Iterator<R> itr = iterator(); itr.hasNext();) {
Run r = itr.next(); Run r = itr.next();
if(!r.getBuildStatusSummary().isWorse) if(!r.getBuildStatusSummary().isWorse)
itr.remove(); itr.remove();
...@@ -109,19 +113,52 @@ public class RunList extends ArrayList<Run> { ...@@ -109,19 +113,52 @@ public class RunList extends ArrayList<Run> {
return this; return this;
} }
/**
* Filter the list by timestamp.
*
* {@code s&lt=;e}.
*/
public RunList<J,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
removeRange(s,size());
removeRange(0,e);
return this;
}
/** /**
* Reduce the size of the list by only leaving relatively new ones. * 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 * This also removes on-going builds, as RSS cannot be used to publish information
* if it changes. * if it changes.
*/ */
public RunList newBuilds() { public RunList<J,R> newBuilds() {
GregorianCalendar threshold = new GregorianCalendar(); GregorianCalendar threshold = new GregorianCalendar();
threshold.add(Calendar.DAY_OF_YEAR,-7); threshold.add(Calendar.DAY_OF_YEAR,-7);
int count=0; int count=0;
for (Iterator<Run> itr = iterator(); itr.hasNext();) { for (Iterator<R> itr = iterator(); itr.hasNext();) {
Run r = itr.next(); R r = itr.next();
if(r.isBuilding()) { if(r.isBuilding()) {
// can't publish on-going builds // can't publish on-going builds
itr.remove(); itr.remove();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册