org.phpmaven.project.impl.PhpProject.java Source code

Java tutorial

Introduction

Here is the source code for org.phpmaven.project.impl.PhpProject.java

Source

/**
 * Copyright 2010-2012 by PHP-maven.org
 * 
 * Licensed 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.
 */

package org.phpmaven.project.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
import org.apache.maven.project.ProjectBuildingException;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.repository.RepositorySystem;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfigurationException;
import org.phpmaven.core.ConfigurationParameter;
import org.phpmaven.core.IComponentFactory;
import org.phpmaven.dependency.IAction;
import org.phpmaven.dependency.IAction.ActionType;
import org.phpmaven.dependency.IActionExtract;
import org.phpmaven.dependency.IActionExtractAndInclude;
import org.phpmaven.dependency.IDependency;
import org.phpmaven.dependency.IDependencyConfiguration;
import org.phpmaven.phpexec.library.IPhpExecutable;
import org.phpmaven.phpexec.library.PhpCoreException;
import org.phpmaven.phpexec.library.PhpException;
import org.phpmaven.project.IPhpProject;
import org.phpmaven.project.IProjectPhpExecution;
import org.phpmaven.statedb.IStateDatabase;

/**
 * The php project implementation.
 * 
 * @author Martin Eisengardt <Martin.Eisengardt@googlemail.com>
 * @since 2.0.3
 */
@Component(role = IPhpProject.class, instantiationStrategy = "per-lookup")
public class PhpProject implements IPhpProject {

    /**
     * 
     */
    private static final String DEPSTATEKEY = "DependencyState";

    /**
     * 
     */
    private static final String ARTIFACTID = "maven-php-project";

    /**
     * 
     */
    private static final String GROUPID = "org.phpmaven";

    /**
     * the component factory
     */
    @Requirement
    private IComponentFactory factory;

    /**
     * The dependency configuration
     */
    @Requirement
    private IDependencyConfiguration depConfig;

    /**
     * The maven session
     */
    @ConfigurationParameter(name = "session", expression = "${session}")
    private MavenSession session;

    /**
     * The state database
     */
    @Requirement
    private IStateDatabase stateDatabase;

    /**
     * The maven project builder.
     */
    @Requirement
    private ProjectBuilder mavenProjectBuilder;

    /**
     * the repository system.
     */
    @Requirement
    private RepositorySystem reposSystem;

    @Override
    public void prepareDependencies(final Log log, File targetDir, String sourceScope)
            throws MojoExecutionException, PhpException {
        DependencyState depState = this.stateDatabase.get(GROUPID, ARTIFACTID, DEPSTATEKEY, DependencyState.class);
        if (depState == null) {
            depState = new DependencyState();
        }
        if (!depState.containsKey(sourceScope)
                || !depState.get(sourceScope).getDefaultTargetDir().equals(targetDir)) {
            final DependencyInformation info = new DependencyInformation();
            depState.put(sourceScope, info);
            info.setDefaultTargetDir(targetDir);
        }
        final DependencyInformation info = depState.get(sourceScope);

        final BootstrapInfo bootstrapInfo = new BootstrapInfo();

        try {
            final MavenProject project = this.session.getCurrentProject();
            final Set<Artifact> deps = project.getArtifacts();
            for (final Artifact dep : deps) {
                if (!sourceScope.equals(dep.getScope())) {
                    continue;
                }

                final List<String> packedElements = new ArrayList<String>();
                packedElements.add(dep.getFile().getAbsolutePath());
                for (final IAction action : DependencyHelper.getDependencyActions(dep, depConfig, reposSystem,
                        session, mavenProjectBuilder, factory)) {
                    switch (action.getType()) {
                    case ACTION_BOOTSTRAP:
                        performBootstrap(log, info, dep, bootstrapInfo);
                        break;
                    case ACTION_CLASSIC:
                        performClassic(log, targetDir, dep, packedElements, info);
                        break;
                    case ACTION_PEAR:
                        performPearInstall(log, dep, info);
                        break;
                    case ACTION_IGNORE:
                        // do nothing, isClassic should be false so that it is ignored
                        log.info(dep.getFile().getAbsolutePath() + " will be ignored");
                        break;
                    case ACTION_INCLUDE:
                        log.info(dep.getFile().getAbsolutePath() + " will be added on include path");
                        break;
                    case ACTION_EXTRACT:
                        performExtraction(log, dep, packedElements, action, info);
                        break;
                    case ACTION_EXTRACT_INCLUDE:
                        performExtractAndInclude(log, dep, packedElements, action, info);
                        break;
                    }
                }
            }
        } catch (IOException ex) {
            throw new MojoExecutionException("Failed preparing dependencies", ex);
        }

        if (!bootstrapInfo.isEmpty()) {
            // invoke the bootstrap
            invokeBootstrap(log, bootstrapInfo, targetDir, sourceScope, depConfig.getBootstrapFile());
        }

        this.stateDatabase.set(GROUPID, ARTIFACTID, DEPSTATEKEY, depState);
    }

