com.mcleodmoores.mvn.natives.PackageMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.mcleodmoores.mvn.natives.PackageMojo.java

Source

/*
 * Maven tools for native builds
 *
 * Copyright 2014 by Andrew Ian William Griffin <griffin@beerdragon.co.uk>.
 * Released under the GNU General Public License.
 */

package com.mcleodmoores.mvn.natives;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;

import com.google.common.io.PatternFilenameFilter;
import com.mcleodmoores.misc.IOCallback;
import com.mcleodmoores.misc.InputStreamOpener;
import com.mcleodmoores.misc.OutputStreamOpener;
import com.mcleodmoores.misc.IOCallback.IOExceptionHandler;
import com.mcleodmoores.mvn.natives.defaults.Defaults;

/**
 * Implementation of the {@code package} goal.
 */
public class PackageMojo extends AbstractMojo {

    private InputStreamOpener _inputStreams = new InputStreamOpener();

    private OutputStreamOpener _outputStreams = new OutputStreamOpener();

    private boolean _skip;

    private String _defaults;

    private Source[] _sources;

    private HeaderFile[] _headerFiles;

    private StaticLib[] _staticLibs;

    private DynamicLib[] _dynamicLibs;

    private Executable[] _executables;

    /* package */InputStreamOpener getInputStreams() {
        return _inputStreams;
    }

    /* package */void setInputStreams(final InputStreamOpener inputStreams) {
        _inputStreams = Objects.requireNonNull(inputStreams);
    }

    /* package */OutputStreamOpener getOutputStreams() {
        return _outputStreams;
    }

    /* package */void setOutputStreams(final OutputStreamOpener outputStreams) {
        _outputStreams = Objects.requireNonNull(outputStreams);
    }

    public boolean isSkip() {
        return _skip;
    }

    public void setSkip(final boolean skip) {
        _skip = skip;
    }

    public String getDefaults() {
        return _defaults;
    }

    public void setDefaults(final String defaults) {
        _defaults = defaults;
    }

    public Source[] getSources() {
        return ArrayUtils.clone(_sources);
    }

    public void setSources(final Source[] sources) {
        _sources = ArrayUtils.clone(sources);
    }

    public HeaderFile[] getHeaderFiles() {
        return ArrayUtils.clone(_headerFiles);
    }

    public void setHeaderFiles(final HeaderFile[] headerFiles) {
        _headerFiles = ArrayUtils.clone(headerFiles);
    }

    public StaticLib[] getStaticLibs() {
        return ArrayUtils.clone(_staticLibs);
    }

    public void setStaticLibs(final StaticLib[] staticLibs) {
        _staticLibs = ArrayUtils.clone(staticLibs);
    }

    public DynamicLib[] getDynamicLibs() {
        return ArrayUtils.clone(_dynamicLibs);
    }

    public void setDynamicLibs(final DynamicLib[] dynamicLibs) {
        _dynamicLibs = ArrayUtils.clone(dynamicLibs);
    }

    public Executable[] getExecutables() {
        return ArrayUtils.clone(_executables);
    }

    public void setExecutables(final Executable[] executables) {
        _executables = ArrayUtils.clone(executables);
    }

    /* package */void applyDefaults() {
        final Defaults defaults = Defaults.get(getDefaults());
        defaults.applyTo(getSources());
        if (getHeaderFiles() != null) {
            defaults.applyTo(getHeaderFiles());
        } else {
            setHeaderFiles(defaults.createDefaultHeaderFiles());
        }
        if (getDynamicLibs() != null) {
            defaults.applyTo(getDynamicLibs());
        } else {
            setDynamicLibs(defaults.createDefaultDynamicLibs());
        }
        if (getStaticLibs() != null) {
            defaults.applyTo(getStaticLibs());
        } else {
            setStaticLibs(defaults.createDefaultStaticLibs());
        }
        if (getExecutables() != null) {
            defaults.applyTo(getExecutables());
        } else {
            setExecutables(defaults.createDefaultExecutables());
        }
    }

    private static class SourceGatherer extends SourceVisitor {

        private final Map<Source, String> _found;

        private final String _arch;

        private final String _path;

        public SourceGatherer() {
            _found = new HashMap<Source, String>();
            _arch = null;
            _path = null;
        }

        private SourceGatherer(final SourceGatherer parent, final ArchSource inherit) {
            _found = parent._found;
            _arch = parent.getArch(inherit);
            _path = parent.getPath(inherit);
        }

        private String getPath(final Source source) {
            return ObjectUtils.defaultIfNull(source.getPath(), _path);
        }

        private String getArch(final ArchSource source) {
            return ObjectUtils.defaultIfNull(source.getArch(), _arch);
        }

        private String getArchLabel(final ArchSource source) {
            return ObjectUtils.defaultIfNull(getArch(source), "");
        }

        private String getArchSuffix(final ArchSource source) {
            final String arch = getArchLabel(source);
            if (arch.length() > 0) {
                return "-" + arch;
            } else {
                return arch;
            }
        }

