File D:\maven-qcr-plugin-testsunitaires\qcr4java\jenkins-master\target\site\qc\core\src\main\java\hudson\matrix\DefaultMatrixExecutionStrategyImpl.java.html

1 package hudson.matrix;
2
3 import hudson.AbortException;
4 import hudson.Extension;
5 import hudson.Util;
6 import hudson.console.ModelHyperlinkNote;
7 import hudson.matrix.MatrixBuild.MatrixBuildExecution;
8 import hudson.matrix.listeners.MatrixBuildListener;
9 import hudson.model.BuildListener;
10 import hudson.model.Cause.UpstreamCause;
11 import hudson.model.ParametersAction;
12 import hudson.model.Queue;
13 import hudson.model.ResourceController;
14 import hudson.model.Result;
15 import hudson.model.Run;
16 import org.kohsuke.stapler.DataBoundConstructor;
17
18 import javax.annotation.Nullable;
19 import java.io.IOException;
20 import java.io.PrintStream;
21 import java.util.Collection;
22 import java.util.Comparator;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.TreeSet;
26
27 /**
28 * {@link MatrixExecutionStrategy} that captures historical behavior.
29 *
30 * <p>
31 * This class is somewhat complex because historically this wasn't an extension point and so
32 * people tried to put various logics that cover different use cases into one place.
33 * Going forward, people are encouraged to create subtypes to implement a custom logic that suits their needs.
34 *
35 * @author Kohsuke Kawaguchi
36 * @since 1.456
37 */
38 public class DefaultMatrixExecutionStrategyImpl extends MatrixExecutionStrategy {
39 private volatile boolean runSequentially;
40
41 /**
42 * Filter to select a number of combinations to build first
43 */
44 private volatile String touchStoneCombinationFilter;
45
46 /**
47 * Required result on the touchstone combinations, in order to
48 * continue with the rest
49 */
50 private volatile Result touchStoneResultCondition;
51
52 private volatile MatrixConfigurationSorter sorter;
53
54 @DataBoundConstructor
55 public DefaultMatrixExecutionStrategyImpl(Boolean runSequentially, boolean hasTouchStoneCombinationFilter, String touchStoneCombinationFilter, Result touchStoneResultCondition, MatrixConfigurationSorter sorter) {
56 this(runSequentially!=null ? runSequentially : false,
57 hasTouchStoneCombinationFilter ? touchStoneCombinationFilter : null,
58 hasTouchStoneCombinationFilter ? touchStoneResultCondition : null,
59 sorter);
60 }
61
62 public DefaultMatrixExecutionStrategyImpl(boolean runSequentially, String touchStoneCombinationFilter, Result touchStoneResultCondition, MatrixConfigurationSorter sorter) {
63 this.runSequentially = runSequentially;
64 this.touchStoneCombinationFilter = touchStoneCombinationFilter;
65 this.touchStoneResultCondition = touchStoneResultCondition;
66 this.sorter = sorter;
67 }
68
69 public DefaultMatrixExecutionStrategyImpl() {
70 this(false,false,null,null,null);
71 }
72
73 public boolean getHasTouchStoneCombinationFilter() {
74 return touchStoneCombinationFilter!=null;
75 }
76
77 /**
78 * If true, {@link MatrixRun}s are run sequentially, instead of running in parallel.
79 *
80 * TODO: this should be subsumed by {@link ResourceController}.
81 */
82 public boolean isRunSequentially() {
83 return runSequentially;
84 }
85
86 public void setRunSequentially(boolean runSequentially) {
87 this.runSequentially = runSequentially;
88 }
89
90 public String getTouchStoneCombinationFilter() {
91 return touchStoneCombinationFilter;
92 }
93
94 public void setTouchStoneCombinationFilter(String touchStoneCombinationFilter) {
95 this.touchStoneCombinationFilter = touchStoneCombinationFilter;
96 }
97
98 public Result getTouchStoneResultCondition() {
99 return touchStoneResultCondition;
100 }
101
102 public void setTouchStoneResultCondition(Result touchStoneResultCondition) {
103 this.touchStoneResultCondition = touchStoneResultCondition;
104 }
105
106 public MatrixConfigurationSorter getSorter() {
107 return sorter;
108 }
109
110 public void setSorter(MatrixConfigurationSorter sorter) {
111 this.sorter = sorter;
112 }
113
114 @Override
115 public Result run(MatrixBuildExecution execution) throws InterruptedException, IOException {
116 MatrixBuild build = execution.getBuild();
117 MatrixProject p = execution.getProject();
118 PrintStream logger = execution.getListener().getLogger();
119
120 Collection<MatrixConfiguration> touchStoneConfigurations = new HashSet<MatrixConfiguration>();
121 Collection<MatrixConfiguration> delayedConfigurations = new HashSet<MatrixConfiguration>();
122 for (MatrixConfiguration c: execution.getActiveConfigurations()) {
123 if (!MatrixBuildListener.buildConfiguration(build, c))
124 continue; // skip rebuild
125 if (touchStoneCombinationFilter != null && c.getCombination().evalGroovyExpression(p.getAxes(), getTouchStoneCombinationFilter())) {
126 touchStoneConfigurations.add(c);
127 } else {
128 delayedConfigurations.add(c);
129 }
130 }
131
132 if (notifyStartBuild(execution.getAggregators())) return Result.FAILURE;
133
134 if (sorter != null) {
135 touchStoneConfigurations = createTreeSet(touchStoneConfigurations, sorter);
136 delayedConfigurations = createTreeSet(delayedConfigurations,sorter);
137 }
138
139 if(!runSequentially)
140 for(MatrixConfiguration c : touchStoneConfigurations)
141 scheduleConfigurationBuild(execution, c);
142
143 Result r = Result.SUCCESS;
144 for (MatrixConfiguration c : touchStoneConfigurations) {
145 if(runSequentially)
146 scheduleConfigurationBuild(execution, c);
147 MatrixRun run = waitForCompletion(execution, c);
148 notifyEndBuild(run,execution.getAggregators());
149 r = r.combine(getResult(run));
150 }
151
152 if (touchStoneResultCondition != null && r.isWorseThan(touchStoneResultCondition)) {
153 logger.printf("Touchstone configurations resulted in %s, so aborting...%n", r);
154 return r;
155 }
156
157 if(!runSequentially)
158 for(MatrixConfiguration c : delayedConfigurations)
159 scheduleConfigurationBuild(execution, c);
160
161 for (MatrixConfiguration c : delayedConfigurations) {
162 if(runSequentially)
163 scheduleConfigurationBuild(execution, c);
164 MatrixRun run = waitForCompletion(execution, c);
165 notifyEndBuild(run,execution.getAggregators());
166 logger.println(Messages.MatrixBuild_Completed(ModelHyperlinkNote.encodeTo(c), getResult(run)));
167 r = r.combine(getResult(run));
168 }
169
170 return r;
171 }
172
173 private Result getResult(@Nullable MatrixRun run) {
174 // null indicates that the run was cancelled before it even gets going
175 return run!=null ? run.getResult() : Result.ABORTED;
176 }
177
178 private boolean notifyStartBuild(List<MatrixAggregator> aggregators) throws InterruptedException, IOException {
179 for (MatrixAggregator a : aggregators)
180 if(!a.startBuild())
181 return true;
182 return false;
183 }
184
185 private void notifyEndBuild(MatrixRun b, List<MatrixAggregator> aggregators) throws InterruptedException, IOException {
186 if (b==null) return; // can happen if the configuration run gets cancelled before it gets started.
187 for (MatrixAggregator a : aggregators)
188 if(!a.endRun(b))
189 throw new AbortException();
190 }
191
192 private <T> TreeSet<T> createTreeSet(Collection<T> items, Comparator<T> sorter) {
193 TreeSet<T> r = new TreeSet<T>(sorter);
194 r.addAll(items);
195 return r;
196 }
197
198 /** Function to start schedule a single configuration
199 *
200 * This function schedule a build of a configuration passing all of the Matrixchild actions
201 * that are present in the parent build.
202 *
203 * @param exec Matrix build that is the parent of the configuration
204 * @param c Configuration to schedule
205 */
206 private void scheduleConfigurationBuild(MatrixBuildExecution exec, MatrixConfiguration c) {
207 MatrixBuild build = exec.getBuild();
208 exec.getListener().getLogger().println(Messages.MatrixBuild_Triggering(ModelHyperlinkNote.encodeTo(c)));
209
210 // filter the parent actions for those that can be passed to the individual jobs.
211 List<MatrixChildAction> childActions = Util.filter(build.getActions(), MatrixChildAction.class);
212 c.scheduleBuild(childActions, new UpstreamCause((Run)build));
213 }
214
215 private MatrixRun waitForCompletion(MatrixBuildExecution exec, MatrixConfiguration c) throws InterruptedException, IOException {
216 BuildListener listener = exec.getListener();
217 String whyInQueue = "";
218 long startTime = System.currentTimeMillis();
219
220 // wait for the completion
221 int appearsCancelledCount = 0;
222 while(true) {
223 MatrixRun b = c.getBuildByNumber(exec.getBuild().getNumber());
224
225 // two ways to get beyond this. one is that the build starts and gets done,
226 // or the build gets cancelled before it even started.
227 if(b!=null && !b.isBuilding()) {
228 Result buildResult = b.getResult();
229 if(buildResult!=null)
230 return b;
231 }
232 Queue.Item qi = c.getQueueItem();
233 if(b==null && qi==null)
234 appearsCancelledCount++;
235 else
236 appearsCancelledCount = 0;
237
238 if(appearsCancelledCount>=5) {
239 // there's conceivably a race condition in computating b and qi, as their computation
240 // are not synchronized. There are indeed several reports of Hudson incorrectly assuming
241 // builds being cancelled. See
242 // http://www.nabble.com/Master-slave-problem-tt14710987.html and also
243 // http://www.nabble.com/Anyone-using-AccuRev-plugin--tt21634577.html#a21671389
244 // because of this, we really make sure that the build is cancelled by doing this 5
245 // times over 5 seconds
246 listener.getLogger().println(Messages.MatrixBuild_AppearsCancelled(ModelHyperlinkNote.encodeTo(c)));
247 return null;
248 }
249
250 if(qi!=null) {
251 // if the build seems to be stuck in the queue, display why
252 String why = qi.getWhy();
253 if(!why.equals(whyInQueue) && System.currentTimeMillis()-startTime>5000) {
254 listener.getLogger().print("Configuration " + ModelHyperlinkNote.encodeTo(c)+" is still in the queue: ");
255 qi.getCauseOfBlockage().print(listener); //this is still shown on the same line
256 whyInQueue = why;
257 }
258 }
259
260 Thread.sleep(1000);
261 }
262 }
263
264 @Extension
265 public static class DescriptorImpl extends MatrixExecutionStrategyDescriptor {
266 @Override
267 public String getDisplayName() {
268 return "Classic";
269 }
270 }
271 }
272