    /**
     * @param bootstrapInfo
     * @param targetDir
     * @param sourceScope
     * @param bootstrapFile
     */
    private void invokeBootstrap(Log log, BootstrapInfo bootstrapInfo, File targetDir, String sourceScope,
            File bootstrapFile) throws PhpException {
        try {
            final IProjectPhpExecution config = this.factory.lookup(IProjectPhpExecution.class,
                    IComponentFactory.EMPTY_CONFIG, this.session);
            final IPhpExecutable exec = config.getExecutionConfiguration(null, this.session.getCurrentProject())
                    .getPhpExecutable();
            final StringBuffer script = new StringBuffer();
            script.append("$mavenDependencies = array(\n");
            for (final BootstrapFileInfo fileInfo : bootstrapInfo) {
                script.append("    array(\n");
                script.append("        'groupId' => '").append(fileInfo.getGroupId()).append("',\n");
                script.append("        'artifactId' => '").append(fileInfo.getArtifactId()).append("',\n");
                script.append("        'version' => '").append(fileInfo.getVersion()).append("',\n");
                script.append("        'pharFile' => '")
                        .append(fileInfo.getPharFile().getAbsolutePath().replace("\\", "\\\\").replace("'", "\\'"))
                        .append("',\n");
                script.append("        'isNew' => ").append(fileInfo.isNew() ? "true" : "false").append(",\n");
                script.append("        'isChanged' => ").append(fileInfo.isChanged() ? "true" : "false")
                        .append("\n");
                script.append("    ),\n");
            }
            script.append("    'scope' => '").append(sourceScope).append("',\n");
            script.append("    'targetDir' => '")
                    .append(targetDir.getAbsolutePath().replace("\\", "\\\\").replace("'", "\\'")).append("'\n");
            script.append(");\n");
            script.append("require '")
                    .append(bootstrapFile.getAbsolutePath().replace("\\", "\\\\").replace("'", "\\'"))
                    .append("';\n");
            exec.executeCode("", script.toString());
        } catch (ComponentLookupException ex) {
            throw new PhpCoreException("Unable to execute bootstrap script", ex);
        } catch (PlexusConfigurationException ex) {
            throw new PhpCoreException("Unable to execute bootstrap script", ex);
        }
    }

    /**
     * @param info
     * @param dep
     */
    private void performBootstrap(Log log, final DependencyInformation info, final Artifact dep,
            BootstrapInfo bootstrapInfo) {
        final String depKey = getDepKey(dep);
        log.debug("Dependency " + depKey + " will be passed to bootstrap.");
        final BootstrapFileInfo fileInfo = new BootstrapFileInfo();
        fileInfo.setGroupId(dep.getGroupId());
        fileInfo.setArtifactId(dep.getArtifactId());
        fileInfo.setVersion(dep.getVersion());
        fileInfo.setPharFile(dep.getFile());
        DependencyArtifact artifact = info.get(depKey);
        if (artifact == null || !artifact.getActionStatement().equals("bootstrap")) {
            fileInfo.setNew(true);
            artifact = new DependencyArtifact();
            artifact.setDepKey(depKey);
            artifact.setActionStatement("bootstrap");
            artifact.setFileTimestamp(dep.getFile().lastModified());
            artifact.setReposFile(dep.getFile());
        } else if (artifact.getFileTimestamp() != dep.getFile().lastModified()
                || !artifact.getReposFile().equals(dep.getFile())) {
            fileInfo.setChanged(true);
            artifact.setFileTimestamp(dep.getFile().lastModified());
            artifact.setReposFile(dep.getFile());
        }
        bootstrapInfo.add(fileInfo);
    }

