1 package hudson.triggers; 2 3 import antlr.ANTLRException; 4 import hudson.Util; 5 import hudson.model.AbstractBuild; 6 import hudson.model.AbstractProject; 7 import hudson.model.Action; 8 import hudson.model.Item; 9 import hudson.model.Project; 10 import hudson.model.SCMedItem; 11 import hudson.model.TaskListener; 12 import hudson.util.StreamTaskListener; 13 import org.kohsuke.stapler.StaplerRequest; 14 15 import java.io.File ; 16 import java.io.FileOutputStream ; 17 import java.io.IOException ; 18 import java.io.OutputStream ; 19 import java.io.PrintStream ; 20 import java.util.Date ; 21 import java.util.concurrent.CancellationException ; 22 import java.util.concurrent.ExecutionException ; 23 import java.util.concurrent.ExecutorService ; 24 import java.util.concurrent.Executors ; 25 import java.util.concurrent.Future ; 26 import java.util.logging.Level ; 27 import java.util.logging.Logger ; 28 29 34 public class SCMTrigger extends Trigger<SCMedItem> { 35 44 private transient boolean pollingScheduled; 45 46 49 private transient boolean abortNow; 50 51 57 private transient Future <?> polling; 58 59 public SCMTrigger(String cronTabSpec) throws ANTLRException { 60 super(cronTabSpec); 61 } 62 63 protected synchronized void run() { 64 if(pollingScheduled) 65 return; pollingScheduled = true; 67 68 startPolling(); 70 } 71 72 public Action getProjectAction() { 73 return new SCMAction(); 74 } 75 76 79 public synchronized void abort() throws InterruptedException { 80 if(polling!=null && !polling.isDone()) { 81 System.out.println("killing polling"); 82 83 abortNow = true; 84 polling.cancel(true); 85 try { 86 polling.get(); 87 } catch (ExecutionException e) { 88 LOGGER.log(Level.WARNING, "Failed to poll",e); 89 } catch (CancellationException e) { 90 } 92 abortNow = false; 93 } 94 } 95 96 99 public synchronized void startPolling() { 100 AbstractBuild b = job.asProject().getLastBuild(); 101 102 if(b!=null && b.isBuilding()) 103 return; 105 if(polling!=null && !polling.isDone()) 106 return; 108 if(!pollingScheduled) 109 return; 111 pollingScheduled = false; 112 polling = DESCRIPTOR.getExecutor().submit(new Runner()); 113 } 114 115 118 public File getLogFile() { 119 return new File (job.getRootDir(),"scm-polling.log"); 120 } 121 122 public TriggerDescriptor getDescriptor() { 123 return DESCRIPTOR; 124 } 125 126 public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); 127 128 public static final class DescriptorImpl extends TriggerDescriptor { 129 132 transient volatile ExecutorService executor; 133 134 138 private int maximumThreads; 139 140 DescriptorImpl() { 141 super(SCMTrigger.class); 142 load(); 143 update(); 145 } 146 147 public boolean isApplicable(Item item) { 148 return item instanceof SCMedItem; 149 } 150 151 public ExecutorService getExecutor() { 152 return executor; 153 } 154 155 public String getDisplayName() { 156 return "Poll SCM"; 157 } 158 159 public String getHelpFile() { 160 return "/help/project-config/poll-scm.html"; 161 } 162 163 public Trigger newInstance(StaplerRequest req) throws FormException { 164 try { 165 return new SCMTrigger(req.getParameter("scmpoll_spec")); 166 } catch (ANTLRException e) { 167 throw new FormException(e.toString(),e,"scmpoll_spec"); 168 } 169 } 170 171 177 public int getPollingThreadCount() { 178 return maximumThreads; 179 } 180 181 public void setPollingThreadCount(int n) { 182 if(n<0) n=0; 184 if(n>100) n=100; 185 186 maximumThreads = n; 187 save(); 188 } 189 190 193 synchronized void update() { 194 ExecutorService newExec = maximumThreads==0 ? Executors.newCachedThreadPool() : Executors.newFixedThreadPool(maximumThreads); 196 ExecutorService old = executor; 197 executor = newExec; 198 if(old!=null) 199 old.shutdown(); 200 } 201 202 public boolean configure(StaplerRequest req) throws FormException { 203 String t = req.getParameter("poll_scm_threads"); 204 if(t==null || t.length()==0) 205 setPollingThreadCount(0); 206 else 207 setPollingThreadCount(Integer.parseInt(t)); 208 return super.configure(req); 209 } 210 } 211 212 215 public final class SCMAction implements Action { 216 public AbstractProject<?,?> getOwner() { 217 return job.asProject(); 218 } 219 220 public String getIconFileName() { 221 return "clipboard.gif"; 222 } 223 224 public String getDisplayName() { 225 return job.getScm().getDescriptor().getDisplayName()+" Polling Log"; 226 } 227 228 public String getUrlName() { 229 return "scmPollLog"; 230 } 231 232 public String getLog() throws IOException { 233 return Util.loadFile(getLogFile()); 234 } 235 } 236 237 private static final Logger LOGGER = Logger.getLogger(SCMTrigger.class.getName()); 238 239 242 private class Runner implements Runnable { 243 private boolean runPolling() { 244 try { 245 OutputStream fos = new FileOutputStream (getLogFile()); 248 TaskListener listener = new StreamTaskListener(fos); 249 250 try { 251 LOGGER.info("Polling SCM changes of "+ job.getName()); 252 253 PrintStream logger = listener.getLogger(); 254 long start = System.currentTimeMillis(); 255 logger.println("Started on "+new Date ().toLocaleString()); 256 boolean result = job.pollSCMChanges(listener); 257 logger.println("Done. Took "+ Util.getTimeSpanString(System.currentTimeMillis()-start)); 258 if(result) 259 logger.println("Changes found"); 260 else 261 logger.println("No changes"); 262 return result; 263 } finally { 264 fos.close(); 265 } 266 } catch (IOException e) { 267 LOGGER.log(Level.SEVERE,"Failed to record SCM polling",e); 268 return false; 269 } 270 } 271 272 public void run() { 273 if(runPolling()) { 274 LOGGER.info("SCM changes detected in "+ job.getName()); 275 job.scheduleBuild(); 276 } 277 278 synchronized(SCMTrigger.this) { 279 if(abortNow) 280 return; 282 if(pollingScheduled) { 283 polling = DESCRIPTOR.getExecutor().submit(new Runner()); 285 } 286 pollingScheduled = false; 287 } 288 } 289 } 290 } 291 | Popular Tags |