org.phpmaven.phpnar.CompileMojo.java Source code

Java tutorial

Introduction

Here is the source code for org.phpmaven.phpnar.CompileMojo.java

Source

/**
 * 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.phpnar;

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

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugin.nar.NarProperties;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
import org.codehaus.plexus.util.cli.StreamConsumer;
import org.phpmaven.core.ExecutionUtils;

/**
 * A goal to compile the php extension
 * 
 * @goal compile
 * @author mepeisen
 */
public class CompileMojo extends AbstractNarMojo {

    /**
     * The extensions that should be activated or deactivated
     * @parameter
     */
    private List<Extension> extensions = new ArrayList<Extension>();

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        super.execute();

        for (AolItem item : this.aolItems) {
            item.check(getLog(), this.project);

            File targetFolder = new File(this.project.getBuild().getDirectory() + "/" + item.getAol());

            getLog().info("************");
            getLog().info("Starting build for " + item);
            getLog().info("");

            if ("Windows".equalsIgnoreCase(item.getEffectiveOs())) {
                getLog().debug("windows build");

                // windows build
                final File buildTargetDir = new File(targetFolder,
                        "phpdev/vc9/" + item.getArch() + "/php-" + this.project.getVersion());

                final File buildScript = this.generateWindowsBuildScript(item, targetFolder, buildTargetDir);
                try {
                    executeCommand(this.getLog(), "cmd /E:ON /V:ON /c \"" + buildScript.getAbsolutePath() + "\"",
                            targetFolder);
                } catch (CommandLineException ex) {
                    throw new MojoFailureException("Error during compile", ex);
                }
            } else {
                getLog().debug("*ix build (configure/make)");

                final File buildScript = this.generateIxBuildScript(item, targetFolder);

                try {
                    executeCommand(this.getLog(), "bash \"" + buildScript.getAbsolutePath() + "\"", targetFolder);
                } catch (CommandLineException ex) {
                    throw new MojoFailureException("Error during compile", ex);
                }
            }
        }
    }

    /**
     * Executes a command.
     * @param log the logger
     * @param command command line
     * @param workDir working directory
     * @throws CommandLineException throw on execution errors.
     */
    private static void executeCommand(final Log log, final String command, final File workDir)
            throws CommandLineException {
        final Commandline cli = new Commandline(command);
        if (log != null) {
            log.debug("Executing " + command);
        }

        if (workDir != null) {
            if (!workDir.exists()) {
                workDir.mkdirs();
            }
            cli.setWorkingDirectory(workDir);
        }
        final StreamConsumer systemOut = new StreamConsumer() {
            @Override
            public void consumeLine(String line) {
                log.info(line);
            }
        };
        final StreamConsumer systemErr = new StreamConsumer() {
            @Override
            public void consumeLine(String line) {
                log.warn(line);
            }
        };
        try {
            final int result = CommandLineUtils.executeCommandLine(cli, systemOut, systemErr);
            if (result != 0) {
                if (log != null) {
                    log.warn("Error invoking command. Return code " + result);
                }
                throw new CommandLineException("Error invoking command. Return code " + result);
            }
        } catch (CommandLineException ex) {
            if (log != null) {
                log.warn("Error invoking command");
            }
            throw ex;
        }
    }

    private File generateIxBuildScript(AolItem item, File targetFolder) throws MojoFailureException {
        final File buildScript = new File(targetFolder, "phpmaven.build.sh");
        if (buildScript.exists()) {
            buildScript.delete();
        }

        final File installFolder = new File(targetFolder, "phpmaven.install");

        String buildOs = null;

        try {
            ExecutionUtils.executeCommand(getLog(), "chmod +x " + new File(targetFolder, "config.guess")
                    .getAbsolutePath().replace("\\", "\\\\").replace(" ", "\\ "));
            ExecutionUtils.executeCommand(getLog(), "chmod +x " + new File(targetFolder, "buildconf")
                    .getAbsolutePath().replace("\\", "\\\\").replace(" ", "\\ "));
            for (final File file : new File(targetFolder, "build").listFiles()) {
                if (file.isFile()) {
                    ExecutionUtils.executeCommand(getLog(),
                            "chmod +x " + file.getAbsolutePath().replace("\\", "\\\\").replace(" ", "\\ "));
                }
            }
            buildOs = ExecutionUtils
                    .executeCommand(getLog(),
                            "\"" + new File(targetFolder, "config.guess").getAbsolutePath() + "\"", targetFolder)
                    .trim();
            ExecutionUtils.executeCommand(getLog(),
                    "\"" + new File(targetFolder, "buildconf").getAbsolutePath() + "\" --force", targetFolder);
        } catch (CommandLineException ex) {
            throw new MojoFailureException("Failed to find the host os (config.guess)", ex);
        }

        final String propertyKey = item.getAol().getKey();
        final NarProperties props = NarProperties.getInstance(this.project);
        final String hostOs = props.getProperty(propertyKey + ".HostOs");
        final String archFlags = props.getProperty(propertyKey + ".ArchFlags");
        String extraLdFlags = "";
        if (archFlags.contains("-m32")) {
            extraLdFlags = " -L/usr/lib32";
        } else if (archFlags.contains("-m64")) {
            extraLdFlags = " -L/usr/lib64";
        }

        final StringBuffer content = new StringBuffer();
        // TODO macosx cross compile
        content.append("./configure " + "--prefix=\"" + installFolder.getAbsolutePath() + "\" "
                + this.createConfigureArgs(item, "--enable-cli --enable-embed=shared") + " " + "--build=" + buildOs
                + " " + "--host=" + hostOs + " " + "CFLAGS='" + archFlags + " "
                + props.getProperty(propertyKey + ".c.options").replace("-Wall", "") + "' " + "CXXFLAGS='"
                + archFlags + " " + props.getProperty(propertyKey + ".cpp.options").replace("-Wall", "") + "' "
                + "LDFLAGS='" + archFlags + extraLdFlags + "'\n");
        content.append("make\n");
        content.append("make install\n");

        try {
            final FileOutputStream fos = new FileOutputStream(buildScript);
            fos.write(content.toString().getBytes());
            fos.flush();
            fos.close();
        } catch (IOException ex) {
            throw new MojoFailureException("Error writing build script", ex);
        }

        try {
            ExecutionUtils.executeCommand(getLog(),
                    "chmod +x " + buildScript.getAbsolutePath().replace("\\", "\\\\").replace(" ", "\\ "));
        } catch (CommandLineException ex) {
            throw new MojoFailureException("Error while chmod build script", ex);
        }

        return buildScript;
    }

    private File generateWindowsBuildScript(AolItem item, File targetFolder, File buildTargetDir)
            throws MojoFailureException {
        final File buildScript = new File(buildTargetDir, "phpmaven.build.cmd");
        if (buildScript.exists()) {
            buildScript.delete();
        }

        final StringBuffer content = new StringBuffer();
        content.append("@echo off\n");

        final String effectiveArch = item.getArch().equals("amd64") ? "x64" : item.getArch();

        content.append("call setenv /" + effectiveArch + " /win7 /release\n");
        content.append("cd \"" + targetFolder.getAbsolutePath() + "\"\n");
        content.append("call bin\\phpsdk_setvars.bat\n");
        content.append("cd \"" + buildTargetDir.getAbsolutePath() + "\"\n");
        content.append("call buildconf\n");
        content.append(
                "perl -p -i.bak -e 's/PHP_OBJECT_OUT_DIR = \\'x64..\\'/PHP_OBJECT_OUT_DIR = \\'\\'/' configure.js\n");
        content.append("call configure " + this.createConfigureArgs(item, "--enable-cli") + "\n");

        // fix makefile for 64 builds. nmake snap wont work because of subdirectory in BUILD_DIR
        // see https://bugs.php.net/bug.php?id=62945
        if ("amd64".equals(item.getArch()) || "ia64".equals(item.getArch())) {
            content.append("perl -p -i.bak -e 's/BUILD_DIR=(.*)/BUILD_DIR=Release_TS/' Makefile\n");
            content.append("mkdir Release_TS\n");
            content.append("mkdir Release_TS\\devel\n");
            content.append("copy x64\\Release_TS\\devel Release_TS\\devel /Y\n");
        }

        content.append("call nmake\n");
        content.append("call nmake snap\n");

        try {
            final FileOutputStream fos = new FileOutputStream(buildScript);
            fos.write(content.toString().getBytes());
            fos.flush();
            fos.close();
        } catch (IOException ex) {
            throw new MojoFailureException("Error writing build script", ex);
        }

        return buildScript;
    }

    /**
     * Creates the configure line
     * @param item
     * @param defaultValue
     * @return command line arguments to be used
     * @throws MojoFailureException 
     */
    private String createConfigureArgs(AolItem item, String defaultValue) throws MojoFailureException {
        String configure = item.getConfigureArgs() != null ? item.getConfigureArgs()
                : (this.getConfigureArgs() == null ? "" : this.getConfigureArgs());
        if (configure.length() == 0) {
            configure = defaultValue;
        }
        for (final Extension ext : this.extensions) {
            if (ext.getName() == null || ext.getName().length() == 0) {
                throw new MojoFailureException("Extension name not set");
            }
            if (ext.getEnable() == null && ext.getWith() == null) {
                throw new MojoFailureException("Either set enable or with flag for extension " + ext.getName());
            }

            if (configure.length() > 0) {
                configure = configure + " ";
            }
            if (ext.getEnable() != null) {
                if (ext.getEnable()) {
                    configure = configure + "--enable-" + ext.getName();
                } else {
                    configure = configure + "--disable-" + ext.getName();
                    continue; // skip shared keyword
                }
            }
            if (ext.getWith() != null) {
                if (ext.getWith()) {
                    configure = configure + "--with-" + ext.getName();
                } else {
                    configure = configure + "--without-" + ext.getName();
                    continue; // skip shared keyword
                }
            }

            if (ext.getShared() != null) {
                if (ext.getShared()) {
                    configure = configure + "=shared";
                } else {
                    configure = configure + "=static";
                }
            }
        }
        return configure;
    }

}