1 package org.apache.continuum.buildagent.build.execution;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Properties;
29
30 import org.apache.continuum.buildagent.configuration.BuildAgentConfigurationService;
31 import org.apache.continuum.buildagent.installation.BuildAgentInstallationService;
32 import org.apache.continuum.buildagent.manager.BuildAgentManager;
33 import org.apache.continuum.buildagent.utils.ContinuumBuildAgentUtil;
34 import org.apache.continuum.utils.shell.ExecutionResult;
35 import org.apache.continuum.utils.shell.ShellCommandHelper;
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.continuum.model.project.BuildDefinition;
38 import org.apache.maven.continuum.model.project.Project;
39 import org.apache.maven.continuum.model.project.ProjectDependency;
40 import org.apache.maven.continuum.model.project.ProjectDeveloper;
41 import org.apache.maven.continuum.model.project.ProjectNotifier;
42 import org.apache.maven.continuum.project.ContinuumProjectState;
43 import org.apache.maven.project.MavenProject;
44 import org.codehaus.plexus.commandline.ExecutableResolver;
45 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
46 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
47 import org.codehaus.plexus.util.StringUtils;
48 import org.codehaus.plexus.util.cli.CommandLineException;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public abstract class AbstractBuildExecutor
53 implements ContinuumAgentBuildExecutor, Initializable
54 {
55 protected static final Logger log = LoggerFactory.getLogger( AbstractBuildExecutor.class );
56
57
58
59
60 private ShellCommandHelper shellCommandHelper;
61
62
63
64
65 private ExecutableResolver executableResolver;
66
67
68
69
70 private BuildAgentConfigurationService buildAgentConfigurationService;
71
72
73
74
75 private BuildAgentInstallationService buildAgentInstallationService;
76
77
78
79
80 private String defaultExecutable;
81
82
83
84
85 private BuildAgentManager buildAgentManager;
86
87
88
89
90
91 private final String id;
92
93 private boolean resolveExecutable;
94
95
96
97
98
99 protected AbstractBuildExecutor( String id, boolean resolveExecutable )
100 {
101 this.id = id;
102
103 this.resolveExecutable = resolveExecutable;
104 }
105
106 public void setShellCommandHelper( ShellCommandHelper shellCommandHelper )
107 {
108 this.shellCommandHelper = shellCommandHelper;
109 }
110
111 public ShellCommandHelper getShellCommandHelper()
112 {
113 return shellCommandHelper;
114 }
115
116 public void setDefaultExecutable( String defaultExecutable )
117 {
118 this.defaultExecutable = defaultExecutable;
119 }
120
121 public BuildAgentConfigurationService getBuildAgentConfigurationService()
122 {
123 return buildAgentConfigurationService;
124 }
125
126 public void setBuildAgentConfigurationService( BuildAgentConfigurationService buildAgentConfigurationService )
127 {
128 this.buildAgentConfigurationService = buildAgentConfigurationService;
129 }
130
131 public BuildAgentInstallationService getBuildAgentInstallationService()
132 {
133 return buildAgentInstallationService;
134 }
135
136 public void setBuildAgentInstallationService( BuildAgentInstallationService buildAgentInstallationService )
137 {
138 this.buildAgentInstallationService = buildAgentInstallationService;
139 }
140
141 public BuildAgentManager getBuildAgentManager()
142 {
143 return buildAgentManager;
144 }
145
146 public void setBuildAgentManager( BuildAgentManager buildAgentManager )
147 {
148 this.buildAgentManager = buildAgentManager;
149 }
150
151
152
153
154
155 public String getDefaultExecutable()
156 {
157 return defaultExecutable;
158 }
159
160 public void initialize()
161 throws InitializationException
162 {
163 List path = executableResolver.getDefaultPath();
164
165 if ( resolveExecutable )
166 {
167 if ( StringUtils.isEmpty( defaultExecutable ) )
168 {
169 log.warn( "The default executable for build executor '" + id + "' is not set. " +
170 "This will cause a problem unless the project has a executable configured." );
171 }
172 else
173 {
174 File resolvedExecutable = executableResolver.findExecutable( defaultExecutable, path );
175
176 if ( resolvedExecutable == null )
177 {
178 log.warn(
179 "Could not find the executable '" + defaultExecutable + "' in the " + "path '" + path + "'." );
180 }
181 else
182 {
183 log.info( "Resolved the executable '" + defaultExecutable + "' to " + "'" +
184 resolvedExecutable.getAbsolutePath() + "'." );
185 }
186 }
187 }
188 }
189
190
191
192
193
194
195
196
197
198
199
200 protected String findExecutable( String executable, String defaultExecutable, boolean resolveExecutable,
201 File workingDirectory )
202 {
203
204
205
206
207
208
209 String actualExecutable;
210
211 if ( !resolveExecutable )
212 {
213 actualExecutable = new File( workingDirectory, executable ).getAbsolutePath();
214 }
215 else
216 {
217 List<String> path = executableResolver.getDefaultPath();
218
219 if ( StringUtils.isEmpty( executable ) )
220 {
221 executable = defaultExecutable;
222 }
223
224 File e = executableResolver.findExecutable( executable, path );
225
226 if ( e == null )
227 {
228 log.debug( "Could not find the executable '" + executable + "' in this path: " );
229
230 for ( String element : path )
231 {
232 log.debug( element );
233 }
234
235 actualExecutable = defaultExecutable;
236 }
237 else
238 {
239 actualExecutable = e.getAbsolutePath();
240 }
241 }
242
243
244 File actualExecutableFile = new File( actualExecutable );
245
246 if ( !actualExecutableFile.exists() )
247 {
248 actualExecutable = executable;
249 }
250
251 return actualExecutable;
252 }
253
254 protected ContinuumAgentBuildExecutionResult executeShellCommand( Project project, String executable,
255 String arguments, File output,
256 Map<String, String> environments )
257 throws ContinuumAgentBuildExecutorException, ContinuumAgentBuildCancelledException
258 {
259
260 File workingDirectory = getWorkingDirectory( project.getId() );
261
262 String actualExecutable = findExecutable( executable, defaultExecutable, resolveExecutable, workingDirectory );
263
264
265
266
267
268 try
269 {
270 ExecutionResult result =
271 getShellCommandHelper().executeShellCommand( workingDirectory, actualExecutable, arguments, output,
272 project.getId(), environments );
273
274 log.info( "Exit code: " + result.getExitCode() );
275
276 return new ContinuumAgentBuildExecutionResult( output, result.getExitCode() );
277 }
278 catch ( CommandLineException e )
279 {
280 if ( e.getCause() instanceof InterruptedException )
281 {
282 throw new ContinuumAgentBuildCancelledException( "The build was cancelled", e );
283 }
284 else
285 {
286 throw new ContinuumAgentBuildExecutorException(
287 "Error while executing shell command. The most common error is that '" + executable + "' " +
288 "is not in your path.", e );
289 }
290 }
291 catch ( Exception e )
292 {
293 throw new ContinuumAgentBuildExecutorException(
294 "Error while executing shell command. " + "The most common error is that '" + executable + "' " +
295 "is not in your path.", e );
296 }
297 }
298
299 protected Properties getContinuumSystemProperties( Project project )
300 {
301 Properties properties = new Properties();
302 properties.setProperty( "continuum.project.group.name", project.getProjectGroup().getName() );
303 properties.setProperty( "continuum.project.lastBuild.state", String.valueOf( project.getOldState() ) );
304 properties.setProperty( "continuum.project.lastBuild.number", String.valueOf( project.getBuildNumber() ) );
305 properties.setProperty( "continuum.project.nextBuild.number", String.valueOf( project.getBuildNumber() + 1 ) );
306 properties.setProperty( "continuum.project.id", String.valueOf( project.getId() ) );
307 properties.setProperty( "continuum.project.name", project.getName() );
308 properties.setProperty( "continuum.project.version", project.getVersion() );
309 return properties;
310 }
311
312 protected String getBuildFileForProject( BuildDefinition buildDefinition )
313 {
314 return StringUtils.clean( buildDefinition.getBuildFile() );
315 }
316
317 protected void updateProject( Project project )
318 throws ContinuumAgentBuildExecutorException
319 {
320 Map<String, Object> projectMap = new HashMap<String, Object>();
321
322 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_ID, project.getId() );
323 if ( StringUtils.isNotEmpty( project.getVersion() ) )
324 {
325 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, project.getVersion() );
326 }
327 else
328 {
329 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, "" );
330 }
331 if ( StringUtils.isNotEmpty( project.getArtifactId() ) )
332 {
333 projectMap.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, project.getArtifactId() );
334 }
335 else
336 {
337 projectMap.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, "" );
338 }
339 if ( StringUtils.isNotEmpty( project.getGroupId() ) )
340 {
341 projectMap.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, project.getGroupId() );
342 }
343 else
344 {
345 projectMap.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, "" );
346 }
347 if ( StringUtils.isNotEmpty( project.getName() ) )
348 {
349 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_NAME, project.getName() );
350 }
351 else
352 {
353 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_NAME, "" );
354 }
355 if ( StringUtils.isNotEmpty( project.getDescription() ) )
356 {
357 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_DESCRIPTION, project.getDescription() );
358 }
359 else
360 {
361 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_DESCRIPTION, "" );
362 }
363 if ( StringUtils.isNotEmpty( project.getScmUrl() ) )
364 {
365 projectMap.put( ContinuumBuildAgentUtil.KEY_SCM_URL, project.getScmUrl() );
366 }
367 else
368 {
369 projectMap.put( ContinuumBuildAgentUtil.KEY_SCM_URL, "" );
370 }
371 if ( StringUtils.isNotEmpty( project.getScmTag() ) )
372 {
373 projectMap.put( ContinuumBuildAgentUtil.KEY_SCM_TAG, project.getScmTag() );
374 }
375 else
376 {
377 projectMap.put( ContinuumBuildAgentUtil.KEY_SCM_TAG, "" );
378 }
379 if ( StringUtils.isNotEmpty( project.getUrl() ) )
380 {
381 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_URL, project.getUrl() );
382 }
383 else
384 {
385 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_URL, "" );
386 }
387 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_PARENT, getProjectParent( project.getParent() ) );
388 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPERS,
389 getProjectDevelopers( project.getDevelopers() ) );
390 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEPENDENCIES,
391 getProjectDependencies( project.getDependencies() ) );
392 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_NOTIFIERS, getProjectNotifiers( project.getNotifiers() ) );
393
394 try
395 {
396 buildAgentManager.updateProject( projectMap );
397 }
398 catch ( Exception e )
399 {
400 throw new ContinuumAgentBuildExecutorException( "Failed to update project", e );
401 }
402 }
403
404 protected List<Map<String, String>> getProjectDevelopers( List<ProjectDeveloper> developers )
405 {
406 List<Map<String, String>> pDevelopers = new ArrayList<Map<String, String>>();
407
408 if ( developers != null )
409 {
410 for ( ProjectDeveloper developer : developers )
411 {
412 Map<String, String> map = new HashMap<String, String>();
413 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_NAME, developer.getName() );
414 if ( StringUtils.isNotEmpty( developer.getEmail() ) )
415 {
416 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_EMAIL, developer.getEmail() );
417 }
418 else
419 {
420 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_EMAIL, "" );
421 }
422 if ( StringUtils.isNotEmpty( developer.getScmId() ) )
423 {
424 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_SCMID, developer.getScmId() );
425 }
426 else
427 {
428 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_SCMID, "" );
429 }
430
431 pDevelopers.add( map );
432 }
433 }
434 return pDevelopers;
435 }
436
437 protected Map<String, Object> getProjectParent( ProjectDependency parent )
438 {
439 Map<String, Object> map = new HashMap<String, Object>();
440
441 if ( parent != null )
442 {
443 if ( StringUtils.isNotEmpty( parent.getGroupId() ) )
444 {
445 map.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, parent.getGroupId() );
446 }
447 else
448 {
449 map.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, "" );
450 }
451 if ( StringUtils.isNotEmpty( parent.getArtifactId() ) )
452 {
453 map.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, parent.getArtifactId() );
454 }
455 else
456 {
457 map.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, "" );
458 }
459 if ( StringUtils.isNotEmpty( parent.getVersion() ) )
460 {
461 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, parent.getVersion() );
462 }
463 else
464 {
465 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, "" );
466 }
467 }
468 return map;
469 }
470
471 protected List<Map<String, Object>> getProjectDependencies( List<ProjectDependency> dependencies )
472 {
473 List<Map<String, Object>> pDependencies = new ArrayList<Map<String, Object>>();
474
475 if ( dependencies != null )
476 {
477 for ( ProjectDependency dependency : dependencies )
478 {
479 Map<String, Object> map = new HashMap<String, Object>();
480 map.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, dependency.getGroupId() );
481 map.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, dependency.getArtifactId() );
482 if ( StringUtils.isNotBlank( dependency.getVersion() ) )
483 {
484 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, dependency.getVersion() );
485 }
486 else
487 {
488 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, "" );
489 }
490
491 pDependencies.add( map );
492 }
493 }
494 return pDependencies;
495 }
496
497 protected List<Map<String, Object>> getProjectNotifiers( List<ProjectNotifier> notifiers )
498 {
499 List<Map<String, Object>> pNotifiers = new ArrayList<Map<String, Object>>();
500
501 if ( notifiers != null )
502 {
503 for ( ProjectNotifier notifier : notifiers )
504 {
505 Map<String, Object> map = new HashMap<String, Object>();
506
507 if ( notifier.getConfiguration() != null )
508 {
509 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_CONFIGURATION, notifier.getConfiguration() );
510 }
511 else
512 {
513 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_CONFIGURATION, "" );
514 }
515 if ( StringUtils.isNotBlank( notifier.getType() ) )
516 {
517 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_TYPE, notifier.getType() );
518 }
519 else
520 {
521 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_TYPE, "" );
522 }
523 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_FROM, notifier.getFrom() );
524 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_RECIPIENT_TYPE, notifier.getRecipientType() );
525 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_ENABLED, notifier.isEnabled() );
526 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_ERROR, notifier.isSendOnError() );
527 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_SUCCESS, notifier.isSendOnSuccess() );
528 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_FAILURE, notifier.isSendOnFailure() );
529 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_SCMFAILURE, notifier.isSendOnScmFailure() );
530 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_WARNING, notifier.isSendOnWarning() );
531 pNotifiers.add(map);
532 }
533 }
534 return pNotifiers;
535 }
536
537 public boolean isBuilding( Project project )
538 {
539 return project.getState() == ContinuumProjectState.BUILDING ||
540 getShellCommandHelper().isRunning( project.getId() );
541 }
542
543 public void killProcess( Project project )
544 {
545 getShellCommandHelper().killProcess( project.getId() );
546 }
547
548 public List<Artifact> getDeployableArtifacts( Project project, File workingDirectory,
549 BuildDefinition buildDefinition )
550 throws ContinuumAgentBuildExecutorException
551 {
552
553 return Collections.EMPTY_LIST;
554 }
555
556 public MavenProject getMavenProject( File workingDirectory, BuildDefinition buildDefinition )
557 throws ContinuumAgentBuildExecutorException
558 {
559 return null;
560 }
561
562 public File getWorkingDirectory( int projectId )
563 {
564 return getBuildAgentConfigurationService().getWorkingDirectory( projectId );
565 }
566
567 public boolean isResolveExecutable()
568 {
569 return resolveExecutable;
570 }
571
572 public void setResolveExecutable( boolean resolveExecutable )
573 {
574 this.resolveExecutable = resolveExecutable;
575 }
576
577 public void setExecutableResolver( ExecutableResolver executableResolver )
578 {
579 this.executableResolver = executableResolver;
580 }
581
582 public ExecutableResolver getExecutableResolver()
583 {
584 return executableResolver;
585 }
586 }