    /**
     * @param log
     * @param targetDir
     * @param dep
     * @param packedElements
     * @param info 
     * @throws IOException
     */
    private void performClassic(final Log log, File targetDir, final Artifact dep,
            final List<String> packedElements, DependencyInformation info) throws IOException {
        try {
            final String depKey = getDepKey(dep);
            if (this.getProjectFromArtifact(dep).getFile() != null) {
                // Reference to a local project; should only happen in IDEs or multi-project-poms
                log.debug("Dependency " + depKey + " resolved to a local project. skipping.");
                // the maven-php-project plugin will fix it by adding the include paths
            } else {
                final DependencyArtifact depArtifact = new DependencyArtifact();
                depArtifact.setDepKey(depKey);
                depArtifact.setActionStatement("classic");
                depArtifact.setFileTimestamp(dep.getFile().lastModified());
                depArtifact.setReposFile(dep.getFile());
                if (info.containsKey(depKey) && info.get(depKey).equals(depArtifact)) {
                    // check info for changes on that dependency
                    log.info("Dependency " + depKey + " is up to date. skipping...");
                } else {
                    log.info("Extracting " + dep.getFile().getAbsolutePath() + " to target directory");
                    FileHelper.unzipElements(log, targetDir, packedElements, factory, session);
                    info.put(depKey, depArtifact);
                }
            }
        } catch (ProjectBuildingException ex) {
            throw new IOException("Problems creating maven project from dependency", ex);
        }
    }

    /**
     * @param log
     * @param dep
     * @param packedElements
     * @param action
     * @param info 
     * @throws IOException
     * @throws PhpCoreException
     */
    private void performExtractAndInclude(final Log log, final Artifact dep, final List<String> packedElements,
            final IAction action, DependencyInformation info) throws IOException, PhpCoreException {

        final String depKey = getDepKey(dep);

        try {
            if (this.getProjectFromArtifact(dep).getFile() != null) {
                // Reference to a local project; should only happen in IDEs or multi-project-poms
                // TODO add support
                throw new PhpCoreException(
                        "extract action on local project " + depKey + " currently not supported");
            }
        } catch (ProjectBuildingException ex) {
            throw new IOException("Problems creating maven project from dependency", ex);
        }

        final DependencyArtifact depArtifact = new DependencyArtifact();
        depArtifact.setDepKey(depKey);
        depArtifact.setActionStatement("extractAndInclude:" + ((IActionExtractAndInclude) action).getPharPath()
                + ":" + ((IActionExtractAndInclude) action).getTargetPath());
        depArtifact.setFileTimestamp(dep.getFile().lastModified());
        depArtifact.setReposFile(dep.getFile());
        if (info.containsKey(depKey) && info.get(depKey).equals(depArtifact)) {
            // check info for changes on that dependency
            log.info("Dependency " + depKey + " is up to date. skipping...");
            return;
        }

        log.info(dep.getFile().getAbsolutePath() + " will be extracted to "
                + ((IActionExtractAndInclude) action).getTargetPath() + " and added on " + "include path");

        if (((IActionExtractAndInclude) action).getPharPath() == null
                || ((IActionExtractAndInclude) action).getPharPath().equals("/")) {
            FileHelper.unzipElements(log, new File(((IActionExtractAndInclude) action).getTargetPath()),
                    packedElements, factory, session);
        } else {
            // TODO add support
            throw new PhpCoreException("paths inside phar currently not supported");
        }
    }

