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 org.apache.continuum.buildagent.configuration.BuildAgentConfigurationService;
23 import org.apache.continuum.buildagent.installation.BuildAgentInstallationService;
24 import org.apache.continuum.buildagent.manager.BuildAgentManager;
25 import org.apache.continuum.buildagent.utils.ContinuumBuildAgentUtil;
26 import org.apache.continuum.utils.shell.ExecutionResult;
27 import org.apache.continuum.utils.shell.ShellCommandHelper;
28 import org.apache.maven.artifact.Artifact;
29 import org.apache.maven.continuum.model.project.BuildDefinition;
30 import org.apache.maven.continuum.model.project.Project;
31 import org.apache.maven.continuum.model.project.ProjectDependency;
32 import org.apache.maven.continuum.model.project.ProjectDeveloper;
33 import org.apache.maven.continuum.model.project.ProjectNotifier;
34 import org.apache.maven.continuum.project.ContinuumProjectState;
35 import org.apache.maven.project.MavenProject;
36 import org.codehaus.plexus.commandline.ExecutableResolver;
37 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
38 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
39 import org.codehaus.plexus.util.StringUtils;
40 import org.codehaus.plexus.util.cli.CommandLineException;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 import java.io.File;
45 import java.util.ArrayList;
46 import java.util.Collections;
47 import java.util.HashMap;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.Properties;
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 = getShellCommandHelper().executeShellCommand( workingDirectory, actualExecutable,
271 arguments, output, project.getId(),
272 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, getProjectDevelopers(
389 project.getDevelopers() ) );
390 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEPENDENCIES, getProjectDependencies(
391 project.getDependencies() ) );
392 projectMap.put( ContinuumBuildAgentUtil.KEY_PROJECT_NOTIFIERS, getProjectNotifiers( project.getNotifiers() ) );
393
394 try
395 {
396 log.debug( "Update project {}" + project.getId() );
397 buildAgentManager.updateProject( projectMap );
398 }
399 catch ( Exception e )
400 {
401 throw new ContinuumAgentBuildExecutorException( "Failed to update project", e );
402 }
403 }
404
405 protected List<Map<String, String>> getProjectDevelopers( List<ProjectDeveloper> developers )
406 {
407 List<Map<String, String>> pDevelopers = new ArrayList<Map<String, String>>();
408
409 if ( developers != null )
410 {
411 for ( ProjectDeveloper developer : developers )
412 {
413 Map<String, String> map = new HashMap<String, String>();
414 if ( StringUtils.isNotEmpty( developer.getName() ) )
415 {
416 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_NAME, developer.getName() );
417 }
418 else
419 {
420 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_NAME, "" );
421 }
422 if ( StringUtils.isNotEmpty( developer.getEmail() ) )
423 {
424 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_EMAIL, developer.getEmail() );
425 }
426 else
427 {
428 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_EMAIL, "" );
429 }
430 if ( StringUtils.isNotEmpty( developer.getScmId() ) )
431 {
432 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_SCMID, developer.getScmId() );
433 }
434 else
435 {
436 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_DEVELOPER_SCMID, "" );
437 }
438
439 pDevelopers.add( map );
440 }
441 }
442 return pDevelopers;
443 }
444
445 protected Map<String, Object> getProjectParent( ProjectDependency parent )
446 {
447 Map<String, Object> map = new HashMap<String, Object>();
448
449 if ( parent != null )
450 {
451 if ( StringUtils.isNotEmpty( parent.getGroupId() ) )
452 {
453 map.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, parent.getGroupId() );
454 }
455 else
456 {
457 map.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, "" );
458 }
459 if ( StringUtils.isNotEmpty( parent.getArtifactId() ) )
460 {
461 map.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, parent.getArtifactId() );
462 }
463 else
464 {
465 map.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, "" );
466 }
467 if ( StringUtils.isNotEmpty( parent.getVersion() ) )
468 {
469 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, parent.getVersion() );
470 }
471 else
472 {
473 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, "" );
474 }
475 }
476 return map;
477 }
478
479 protected List<Map<String, Object>> getProjectDependencies( List<ProjectDependency> dependencies )
480 {
481 List<Map<String, Object>> pDependencies = new ArrayList<Map<String, Object>>();
482
483 if ( dependencies != null )
484 {
485 for ( ProjectDependency dependency : dependencies )
486 {
487 Map<String, Object> map = new HashMap<String, Object>();
488 if ( StringUtils.isNotEmpty( dependency.getGroupId() ) )
489 {
490 map.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, dependency.getGroupId() );
491 }
492 else
493 {
494 map.put( ContinuumBuildAgentUtil.KEY_GROUP_ID, "" );
495 }
496 if ( StringUtils.isNotEmpty( dependency.getArtifactId() ) )
497 {
498 map.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, dependency.getArtifactId() );
499 }
500 else
501 {
502 map.put( ContinuumBuildAgentUtil.KEY_ARTIFACT_ID, "" );
503 }
504 if ( StringUtils.isNotEmpty( dependency.getVersion() ) )
505 {
506 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, dependency.getVersion() );
507 }
508 else
509 {
510 map.put( ContinuumBuildAgentUtil.KEY_PROJECT_VERSION, "" );
511 }
512
513 pDependencies.add( map );
514 }
515 }
516 return pDependencies;
517 }
518
519 protected List<Map<String, Object>> getProjectNotifiers( List<ProjectNotifier> notifiers )
520 {
521 List<Map<String, Object>> pNotifiers = new ArrayList<Map<String, Object>>();
522
523 if ( notifiers != null )
524 {
525 for ( ProjectNotifier notifier : notifiers )
526 {
527 Map<String, Object> map = new HashMap<String, Object>();
528
529 if ( notifier.getConfiguration() != null )
530 {
531 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_CONFIGURATION, notifier.getConfiguration() );
532 }
533 else
534 {
535 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_CONFIGURATION, "" );
536 }
537 if ( StringUtils.isNotBlank( notifier.getType() ) )
538 {
539 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_TYPE, notifier.getType() );
540 }
541 else
542 {
543 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_TYPE, "" );
544 }
545 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_FROM, notifier.getFrom() );
546 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_RECIPIENT_TYPE, notifier.getRecipientType() );
547 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_ENABLED, notifier.isEnabled() );
548 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_ERROR, notifier.isSendOnError() );
549 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_SUCCESS, notifier.isSendOnSuccess() );
550 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_FAILURE, notifier.isSendOnFailure() );
551 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_SCMFAILURE, notifier.isSendOnScmFailure() );
552 map.put( ContinuumBuildAgentUtil.KEY_NOTIFIER_SEND_ON_WARNING, notifier.isSendOnWarning() );
553 pNotifiers.add( map );
554 }
555 }
556 return pNotifiers;
557 }
558
559 public boolean isBuilding( Project project )
560 {
561 return project.getState() == ContinuumProjectState.BUILDING || getShellCommandHelper().isRunning(
562 project.getId() );
563 }
564
565 public void killProcess( Project project )
566 {
567 getShellCommandHelper().killProcess( project.getId() );
568 }
569
570 public List<Artifact> getDeployableArtifacts( Project project, File workingDirectory,
571 BuildDefinition buildDefinition )
572 throws ContinuumAgentBuildExecutorException
573 {
574
575 return Collections.EMPTY_LIST;
576 }
577
578 public MavenProject getMavenProject( File workingDirectory, BuildDefinition buildDefinition )
579 throws ContinuumAgentBuildExecutorException
580 {
581 return null;
582 }
583
584 public File getWorkingDirectory( int projectId )
585 {
586 return getBuildAgentConfigurationService().getWorkingDirectory( projectId );
587 }
588
589 public boolean isResolveExecutable()
590 {
591 return resolveExecutable;
592 }
593
594 public void setResolveExecutable( boolean resolveExecutable )
595 {
596 this.resolveExecutable = resolveExecutable;
597 }
598
599 public void setExecutableResolver( ExecutableResolver executableResolver )
600 {
601 this.executableResolver = executableResolver;
602 }
603
604 public ExecutableResolver getExecutableResolver()
605 {
606 return executableResolver;
607 }
608 }