Package org.apache.maven.continuum.scm.queue

Source Code of org.apache.maven.continuum.scm.queue.PrepareBuildProjectsTaskExecutor

package org.apache.maven.continuum.scm.queue;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import org.apache.continuum.dao.BuildDefinitionDao;
import org.apache.continuum.dao.BuildResultDao;
import org.apache.continuum.dao.ProjectDao;
import org.apache.continuum.dao.ProjectGroupDao;
import org.apache.continuum.dao.ProjectScmRootDao;
import org.apache.continuum.model.project.ProjectScmRoot;
import org.apache.continuum.taskqueue.PrepareBuildProjectsTask;
import org.apache.continuum.utils.ContinuumUtils;
import org.apache.continuum.utils.ProjectSorter;
import org.apache.continuum.utils.build.BuildTrigger;
import org.apache.maven.continuum.core.action.AbstractContinuumAction;
import org.apache.maven.continuum.core.action.CheckWorkingDirectoryAction;
import org.apache.maven.continuum.core.action.CheckoutProjectContinuumAction;
import org.apache.maven.continuum.core.action.UpdateWorkingDirectoryFromScmContinuumAction;
import org.apache.maven.continuum.model.project.BuildDefinition;
import org.apache.maven.continuum.model.project.BuildResult;
import org.apache.maven.continuum.model.project.Project;
import org.apache.maven.continuum.model.project.ProjectGroup;
import org.apache.maven.continuum.model.scm.ChangeSet;
import org.apache.maven.continuum.model.scm.ScmResult;
import org.apache.maven.continuum.notification.ContinuumNotificationDispatcher;
import org.apache.maven.continuum.project.ContinuumProjectState;
import org.apache.maven.continuum.store.ContinuumStoreException;
import org.apache.maven.continuum.utils.WorkingDirectoryService;
import org.codehaus.plexus.action.ActionManager;
import org.codehaus.plexus.action.ActionNotFoundException;
import org.codehaus.plexus.taskqueue.Task;
import org.codehaus.plexus.taskqueue.execution.TaskExecutionException;
import org.codehaus.plexus.taskqueue.execution.TaskExecutor;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* @author <a href="mailto:ctan@apache.org">Maria Catherine Tan</a>
* @version $Id: PrepareBuildProjectsTaskExecutor.java 1372260 2012-08-13 04:29:09Z brett $
* @plexus.component role="org.codehaus.plexus.taskqueue.execution.TaskExecutor"
* role-hint="prepare-build-project"
*/
public class PrepareBuildProjectsTaskExecutor
    implements TaskExecutor
{
    private static final Logger log = LoggerFactory.getLogger( PrepareBuildProjectsTaskExecutor.class );

    /**
     * @plexus.requirement
     */
    private ActionManager actionManager;

    /**
     * @plexus.requirement
     */
    private ProjectDao projectDao;

    /**
     * @plexus.requirement
     */
    private BuildDefinitionDao buildDefinitionDao;

    /**
     * @plexus.requirement
     */
    private ProjectScmRootDao projectScmRootDao;

    /**
     * @plexus.requirement
     */
    private BuildResultDao buildResultDao;

    /**
     * @plexus.requirement
     */
    private WorkingDirectoryService workingDirectoryService;

    /**
     * @plexus.requirement
     */
    private ContinuumNotificationDispatcher notifierDispatcher;

    /**
     * @plexus.requirement
     */
    private ProjectGroupDao projectGroupDao;

    public void executeTask( Task task )
        throws TaskExecutionException
    {
        PrepareBuildProjectsTask prepareTask = (PrepareBuildProjectsTask) task;

        Map<Integer, Integer> projectsBuildDefinitionsMap = prepareTask.getProjectsBuildDefinitionsMap();
        BuildTrigger buildTrigger = prepareTask.getBuildTrigger();
        Set<Integer> projectsId = projectsBuildDefinitionsMap.keySet();
        Map<String, Object> context = new HashMap<String, Object>();
        Map<Integer, ScmResult> scmResultMap = new HashMap<Integer, ScmResult>();
        List<Project> projectList = new ArrayList<Project>();
        int projectGroupId = 0;

        try
        {
            if ( !projectsId.isEmpty() )
            {
                int projectId = projectsId.iterator().next();
                Project project = projectDao.getProject( projectId );
                ProjectGroup projectGroup = project.getProjectGroup();
                projectGroupId = projectGroup.getId();

                List<Project> projects = projectDao.getProjectsWithDependenciesByGroupId( projectGroupId );
                projectList = ProjectSorter.getSortedProjects( projects, log );
            }

            Project rootProject = null;

            for ( Project project : projectList )
            {
                if ( rootProject == null )
                {
                    // first project is the root project.
                    rootProject = project;
                }

                int projectId = project.getId();
                int buildDefinitionId;

                if ( projectsBuildDefinitionsMap.get( projectId ) != null )
                {
                    buildDefinitionId = projectsBuildDefinitionsMap.get( projectId );

                    log.info( "Initializing prepare build" );
                    context = initializeContext( project, buildDefinitionId, prepareTask.getBuildTrigger() );

                    log.info( "Starting prepare build of project: " + AbstractContinuumAction.getProject(
                        context ).getName() );
                    startPrepareBuild( context );

                    if ( !checkProjectScmRoot( context ) )
                    {
                        break;
                    }

                    try
                    {
                        if ( AbstractContinuumAction.getBuildDefinition( context ).isBuildFresh() )
                        {
                            log.info( "Purging existing working copy" );
                            cleanWorkingDirectory( context );
                        }

                        // ----------------------------------------------------------------------
                        // TODO: Centralize the error handling from the SCM related actions.
                        // ContinuumScmResult should return a ContinuumScmResult from all
                        // methods, even in a case of failure.
                        // ----------------------------------------------------------------------
                        log.info( "Updating working dir" );
                        updateWorkingDirectory( context, rootProject );

                        log.info( "Merging SCM results" );
                        //CONTINUUM-1393
                        if ( !AbstractContinuumAction.getBuildDefinition( context ).isBuildFresh() )
                        {
                            mergeScmResults( context );
                        }
                    }
                    finally
                    {
                        log.info( "Ending prepare build of project: " + AbstractContinuumAction.getProject(
                            context ).getName() );
                        scmResultMap.put( AbstractContinuumAction.getProjectId( context ),
                                          AbstractContinuumAction.getScmResult( context, null ) );
                        endProjectPrepareBuild( context );
                    }
                }
            }
        }
        catch ( ContinuumStoreException e )
        {
            throw new TaskExecutionException( "Failed to prepare build project group: " + projectGroupId, e );
        }
        finally
        {
            log.info( "Ending prepare build" );
            endPrepareBuild( context );
        }

        if ( checkProjectScmRoot( context ) )
        {
            projectGroupId = AbstractContinuumAction.getProjectGroupId( context );
            buildProjects( projectGroupId, projectList, projectsBuildDefinitionsMap, buildTrigger, scmResultMap );
        }
    }

    private Map<String, Object> initializeContext( Project project, int buildDefinitionId, BuildTrigger buildTrigger )
        throws TaskExecutionException
    {
        Map<String, Object> context = new HashMap<String, Object>();

        try
        {
            ProjectGroup projectGroup = project.getProjectGroup();

            List<ProjectScmRoot> scmRoots = projectScmRootDao.getProjectScmRootByProjectGroup( projectGroup.getId() );
            String projectScmUrl = project.getScmUrl();
            String projectScmRootAddress = "";

            for ( ProjectScmRoot projectScmRoot : scmRoots )
            {
                projectScmRootAddress = projectScmRoot.getScmRootAddress();

                if ( projectScmUrl.startsWith( projectScmRoot.getScmRootAddress() ) )
                {
                    AbstractContinuumAction.setProjectScmRoot( context, projectScmRoot );
                    AbstractContinuumAction.setProjectScmRootUrl( context, projectScmRootAddress );
                    break;
                }
            }

            AbstractContinuumAction.setProjectGroupId( context, projectGroup.getId() );
            AbstractContinuumAction.setProjectId( context, project.getId() );
            AbstractContinuumAction.setProject( context, project );
            AbstractContinuumAction.setBuildTrigger( context, buildTrigger );

            AbstractContinuumAction.setBuildDefinitionId( context, buildDefinitionId );
            AbstractContinuumAction.setBuildDefinition( context, buildDefinitionDao.getBuildDefinition(
                buildDefinitionId ) );

            if ( project.isCheckedOutInSingleDirectory() )
            {
                List<Project> projectsInGroup = projectGroupDao.getProjectGroupWithProjects(
                    projectGroup.getId() ).getProjects();
                List<Project> projectsWithCommonScmRoot = new ArrayList<Project>();
                for ( Project projectInGroup : projectsInGroup )
                {
                    if ( projectInGroup.getScmUrl().startsWith( projectScmRootAddress ) )
                    {
                        projectsWithCommonScmRoot.add( projectInGroup );
                    }
                }
                AbstractContinuumAction.setListOfProjectsInGroupWithCommonScmRoot( context, projectsWithCommonScmRoot );
            }

            BuildResult oldBuildResult = buildResultDao.getLatestBuildResultForBuildDefinition( project.getId(),
                                                                                                buildDefinitionId );

            if ( oldBuildResult != null )
            {
                AbstractContinuumAction.setOldScmResult( context, getOldScmResults( project.getId(),
                                                                                    oldBuildResult.getBuildNumber(),
                                                                                    oldBuildResult.getEndTime() ) );
            }
            else
            {
                AbstractContinuumAction.setOldScmResult( context, null );
            }
        }
        catch ( ContinuumStoreException e )
        {
            throw new TaskExecutionException( "Error initializing pre-build context", e );
        }

        return context;
    }

    private void cleanWorkingDirectory( Map<String, Object> context )
        throws TaskExecutionException
    {
        performAction( "clean-working-directory", context );
    }

    private void updateWorkingDirectory( Map<String, Object> context, Project rootProject )
        throws TaskExecutionException
    {
        performAction( "check-working-directory", context );

        boolean workingDirectoryExists = CheckWorkingDirectoryAction.isWorkingDirectoryExists( context );

        ScmResult scmResult;

        if ( workingDirectoryExists )
        {
            performAction( "update-working-directory-from-scm", context );

            scmResult = UpdateWorkingDirectoryFromScmContinuumAction.getUpdateScmResult( context, null );
        }
        else
        {
            Project project = AbstractContinuumAction.getProject( context );

            AbstractContinuumAction.setWorkingDirectory( context, workingDirectoryService.getWorkingDirectory(
                project ).getAbsolutePath() );

            List<Project> projectsWithCommonScmRoot = AbstractContinuumAction.getListOfProjectsInGroupWithCommonScmRoot(
                context );
            String projectScmRootUrl = AbstractContinuumAction.getProjectScmRootUrl( context, project.getScmUrl() );
            String workingDir = null;

            if ( rootProject.getId() == project.getId() )
            {
                workingDir = workingDirectoryService.getWorkingDirectory( project, false ).getAbsolutePath();

                if ( project.isCheckedOutInSingleDirectory() )
                {
                    File parentDir = new File( workingDir );

                    while ( !isRootDirectory( parentDir.getAbsolutePath(), project ) )
                    {
                        parentDir = parentDir.getParentFile();
                    }

                    if ( !parentDir.exists() )
                    {
                        workingDir = parentDir.getAbsolutePath();
                    }
                }
            }

            if ( workingDir == null || new File( workingDir ).exists() )
            {
                workingDir = workingDirectoryService.getWorkingDirectory( project, projectScmRootUrl,
                                                                          projectsWithCommonScmRoot ).getAbsolutePath();
            }

            AbstractContinuumAction.setWorkingDirectory( context, workingDir );

            if ( rootProject.getId() != project.getId() || ( rootProject.getId() == project.getId() && !isRootDirectory(
                workingDir, rootProject ) ) )
            {
                AbstractContinuumAction.setRootDirectory( context, false );
            }

            performAction( "checkout-project", context );

            scmResult = CheckoutProjectContinuumAction.getCheckoutScmResult( context, null );
        }

        // [CONTINUUM-2207] when returned scmResult is null, this causes a problem when building the project
        if ( scmResult == null )
        {
            log.debug( "Returned ScmResult is null when updating the working directory" );
            scmResult = new ScmResult();
        }

        AbstractContinuumAction.setScmResult( context, scmResult );
    }

    private boolean checkProjectScmRoot( Map<String, Object> context )
        throws TaskExecutionException
    {
        ProjectScmRoot projectScmRoot = AbstractContinuumAction.getProjectScmRoot( context );

        // check state of scm root
        return projectScmRoot.getState() != ContinuumProjectState.ERROR;

    }

    private void startPrepareBuild( Map<String, Object> context )
        throws TaskExecutionException
    {
        ProjectScmRoot projectScmRoot = AbstractContinuumAction.getProjectScmRoot( context );
        if ( projectScmRoot.getState() != ContinuumProjectState.UPDATING )
        {
            try
            {
                projectScmRoot.setOldState( projectScmRoot.getState() );
                projectScmRoot.setState( ContinuumProjectState.UPDATING );
                projectScmRootDao.updateProjectScmRoot( projectScmRoot );
            }
            catch ( ContinuumStoreException e )
            {
                throw new TaskExecutionException( "Error persisting projectScmRoot", e );
            }
        }
    }

    private void endPrepareBuild( Map<String, Object> context )
        throws TaskExecutionException
    {
        ProjectScmRoot projectScmRoot = AbstractContinuumAction.getProjectScmRoot( context );

        if ( projectScmRoot.getState() != ContinuumProjectState.ERROR )
        {
            projectScmRoot.setState( ContinuumProjectState.UPDATED );
            projectScmRoot.setError( null );

            try
            {
                projectScmRootDao.updateProjectScmRoot( projectScmRoot );
            }
            catch ( ContinuumStoreException e )
            {
                throw new TaskExecutionException( "Error persisting projectScmRoot", e );
            }
        }

        notifierDispatcher.prepareBuildComplete( projectScmRoot );
    }

    /**
     * @param context
     * @throws TaskExecutionException
     */
    private void endProjectPrepareBuild( Map<String, Object> context )
        throws TaskExecutionException
    {
        ScmResult scmResult = AbstractContinuumAction.getScmResult( context, null );

        if ( scmResult == null || !scmResult.isSuccess() )
        {
            String error = convertScmResultToError( scmResult );

            updateProjectScmRoot( context, error );
        }
    }

    private ScmResult getOldScmResults( int projectId, long startId, long fromDate )
        throws ContinuumStoreException
    {
        List<BuildResult> results = buildResultDao.getBuildResultsForProjectFromId( projectId, startId );

        ScmResult res = new ScmResult();

        if ( results != null && results.size() > 0 )
        {
            for ( BuildResult result : results )
            {
                ScmResult scmResult = result.getScmResult();

                if ( scmResult != null )
                {
                    List<ChangeSet> changes = scmResult.getChanges();

                    if ( changes != null )
                    {
                        for ( ChangeSet changeSet : changes )
                        {
                            if ( changeSet.getDate() < fromDate )
                            {
                                continue;
                            }
                            if ( !res.getChanges().contains( changeSet ) )
                            {
                                res.addChange( changeSet );
                            }
                        }
                    }
                }
            }
        }

        return res;
    }

    /**
     * Merges scm results so we'll have all changes since last execution of current build definition
     *
     * @param context The build context
     */
    private void mergeScmResults( Map<String, Object> context )
    {
        ScmResult oldScmResult = AbstractContinuumAction.getOldScmResult( context );
        ScmResult newScmResult = AbstractContinuumAction.getScmResult( context, null );

        if ( oldScmResult != null )
        {
            if ( newScmResult == null )
            {
                AbstractContinuumAction.setScmResult( context, oldScmResult );
            }
            else
            {
                List<ChangeSet> oldChanges = oldScmResult.getChanges();

                List<ChangeSet> newChanges = newScmResult.getChanges();

                for ( ChangeSet change : newChanges )
                {
                    if ( !oldChanges.contains( change ) )
                    {
                        oldChanges.add( change );
                    }
                }

                newScmResult.setChanges( oldChanges );
            }
        }
    }

    private void performAction( String actionName, Map<String, Object> context )
        throws TaskExecutionException
    {
        TaskExecutionException exception;

        try
        {
            log.info( "Performing action " + actionName );
            actionManager.lookup( actionName ).execute( context );
            return;
        }
        catch ( ActionNotFoundException e )
        {
            exception = new TaskExecutionException( "Error looking up action '" + actionName + "'", e );
        }
        catch ( Exception e )
        {
            exception = new TaskExecutionException( "Error executing action '" + actionName + "'", e );
        }

        ScmResult result = new ScmResult();

        result.setSuccess( false );

        result.setException( ContinuumUtils.throwableToString( exception ) );

        AbstractContinuumAction.setScmResult( context, result );

        throw exception;
    }

    private String convertScmResultToError( ScmResult result )
    {
        String error = "";

        if ( result == null )
        {
            error = "Scm result is null.";
        }
        else
        {
            if ( result.getCommandLine() != null )
            {
                error = "Command line: " + StringUtils.clean( result.getCommandLine() ) +
                    System.getProperty( "line.separator" );
            }

            if ( result.getProviderMessage() != null )
            {
                error = "Provider message: " + StringUtils.clean( result.getProviderMessage() ) +
                    System.getProperty( "line.separator" );
            }

            if ( result.getCommandOutput() != null )
            {
                error += "Command output: " + System.getProperty( "line.separator" );
                error += "-------------------------------------------------------------------------------" +
                    System.getProperty( "line.separator" );
                error += StringUtils.clean( result.getCommandOutput() ) + System.getProperty( "line.separator" );
                error += "-------------------------------------------------------------------------------" +
                    System.getProperty( "line.separator" );
            }

            if ( result.getException() != null )
            {
                error += "Exception:" + System.getProperty( "line.separator" );
                error += result.getException();
            }
        }

        return error;
    }

    private void updateProjectScmRoot( Map<String, Object> context, String error )
        throws TaskExecutionException
    {
        ProjectScmRoot projectScmRoot = AbstractContinuumAction.getProjectScmRoot( context );

        try
        {
            projectScmRoot.setState( ContinuumProjectState.ERROR );
            projectScmRoot.setError( error );

            projectScmRootDao.updateProjectScmRoot( projectScmRoot );

            AbstractContinuumAction.setProjectScmRoot( context, projectScmRoot );
        }
        catch ( ContinuumStoreException e )
        {
            throw new TaskExecutionException( "Error storing project scm root", e );
        }
    }

    private void buildProjects( int projectGroupId, List<Project> projectList,
                                Map<Integer, Integer> projectsAndBuildDefinitionsMap, BuildTrigger buildTrigger,
                                Map<Integer, ScmResult> scmResultMap )
        throws TaskExecutionException
    {
        List<Project> projectsToBeBuilt = new ArrayList<Project>();
        Map<Integer, BuildDefinition> projectsBuildDefinitionsMap = new HashMap<Integer, BuildDefinition>();

        for ( Project project : projectList )
        {
            int buildDefinitionId;

            if ( projectsAndBuildDefinitionsMap.get( project.getId() ) != null )
            {
                buildDefinitionId = projectsAndBuildDefinitionsMap.get( project.getId() );

                try
                {
                    BuildDefinition buildDefinition = buildDefinitionDao.getBuildDefinition( buildDefinitionId );
                    projectsBuildDefinitionsMap.put( project.getId(), buildDefinition );
                    projectsToBeBuilt.add( project );
                }
                catch ( ContinuumStoreException e )
                {
                    log.error( "Error while creating build object", e );
                    throw new TaskExecutionException( "Error while creating build object", e );
                }
            }
        }

        try
        {
            Map<String, Object> context = new HashMap<String, Object>();
            AbstractContinuumAction.setListOfProjects( context, projectsToBeBuilt );
            AbstractContinuumAction.setProjectsBuildDefinitionsMap( context, projectsBuildDefinitionsMap );
            AbstractContinuumAction.setBuildTrigger( context, buildTrigger );
            AbstractContinuumAction.setScmResultMap( context, scmResultMap );
            AbstractContinuumAction.setProjectGroupId( context, projectGroupId );

            log.info( "Performing action create-build-project-task" );
            actionManager.lookup( "create-build-project-task" ).execute( context );
        }
        catch ( ActionNotFoundException e )
        {
            log.error( "Error looking up action 'build-project'" );
            throw new TaskExecutionException( "Error looking up action 'build-project'", e );
        }
        catch ( Exception e )
        {
            log.error( e.getMessage(), e );
            throw new TaskExecutionException( "Error executing action 'build-project'", e );
        }
    }

    private boolean isRootDirectory( String workingDir, Project rootProject )
    {
        return workingDir.endsWith( Integer.toString( rootProject.getId() ) + System.getProperty(
            "line.separator" ) ) || workingDir.endsWith( Integer.toString( rootProject.getId() ) );
    }
}
TOP

Related Classes of org.apache.maven.continuum.scm.queue.PrepareBuildProjectsTaskExecutor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.