    /**
     * @param log
     * @param dep
     * @param packedElements
     * @param action
     * @param info 
     * @throws IOException
     * @throws PhpCoreException
     */
    private void performExtraction(final Log log, final Artifact dep, final List<String> packedElements,
            final IAction action, DependencyInformation info) throws IOException, PhpCoreException {
        final String depKey = getDepKey(dep);
        try {
            if (this.getProjectFromArtifact(dep).getFile() != null) {
                // Reference to a local project; should only happen in IDEs or multi-project-poms
                // TODO add support
                throw new PhpCoreException(
                        "extract action on local project " + depKey + " currently not supported");
            }
        } catch (ProjectBuildingException ex) {
            throw new IOException("Problems creating maven project from dependency", ex);
        }

        final DependencyArtifact depArtifact = new DependencyArtifact();
        depArtifact.setDepKey(depKey);
        depArtifact.setActionStatement("extract:" + ((IActionExtract) action).getPharPath() + ":"
                + ((IActionExtract) action).getTargetPath());
        depArtifact.setFileTimestamp(dep.getFile().lastModified());
        depArtifact.setReposFile(dep.getFile());
        if (info.containsKey(depKey) && info.get(depKey).equals(depArtifact)) {
            // check info for changes on that dependency
            log.info("Dependency " + depKey + " is up to date. skipping...");
            return;
        }

        log.info(dep.getFile().getAbsolutePath() + " will be extracted to "
                + ((IActionExtract) action).getTargetPath());

        if (((IActionExtract) action).getPharPath() == null
                || ((IActionExtract) action).getPharPath().equals("/")) {
            FileHelper.unzipElements(log, new File(((IActionExtract) action).getTargetPath()), packedElements,
                    factory, session);
        } else {
            // TODO add support
            throw new PhpCoreException("paths inside phar currently not supported");
        }
    }

    /**
     * @param log
     * @param dep
     * @param info 
     * @throws PhpCoreException
     */
    private void performPearInstall(final Log log, final Artifact dep, DependencyInformation info)
            throws PhpCoreException {
        log.info(dep.getFile().getAbsolutePath() + " will be installed through pear");
        // TODO add support
        throw new PhpCoreException("pear installed currently not supported");
    }

    /**
     * Returns the maven project from given artifact.
     * @param a artifact
     * @return maven project
     * @throws ProjectBuildingException thrown if there are problems creating the project
     */
    protected MavenProject getProjectFromArtifact(final Artifact a) throws ProjectBuildingException {
        final ProjectBuildingRequest request = session.getProjectBuildingRequest();
        request.setLocalRepository(session.getLocalRepository());
        request.setRemoteRepositories(this.session.getCurrentProject().getRemoteArtifactRepositories());
        request.setProcessPlugins(false);
        return this.mavenProjectBuilder.build(a, request).getProject();
    }

    private String getDepKey(Artifact dep) {
        return dep.getGroupId() + ":" + dep.getArtifactId() + ":" + dep.getVersion() + ":" + dep.getClassifier();
    }

    @Override
    public void validateDependencies() throws MojoExecutionException {
        // check if we have a dependency that is not added to dependency section
        final MavenProject project = this.session.getCurrentProject();
        final Set<Artifact> deps = project.getArtifacts();
        for (final IDependency depCfg : depConfig.getDependencies()) {
            for (final IAction action : depCfg.getActions()) {
                if (action.getType() == ActionType.ACTION_BOOTSTRAP
                        && (depConfig.getBootstrapFile() == null || !depConfig.getBootstrapFile().exists())) {
                    throw new MojoExecutionException("There are bootstrap actions but bootstrap file '"
                            + depConfig.getBootstrapFile() + "' does not exist or was not set.");
                }
            }
            boolean found = false;
            for (final Artifact dep : deps) {
                if (depCfg.getGroupId().equals(dep.getGroupId())
                        && depCfg.getArtifactId().equals(dep.getArtifactId())) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                throw new MojoExecutionException("Dependency " + depCfg.getGroupId() + ":" + depCfg.getArtifactId()
                        + " has a dependency configuration but is not added to dependency section.");
            }
        }
    }

}