1 package hudson.model; 2 3 import hudson.FilePath; 4 import hudson.Launcher; 5 import hudson.Launcher.LocalLauncher; 6 import hudson.maven.MavenModule; 7 import hudson.model.Descriptor.FormException; 8 import hudson.model.Fingerprint.RangeSet; 9 import hudson.model.RunMap.Constructor; 10 import hudson.scm.NullSCM; 11 import hudson.scm.SCM; 12 import hudson.scm.SCMS; 13 import hudson.triggers.Trigger; 14 import hudson.triggers.Triggers; 15 import hudson.triggers.TriggerDescriptor; 16 import hudson.util.EditDistance; 17 import org.kohsuke.stapler.StaplerRequest; 18 import org.kohsuke.stapler.StaplerResponse; 19 20 import javax.servlet.ServletException ; 21 import java.io.File ; 22 import java.io.IOException ; 23 import java.util.Collection ; 24 import java.util.Comparator ; 25 import java.util.List ; 26 import java.util.Map ; 27 import java.util.SortedMap ; 28 import java.util.TreeMap ; 29 import java.util.Vector ; 30 31 39 public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends AbstractBuild<P,R>> extends Job<P,R> implements BuildableItem { 40 41 private SCM scm = new NullSCM(); 42 43 46 protected transient RunMap<R> builds = new RunMap<R>(); 47 48 51 private Integer quietPeriod = null; 52 53 60 private String assignedNode; 61 62 69 private boolean canRoam; 70 71 74 protected boolean disabled; 75 76 86 private String jdk; 87 88 91 private transient boolean enableRemoteTrigger; 92 93 private BuildAuthorizationToken authToken = null; 94 95 98 protected List <Trigger<?>> triggers = new Vector <Trigger<?>>(); 99 100 protected AbstractProject(ItemGroup parent, String name) { 101 super(parent,name); 102 103 if(!Hudson.getInstance().getSlaves().isEmpty()) { 104 canRoam = true; 107 } 108 } 109 110 @Override 111 public void onLoad(ItemGroup<? extends Item> parent, String name) throws IOException { 112 super.onLoad(parent, name); 113 114 this.builds = new RunMap<R>(); 115 this.builds.load(this,new Constructor<R>() { 116 public R create(File dir) throws IOException { 117 return loadBuild(dir); 118 } 119 }); 120 121 if(triggers==null) 122 triggers = new Vector <Trigger<?>>(); 124 for (Trigger t : triggers) 125 t.start(this,false); 126 } 127 128 132 public Node getAssignedNode() { 133 if(canRoam) 134 return null; 135 136 if(assignedNode ==null) 137 return Hudson.getInstance(); 138 return Hudson.getInstance().getSlave(assignedNode); 139 } 140 141 144 public abstract FilePath getWorkspace(); 145 146 152 public FilePath getModuleRoot() { 153 return getScm().getModuleRoot(getWorkspace()); 154 } 155 156 public int getQuietPeriod() { 157 return quietPeriod!=null ? quietPeriod : Hudson.getInstance().getQuietPeriod(); 158 } 159 160 public boolean getHasCustomQuietPeriod() { 162 return quietPeriod!=null; 163 } 164 165 public final boolean isBuildable() { 166 return true; 167 } 168 169 public boolean isDisabled() { 170 return disabled; 171 } 172 173 181 public boolean scheduleBuild() { 182 if(isDisabled()) return false; 183 return Hudson.getInstance().getQueue().add(this); 184 } 185 186 189 @Override 190 public boolean isInQueue() { 191 return Hudson.getInstance().getQueue().contains(this); 192 } 193 194 197 public boolean isBuilding() { 198 R b = getLastBuild(); 199 return b!=null && b.isBuilding(); 200 } 201 202 public JDK getJDK() { 203 return Hudson.getInstance().getJDK(jdk); 204 } 205 206 209 public synchronized void setJDK(JDK jdk) throws IOException { 210 this.jdk = jdk.getName(); 211 save(); 212 } 213 214 public BuildAuthorizationToken getAuthToken() { 215 return authToken; 216 } 217 218 public SortedMap <Integer , ? extends R> _getRuns() { 219 return builds.getView(); 220 } 221 222 public void removeRun(R run) { 223 this.builds.remove(run); 224 } 225 226 229 protected abstract R newBuild() throws IOException ; 230 231 234 protected abstract R loadBuild(File dir) throws IOException ; 235 236 243 public Node getLastBuiltOn() { 244 AbstractBuild b = getLastBuild(); 246 if(b==null) 247 return null; 248 else 249 return b.getBuiltOn(); 250 } 251 252 260 protected boolean isBuildBlocked() { 261 return isBuilding(); 262 } 263 264 public boolean checkout(AbstractBuild build, Launcher launcher, BuildListener listener, File changelogFile) throws IOException { 265 if(scm==null) 266 return true; 268 try { 269 FilePath workspace = getWorkspace(); 270 workspace.mkdirs(); 271 272 return scm.checkout(build, launcher, workspace, listener, changelogFile); 273 } catch (InterruptedException e) { 274 e.printStackTrace(listener.fatalError("SCM check out aborted")); 275 return false; 276 } 277 } 278 279 286 public boolean pollSCMChanges( TaskListener listener ) { 287 if(scm==null) { 288 listener.getLogger().println("No SCM"); 289 return false; 290 } 291 if(isDisabled()) { 292 listener.getLogger().println("Build disabled"); 293 return false; 294 } 295 296 try { 297 FilePath workspace = getWorkspace(); 298 if(!workspace.exists()) { 299 listener.getLogger().println("No workspace is available, so can't check for updates."); 301 listener.getLogger().println("Scheduling a new build to get a workspace."); 302 return true; 303 } 304 305 return scm.pollChanges(this, new LocalLauncher(listener), workspace, listener ); 307 } catch (IOException e) { 308 e.printStackTrace(listener.fatalError(e.getMessage())); 309 return false; 310 } catch (InterruptedException e) { 311 e.printStackTrace(listener.fatalError("SCM polling aborted")); 312 return false; 313 } 314 } 315 316 public SCM getScm() { 317 return scm; 318 } 319 320 public void setScm(SCM scm) { 321 this.scm = scm; 322 } 323 324 327 public void addTrigger(Trigger<?> trigger) throws IOException { 328 addToList(trigger,triggers); 329 } 330 331 public void removeTrigger(TriggerDescriptor trigger) throws IOException { 332 removeFromList(trigger,triggers); 333 } 334 335 protected final synchronized <T extends Describable<T>> 336 void addToList( T item, List <T> collection ) throws IOException { 337 for( int i=0; i<collection.size(); i++ ) { 338 if(collection.get(i).getDescriptor()==item.getDescriptor()) { 339 collection.set(i,item); 341 save(); 342 return; 343 } 344 } 345 collection.add(item); 347 save(); 348 } 349 350 protected final synchronized <T extends Describable<T>> 351 void removeFromList(Descriptor<T> item, List <T> collection) throws IOException { 352 for( int i=0; i< collection.size(); i++ ) { 353 if(collection.get(i).getDescriptor()==item) { 354 collection.remove(i); 356 save(); 357 return; 358 } 359 } 360 } 361 362 public synchronized Map <TriggerDescriptor,Trigger> getTriggers() { 363 return (Map )Descriptor.toMap(triggers); 364 } 365 366 374 public abstract boolean isFingerprintConfigured(); 375 376 380 public final List <AbstractProject> getDownstreamProjects() { 381 return Hudson.getInstance().getDependencyGraph().getDownstream(this); 382 } 383 384 public final List <AbstractProject> getUpstreamProjects() { 385 return Hudson.getInstance().getDependencyGraph().getUpstream(this); 386 } 387 388 396 public SortedMap <Integer , RangeSet> getRelationship(AbstractProject that) { 397 TreeMap <Integer ,RangeSet> r = new TreeMap <Integer ,RangeSet>(REVERSE_INTEGER_COMPARATOR); 398 399 checkAndRecord(that, r, this.getBuilds()); 400 402 return r; 403 } 404 405 410 private void checkAndRecord(AbstractProject that, TreeMap <Integer , RangeSet> r, Collection <R> builds) { 411 for (R build : builds) { 412 RangeSet rs = build.getDownstreamRelationship(that); 413 if(rs==null || rs.isEmpty()) 414 continue; 415 416 int n = build.getNumber(); 417 418 RangeSet value = r.get(n); 419 if(value==null) 420 r.put(n,rs); 421 else 422 value.add(rs); 423 } 424 } 425 426 430 protected abstract void buildDependencyGraph(DependencyGraph graph); 431 432 440 public void doBuild( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 441 BuildAuthorizationToken.startBuildIfAuthorized(authToken,this,req,rsp); 442 } 443 444 447 public void doCancelQueue( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException { 448 if(!Hudson.adminCheck(req,rsp)) 449 return; 450 451 Hudson.getInstance().getQueue().cancel(this); 452 rsp.forwardToPreviousPage(req); 453 } 454 455 public synchronized void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException , ServletException { 456 super.doConfigSubmit(req, rsp); 457 458 disabled = req.getParameter("disable")!=null; 459 460 jdk = req.getParameter("jdk"); 461 if(req.getParameter("hasCustomQuietPeriod")!=null) { 462 quietPeriod = Integer.parseInt(req.getParameter("quiet_period")); 463 } else { 464 quietPeriod = null; 465 } 466 467 if(req.getParameter("hasSlaveAffinity")!=null) { 468 canRoam = false; 469 assignedNode = req.getParameter("slave"); 470 if(assignedNode !=null) { 471 if(Hudson.getInstance().getSlave(assignedNode)==null) { 472 assignedNode = null; } 474 } 475 } else { 476 canRoam = true; 477 assignedNode = null; 478 } 479 480 authToken = BuildAuthorizationToken.create(req); 481 482 try { 483 setScm(SCMS.parseSCM(req)); 484 485 for (Trigger t : triggers) 486 t.stop(); 487 buildDescribable(req, Triggers.getApplicableTriggers(this), triggers, "trigger"); 488 for (Trigger t : triggers) 489 t.start(this,true); 490 } catch (FormException e) { 491 throw new ServletException (e); 492 } 493 } 494 495 protected final <T extends Describable<T>> void buildDescribable(StaplerRequest req, List <? extends Descriptor<T>> descriptors, List <T> result, String prefix) 496 throws FormException { 497 498 result.clear(); 499 for( int i=0; i< descriptors.size(); i++ ) { 500 if(req.getParameter(prefix +i)!=null) { 501 T instance = descriptors.get(i).newInstance(req); 502 result.add(instance); 503 } 504 } 505 } 506 507 510 public void doWs( StaplerRequest req, StaplerResponse rsp ) throws IOException , ServletException , InterruptedException { 511 FilePath ws = getWorkspace(); 512 if(!ws.exists()) { 513 rsp.forward(this,"noWorkspace",req); 515 } else { 516 new DirectoryBrowserSupport(this).serveFile(req, rsp, ws, "folder.gif", true); 517 } 518 } 519 520 523 public static AbstractProject findNearest(String name) { 524 List <AbstractProject> projects = Hudson.getInstance().getAllItems(AbstractProject.class); 525 String [] names = new String [projects.size()]; 526 for( int i=0; i<projects.size(); i++ ) 527 names[i] = projects.get(i).getName(); 528 529 String nearest = EditDistance.findNearest(name, names); 530 return (AbstractProject)Hudson.getInstance().getItem(nearest); 531 } 532 533 private static final Comparator <Integer > REVERSE_INTEGER_COMPARATOR = new Comparator <Integer >() { 534 public int compare(Integer o1, Integer o2) { 535 return o2-o1; 536 } 537 }; 538 } 539 | Popular Tags |