1 package hudson.maven; 2 3 import hudson.FilePath; 4 import hudson.Util; 5 import hudson.maven.agent.*; 6 import hudson.model.AbstractBuild; 7 import hudson.model.AbstractProject; 8 import hudson.model.BuildListener; 9 import hudson.model.DependencyGraph; 10 import hudson.model.Hudson; 11 import hudson.model.Result; 12 import hudson.model.Run; 13 import hudson.model.Slave; 14 import hudson.remoting.Callable; 15 import hudson.remoting.Channel; 16 import hudson.remoting.Launcher; 17 import hudson.remoting.Which; 18 import hudson.scm.ChangeLogSet; 19 import hudson.scm.ChangeLogSet.Entry; 20 import hudson.tasks.Maven.MavenInstallation; 21 import hudson.tasks.test.AbstractTestResultAction; 22 import hudson.util.ArgumentListBuilder; 23 import hudson.util.IOException2; 24 import org.codehaus.classworlds.NoSuchRealmException; 25 import org.apache.maven.lifecycle.LifecycleExecutorInterceptor; 26 27 import java.io.File ; 28 import java.io.FilenameFilter ; 29 import java.io.IOException ; 30 import java.io.Serializable ; 31 import java.lang.reflect.InvocationTargetException ; 32 import java.util.ArrayList ; 33 import java.util.Calendar ; 34 import java.util.List ; 35 import java.util.Set ; 36 37 42 public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> { 43 47 List <MavenReporter> projectActionReporters; 48 49 public MavenBuild(MavenModule job) throws IOException { 50 super(job); 51 } 52 53 public MavenBuild(MavenModule job, Calendar timestamp) { 54 super(job, timestamp); 55 } 56 57 public MavenBuild(MavenModule project, File buildDir) throws IOException { 58 super(project, buildDir); 59 } 60 61 68 public MavenModuleSetBuild getParentBuild() { 69 return getParent().getParent().getBuildByNumber(getNumber()); 70 } 71 72 @Override 73 public ChangeLogSet<? extends Entry> getChangeSet() { 74 return new FilteredChangeLogSet(this); 75 } 76 77 80 @Override 81 public boolean hasChangeSetComputed() { 82 return true; 83 } 84 85 @Override 86 public AbstractTestResultAction getTestResultAction() { 87 return getAction(AbstractTestResultAction.class); 88 } 89 90 public void registerAsProjectAction(MavenReporter reporter) { 91 if(projectActionReporters==null) 92 projectActionReporters = new ArrayList <MavenReporter>(); 93 projectActionReporters.add(reporter); 94 } 95 96 @Override 97 public void run() { 98 run(new RunnerImpl()); 99 getProject().updateTransientActions(); 100 } 101 102 105 private static final class Builder implements Callable<Result,IOException > { 106 private final BuildListener listener; 107 private final MavenBuildProxy buildProxy; 108 private final MavenReporter[] reporters; 109 private final List <String > goals; 110 111 public Builder(BuildListener listener,MavenBuildProxy buildProxy,MavenReporter[] reporters, List <String > goals) { 112 this.listener = listener; 113 this.buildProxy = buildProxy; 114 this.reporters = reporters; 115 this.goals = goals; 116 } 117 118 121 public Result call() throws IOException { 122 try { 123 PluginManagerInterceptor pmi = new PluginManagerInterceptor(buildProxy, reporters, listener); 124 hudson.maven.agent.PluginManagerInterceptor.setListener(pmi); 125 LifecycleExecutorInterceptor.setListener(pmi); 126 127 int r = Main.launch(goals.toArray(new String [goals.size()])); 128 return r==0 ? Result.SUCCESS : Result.FAILURE; 129 } catch (NoSuchMethodException e) { 130 throw new IOException2(e); 131 } catch (IllegalAccessException e) { 132 throw new IOException2(e); 133 } catch (NoSuchRealmException e) { 134 throw new IOException2(e); 135 } catch (InvocationTargetException e) { 136 throw new IOException2(e); 137 } catch (ClassNotFoundException e) { 138 throw new IOException2(e); 139 } 140 } 141 } 142 143 146 private class ProxyImpl implements MavenBuildProxy, Serializable { 147 public <V, T extends Throwable > V execute(BuildCallable<V, T> program) throws T, IOException , InterruptedException { 148 return program.call(MavenBuild.this); 149 } 150 151 public FilePath getRootDir() { 152 return new FilePath(MavenBuild.this.getRootDir()); 153 } 154 155 public FilePath getProjectRootDir() { 156 return new FilePath(MavenBuild.this.getParent().getRootDir()); 157 } 158 159 public FilePath getArtifactsDir() { 160 return new FilePath(MavenBuild.this.getArtifactsDir()); 161 } 162 163 public void setResult(Result result) { 164 MavenBuild.this.setResult(result); 165 } 166 167 public void registerAsProjectAction(MavenReporter reporter) { 168 MavenBuild.this.registerAsProjectAction(reporter); 169 } 170 171 private Object writeReplace() { 172 return Channel.current().export(MavenBuildProxy.class, new ProxyImpl()); 173 } 174 } 175 176 private static final class getJavaExe implements Callable<String ,IOException > { 177 public String call() throws IOException { 178 return new File (new File (System.getProperty("java.home")),"bin/java").getPath(); 179 } 180 } 181 182 private class RunnerImpl extends AbstractRunner { 183 protected Result doRun(BuildListener listener) throws Exception { 184 List <MavenReporter> reporters = new ArrayList <MavenReporter>(); 186 getProject().getReporters().addAllTo(reporters); 187 for (MavenReporterDescriptor d : MavenReporters.LIST) { 188 if(getProject().getReporters().contains(d)) 189 continue; MavenReporter auto = d.newAutoInstance(getProject()); 191 if(auto!=null) 192 reporters.add(auto); 193 } 194 195 ArgumentListBuilder args = buildMavenCmdLine(listener); 197 198 Channel channel = launcher.launchChannel(args.toCommandArray(), 199 listener.getLogger(), getProject().getModuleRoot()); 200 201 203 ArgumentListBuilder margs = new ArgumentListBuilder(); 204 margs.add("-N"); 205 margs.addTokenized(getProject().getGoals()); 206 207 try { 208 return channel.call(new Builder( 209 listener,new ProxyImpl(), 210 reporters.toArray(new MavenReporter[0]), margs.toList())); 211 } finally { 212 channel.close(); 213 } 214 } 215 216 private ArgumentListBuilder buildMavenCmdLine(BuildListener listener) throws IOException , InterruptedException { 218 MavenInstallation mvn = getParent().getParent().getMaven(); 219 if(mvn==null) { 220 listener.error("Maven version is not configured for this project. Can't determine which Maven to run"); 221 throw new RunnerAbortedException(); 222 } 223 224 File bootDir = new File (mvn.getHomeDir(), "core/boot"); 226 File [] classworlds = bootDir.listFiles(new FilenameFilter () { 227 public boolean accept(File dir, String name) { 228 return name.startsWith("classworlds") && name.endsWith(".jar"); 229 } 230 }); 231 if(classworlds==null || classworlds.length==0) { 232 listener.error("No classworlds*.jar found in "+bootDir+" -- Is this a valid maven2 directory?"); 233 throw new RunnerAbortedException(); 234 } 235 236 boolean isMaster = getCurrentNode()==Hudson.getInstance(); 237 FilePath slaveRoot=null; 238 if(!isMaster) 239 slaveRoot = ((Slave)getCurrentNode()).getFilePath(); 240 241 ArgumentListBuilder args = new ArgumentListBuilder(); 242 args.add(launcher.getChannel().call(new getJavaExe())); 243 244 246 args.add("-cp"); 247 args.add( 248 (isMaster?Which.jarFile(Main.class).getAbsolutePath():slaveRoot.child("maven-agent.jar").getRemote())+ 249 (launcher.isUnix()?":":";")+ 250 classworlds[0].getAbsolutePath()); 251 args.add(Main.class.getName()); 252 253 args.add(mvn.getMavenHome()); 255 256 args.add(Which.jarFile(Launcher.class).getPath()); 258 args.add(isMaster? 260 Which.jarFile(hudson.maven.agent.PluginManagerInterceptor.class).getAbsolutePath(): 261 slaveRoot.child("maven-interceptor.jar").getRemote()); 262 return args; 263 } 264 265 public void post(BuildListener listener) { 266 if(!getResult().isWorseThan(Result.UNSTABLE)) { 267 DependencyGraph graph = Hudson.getInstance().getDependencyGraph(); 269 for( AbstractProject<?,?> down : getParent().getDownstreamProjects()) { 270 if(graph.hasIndirectDependencies(getParent(),down)) 271 continue; 276 277 boolean trigger = true; 280 281 AbstractBuild<?,?> dlb = down.getLastBuild(); for (MavenModule up : Util.filter(down.getUpstreamProjects(),MavenModule.class)) { 283 MavenBuild ulb; 284 if(up==getProject()) { 285 if(getResult()==null || !getResult().isWorseThan(Result.UNSTABLE)) 288 ulb = MavenBuild.this; 289 else 290 ulb = up.getLastSuccessfulBuild(); 291 } else 292 ulb = up.getLastSuccessfulBuild(); 293 if(ulb==null) { 294 trigger = false; 297 break; 298 } 299 300 if(dlb==null) continue; 304 int n = dlb.getUpstreamRelationship(up); 305 if(n==-1) continue; 306 307 assert ulb.getNumber()>=n; 308 309 if(ulb.getNumber()==n) { 310 if(isUpstreamBuilding(graph,up)) { 314 trigger = false; 315 break; 316 } 317 } 318 } 319 320 if(trigger) { 321 listener.getLogger().println("Triggering a new build of "+down.getName()); 322 down.scheduleBuild(); 323 } 324 } 325 } 326 } 327 328 335 private boolean isUpstreamBuilding(DependencyGraph graph, AbstractProject project) { 336 Set<AbstractProject> tups = graph.getTransitiveUpstream(project); 337 tups.add(project); 338 for (AbstractProject tup : tups) { 339 if(tup.isBuilding() || tup.isInQueue()) 340 return true; 341 } 342 return false; 343 } 344 } 345 } 346 | Popular Tags |