        private void storePath(final Source source, String path) {
            if (path.length() > 0)
                path = path + File.separator;
            if (source.getDest() != null) {
                path = path + source.getDest() + File.separator;
            }
            _found.put(source, path);
        }

        @Override
        protected void visitSource(final Source source) {
            source.setPath(ObjectUtils.defaultIfNull(source.getPath(), _path));
            storePath(source, "");
        }

        @Override
        protected void visitArchSource(final ArchSource source) {
            source.setArch(ObjectUtils.defaultIfNull(source.getArch(), _arch));
            super.visitArchSource(source);
            storePath(source, getArchLabel(source));
        }

        @Override
        protected void visitDynamicLib(final DynamicLib library) {
            final SourceVisitor nested = new SourceGatherer(this, library);
            nested.applyTo(library.getHeaders());
            nested.applyTo(library.getImplibs());
            super.visitDynamicLib(library);
            storePath(library, "bin" + getArchSuffix(library));
        }

        @Override
        protected void visitExecutable(final Executable executable) {
            final SourceVisitor nested = new SourceGatherer(this, executable);
            nested.applyTo(executable.getHeaders());
            nested.applyTo(executable.getLibraries());
            super.visitExecutable(executable);
            storePath(executable, "bin" + getArchSuffix(executable));
        }

        @Override
        protected void visitStaticLib(final StaticLib library) {
            final SourceVisitor nested = new SourceGatherer(this, library);
            nested.applyTo(library.getHeaders());
            super.visitStaticLib(library);
            storePath(library, "lib" + getArchSuffix(library));
        }

        @Override
        protected void visitHeaderFile(final HeaderFile header) {
            super.visitHeaderFile(header);
            storePath(header, "include");
        }

    }

    /* package */Map<Source, String> gatherSources() {
        final SourceGatherer visitor = new SourceGatherer();
        visitor.applyTo(getSources());
        visitor.applyTo(getHeaderFiles());
        visitor.applyTo(getDynamicLibs());
        visitor.applyTo(getStaticLibs());
        visitor.applyTo(getExecutables());
        return visitor._found;
    }

    /* package */static String regex(final String pattern) {
        if ((pattern == null) || (pattern.length() == 0))
            return "^.*$";
        final StringBuilder sb = new StringBuilder();
        sb.append('^');
        for (int i = 0; i < pattern.length(); i++) {
            final char c = pattern.charAt(i);
            switch (c) {
            case '.':
                sb.append('\\').append('.');
                break;
            case '\\':
                sb.append('\\').append('\\');
                break;
            case '?':
                sb.append('.');
                break;
            case '*':
                sb.append('.').append('*');
                break;
            default:
                sb.append(c);
                break;
            }
        }
        sb.append('$');
        return sb.toString();
    }

    // Mojo

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        if (isSkip()) {
            getLog().debug("Skipping step");
            return;
        }
        applyDefaults();
        final MavenProject project = (MavenProject) getPluginContext().get("project");
        final File targetDir = new File(project.getBuild().getDirectory());
        targetDir.mkdirs();
        final File targetFile = new File(targetDir, project.getArtifactId() + ".zip");
        getLog().debug("Writing to " + targetFile);
        final OutputStream output;
        try {
            output = getOutputStreams().open(targetFile);
        } catch (final IOException e) {
            throw new MojoFailureException("Can't write to " + targetFile);
        }
        final IOExceptionHandler errorLog = new MojoLoggingErrorCallback(this);
        if ((new IOCallback<OutputStream, Boolean>(output) {

            @Override
            protected Boolean apply(final OutputStream output) throws IOException {
                final byte[] buffer = new byte[4096];
                final ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(output));
                for (final Map.Entry<Source, String> sourceInfo : gatherSources().entrySet()) {
                    final Source source = sourceInfo.getKey();
                    getLog().info("Processing " + source.getPath() + " into " + sourceInfo.getValue() + " ("
                            + source.getPattern() + ")");
                    final File folder = new File(source.getPath());
                    final String[] files = folder.list(new PatternFilenameFilter(regex(source.getPattern())));
                    if (files != null) {
                        for (final String file : files) {
                            getLog().debug("Adding " + file + " to archive");
                            final ZipEntry entry = new ZipEntry(sourceInfo.getValue() + file);
                            zip.putNextEntry(entry);
                            if ((new IOCallback<InputStream, Boolean>(
                                    getInputStreams().open(new File(folder, file))) {

                                @Override
                                protected Boolean apply(final InputStream input) throws IOException {
                                    int bytes;
                                    while ((bytes = input.read(buffer, 0, buffer.length)) > 0) {
                                        zip.write(buffer, 0, bytes);
                                    }
                                    return Boolean.TRUE;
                                }

                            }).call(errorLog) != Boolean.TRUE) {
                                return Boolean.FALSE;
                            }
                            zip.closeEntry();
                        }
                    } else {
                        getLog().debug("Source folder is empty or does not exist");
                    }
                }
                zip.close();
                return Boolean.TRUE;
            }

        }).call(errorLog) != Boolean.TRUE) {
            throw new MojoFailureException("Error writing to " + targetFile);
        }
        project.getArtifact().setFile(targetFile);
    }
}