All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazendaz.maven.makeself.MakeselfMojo Maven / Gradle / Ivy

Go to download

Makeself is a self-extracting archiving tool for Unix systems, in 100% shell script.

There is a newer version: 1.8.4
Show newest version
/**
 *    Copyright 2011-2017 the original author or authors.
 *
 *    This program is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU General Public License
 *    as published by the Free Software Foundation; either version 2
 *    of the License, or (at your option) any later version.
 *
 *    You may obtain a copy of the License at
 *
 *       https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 */
package com.hazendaz.maven.makeself;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

/**
 * The Class MakeselfMojo.
 */
@Mojo(name = "makeself", defaultPhase = LifecyclePhase.PACKAGE, requiresProject = false)
public class MakeselfMojo extends AbstractMojo {

    /**
     * archive_dir is the name of the directory that contains the files to be archived.
     */
    @Parameter(defaultValue = "makeself", property = "archiveDir", required = true)
    private String  archiveDir;

    /**
     * file_name is the name of the archive to be created.
     */
    @Parameter(defaultValue = "makeself", property = "fileName", required = true)
    private String  fileName;

    /**
     * label is an arbitrary text string describing the package. It will be displayed while extracting the files.
     */
    @Parameter(defaultValue = "Make self-extrabable archives", property = "label", required = true)
    private String  label;

    /**
     * startup_script is the command to be executed from within the directory of extracted files. Thus, if you wish to
     * execute a program contain in this directory, you must prefix your command with './'. For example, './program'
     * will be fine. The script_args are additional arguments for this command.
     */
    @Parameter(defaultValue = "makeself.sh", property = "startupScript", required = true)
    private String  startupScript;

    /** --version : Prints the version number on stdout, then exits immediately. Internally will display on all runs. */
    @Parameter(property = "version", readonly = true)
    private Boolean version;

    /** --gzip : Use gzip for compression (the default on platforms on which gzip is commonly available, like Linux) */
    @Parameter(property = "gzip")
    private Boolean gzip;

    /**
     * --bzip2 : Use bzip2 instead of gzip for better compression. The bzip2 command must be available in the command
     * path. It is recommended that the archive prefix be set to something like '.bz2.run', so that potential users know
     * that they'll need bzip2 to extract it.
     */
    @Parameter(property = "bzip2")
    private Boolean bzip2;

    /**
     * --pbzip2 : Use pbzip2 instead of gzip for better and faster compression on machines having multiple CPUs. The
     * pbzip2 command must be available in the command path. It is recommended that the archive prefix be set to
     * something like '.bz2.run', so that potential users know that they'll need bzip2 to extract it.
     */
    @Parameter(property = "pbzip2")
    private Boolean pbzip2;

    /**
     * --xz : Use xz instead of gzip for better compression. The xz command must be available in the command path. It is
     * recommended that the archive prefix be set to something like '.xz.run' for the archive, so that potential users
     * know that they'll need xz to extract it.
     */
    @Parameter(property = "xz")
    private Boolean xz;

    /**
     * --lzo : Use lzop instead of gzip for better compression. The lzop command must be available in the command path.
     * It is recommended that the archive prefix be set to something like '.lzo.run' for the archive, so that potential
     * users know that they'll need lzop to extract it.
     */
    @Parameter(property = "lzo")
    private Boolean lzo;

    /**
     * --lz4 : Use lz4 instead of gzip for better compression. The lz4 command must be available in the command path. It
     * is recommended that the archive prefix be set to something like '.lz4.run' for the archive, so that potential
     * users know that they'll need lz4 to extract it.
     */
    @Parameter(property = "lz4")
    private Boolean lz4;

    /** --pigz : Use pigz for compression. */
    @Parameter(property = "pigz")
    private Boolean pigz;

    /** --base64 : Encode the archive to ASCII in Base64 format (base64 command required). */
    @Parameter(property = "base64")
    private Boolean base64;

    /**
     * --gpg-encrypt : Encrypt the archive using gpg -ac -z $COMPRESS_LEVEL. This will prompt for a password to encrypt
     * with. Assumes that potential users have gpg installed.
     */
    @Parameter(property = "gpgEncrypt")
    private Boolean gpgEncrypt;

    /**
     * --ssl-encrypt : Encrypt the archive using openssl aes-256-cbc -a -salt. This will prompt for a password to
     * encrypt with. Assumes that the potential users have the OpenSSL tools installed.
     */
    @Parameter(property = "sslEncrypt")
    private Boolean sslEncrypt;

    /**
     * --compress : Use the UNIX compress command to compress the data. This should be the default on all platforms that
     * don't have gzip available.
     */
    @Parameter(property = "compress")
    private Boolean compress;

    /** --nocomp : Do not use any compression for the archive, which will then be an uncompressed TAR. */
    @Parameter(property = "nocomp")
    private Boolean nocomp;

    /** --complevel : Specify the compression level for gzip, bzip2, pbzip2, xz, lzo or lz4. (defaults to 9). */
    @Parameter(property = "complevel")
    private Integer complevel;

    /**
     * --notemp : The generated archive will not extract the files to a temporary directory, but in a new directory
     * created in the current directory. This is better to distribute software packages that may extract and compile by
     * themselves (i.e. launch the compilation through the embedded script).
     */
    @Parameter(property = "notemp")
    private Boolean notemp;

    /**
     * --current : Files will be extracted to the current directory, instead of in a subdirectory. This option implies
     * --notemp above.
     */
    @Parameter(property = "current")
    private Boolean current;

    /**
     * --follow : Follow the symbolic links inside of the archive directory, i.e. store the files that are being pointed
     * to instead of the links themselves.
     */
    @Parameter(property = "follow")
    private Boolean follow;

    /**
     * --append (new in 2.1.x): Append data to an existing archive, instead of creating a new one. In this mode, the
     * settings from the original archive are reused (compression type, label, embedded script), and thus don't need to
     * be specified again on the command line.
     */
    @Parameter(property = "append")
    private Boolean append;

    /**
     * --header: Makeself 2.0 uses a separate file to store the header stub, called makeself-header.sh. By default, it
     * is assumed that it is stored in the same location as makeself.sh. This option can be used to specify its actual
     * location if it is stored someplace else. This is not required for this plugin as the header is provided.
     */
    @Parameter(property = "headerFile", readonly = true)
    private Boolean headerFile;

    /**
     * --copy : Upon extraction, the archive will first extract itself to a temporary directory. The main application of
     * this is to allow self-contained installers stored in a Makeself archive on a CD, when the installer program will
     * later need to unmount the CD and allow a new one to be inserted. This prevents "Filesystem busy" errors for
     * installers that span multiple CDs.
     */
    @Parameter(property = "copy")
    private Boolean copy;

    /** --nox11 : Disable the automatic spawning of a new terminal in X11. */
    @Parameter(property = "nox11")
    private Boolean nox11;

    /** --nox11 : Disable the automatic spawning of a new terminal in X11. */
    @Parameter(property = "nowait")
    private Boolean nowait;

    /**
     * --nomd5 : Disable the creation of a MD5 checksum for the archive. This speeds up the extraction process if
     * integrity checking is not necessary.
     */
    @Parameter(property = "nomd5")
    private Boolean nomd5;

    /**
     * --nocrc : Disable the creation of a CRC checksum for the archive. This speeds up the extraction process if
     * integrity checking is not necessary.
     */
    @Parameter(property = "nocrc")
    private Boolean nocrc;

    /**
     * --lsm file : Provide and LSM file to makeself, that will be embedded in the generated archive. LSM files are
     * describing a software package in a way that is easily parseable. The LSM entry can then be later retrieved using
     * the --lsm argument to the archive. An example of a LSM file is provided with Makeself.
     */
    @Parameter(property = "lsmFile")
    private String  lsmFile;

    /**
     * --tar-extra opt : Append more options to the tar command line.
     *
     * For instance, in order to exclude the .git directory from the packaged archive directory using the GNU tar, one
     * can use makeself.sh --tar-extra "--exclude=.git" ...
     */
    @Parameter(property = "tarExtraOpt")
    private String  tarExtraOpt;

    /**
     * --keep-umask : Keep the umask set to shell default, rather than overriding when executing self-extracting
     * archive.
     */
    @Parameter(property = "keepUmask")
    private Boolean keepUmask;

    /**
     * --packaging-date date : Use provided string as the packaging date instead of the current date.
     */
    @Parameter(property = "packagingDate")
    private String  packagingDate;

    /**
     * --license : Append a license file.
     */
    @Parameter(property = "licenseFile")
    private String  licenseFile;

    /**
     * --nooverwrite : Do not extract the archive if the specified target directory already exists.
     */
    @Parameter(property = "nooverwrite")
    private Boolean nooverwrite;

    /**
     * --help-header file : Add a header to the archive's --help output.
     */
    @Parameter(property = "helpHeaderFile")
    private String  helpHeaderFile;

    @Parameter(defaultValue = "false", alias = "skip", property = "skip")
    private Boolean skip;

    /** The target directory. */
    @Parameter(defaultValue = "${project.build.directory}/makeself-temp", readonly = true)
    private File    targetDirectory;

    //** The build target. */
    @Parameter(defaultValue = "${project.build.directory}/", readonly = true)
    private String  buildTarget;

    /** The makeself. */
    private File    makeself;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        if (this.skip) {
            getLog().info("Formatting is skipped");
            return;
        }

        // Setup make self files
        this.extractMakeself();

        try {
            // Location of makeself.sh
            String makeselfTarget = "bash " + makeself.getAbsolutePath() + " ";

            // Output version of makeself.sh
            executeMakeself(makeselfTarget + "--version");

            // Basic Configuration
            String target = makeselfTarget + loadArgs() + buildTarget + archiveDir + " " + buildTarget + fileName + " "
                    + label + " " + startupScript;

            // Output Executed Command
            getLog().debug("### " + target);

            // Execute main run of makeself.sh
            executeMakeself(target);
        } catch (IOException | InterruptedException e) {
            if (e.getMessage().contains("Cannot run program \"bash\"")) {
                getLog().error("Add git's '/usr/bin' to environment variables to execute this plugin", e);
            } else {
                getLog().error("", e);
            }
        }
    }

    private void executeMakeself(String target) throws IOException, InterruptedException {
        Runtime rt = Runtime.getRuntime();
        Process proc = rt.exec(target);
        proc.waitFor();
        StringBuilder output = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
        String line = "";
        while ((line = reader.readLine()) != null) {
            output.append(line).append("\n");
        }
        getLog().info("### " + output);
    }

    /**
     * Extract makeself.
     */
    private void extractMakeself() {
        ClassLoader classloader = this.getClass().getClassLoader();

        try {
            File makeselfTemp = new File(targetDirectory.getAbsolutePath());
            if (!makeselfTemp.exists()) {
                makeselfTemp.mkdir();
            }

            makeself = new File(targetDirectory + "/makeself.sh");
            if (!makeself.exists()) {
                try (InputStream link = classloader.getResourceAsStream("makeself.sh")) {
                    Files.copy(link, makeself.getAbsoluteFile().toPath());
                }
            }

            File makeselfHeader = new File(targetDirectory + "/makeself-header.sh");
            if (!makeselfHeader.exists()) {
                try (InputStream link = classloader.getResourceAsStream("makeself-header.sh")) {
                    Files.copy(link, makeselfHeader.getAbsoluteFile().toPath());
                }
            }
        } catch (IOException e) {
            getLog().error("", e);
        }
    }

    /**
     * Load args.
     *
     * @return the string
     */
    private String loadArgs() {
        StringBuilder args = new StringBuilder();

        // --version : Prints the version number on stdout, then exits immediately
        if (isTrue(version)) {
            args.append("--version ");
        }

        // --gzip : Use gzip for compression (the default on platforms on which gzip is commonly available, like Linux)
        if (isTrue(gzip)) {
            args.append("--gzip ");
        }

        // --bzip2 : Use bzip2 instead of gzip for better compression. The bzip2 command must be available in the
        // command path. It
        // is recommended that the archive prefix be set to something like '.bz2.run', so that potential users know that
        // they'll need bzip2 to extract it.
        if (isTrue(bzip2)) {
            args.append("--bzip2 ");
        }

        // --pbzip2 : Use pbzip2 instead of gzip for better and faster compression on machines having multiple CPUs. The
        // pbzip2
        // command must be available in the command path. It is recommended that the archive prefix be set to something
        // like '.bz2.run', so that potential users know that they'll need bzip2 to extract it.
        if (isTrue(pbzip2)) {
            args.append("--pbzip2 ");
        }

        // --xz : Use xz instead of gzip for better compression. The xz command must be available in the command path.
        // It is
        // recommended that the archive prefix be set to something like '.xz.run' for the archive, so that potential
        // users know that they'll need xz to extract it.
        if (isTrue(xz)) {
            args.append("--xz ");
        }

        // --lzo : Use lzop instead of gzip for better compression. The lzop command must be available in the command
        // path. It
        // is recommended that the archive prefix be set to something like '.lzo.run' for the archive, so that potential
        // users know that they'll need lzop to extract it.
        if (isTrue(lzo)) {
            args.append("--lzo ");
        }

        // --lz4 : Use lz4 instead of gzip for better compression. The lz4 command must be available in the command
        // path. It is
        // recommended that the archive prefix be set to something like '.lz4.run' for the archive, so that potential
        // users know that they'll need lz4 to extract it.
        if (isTrue(lz4)) {
            args.append("--lz4 ");
        }

        // --pigz : Use pigz for compression.
        if (isTrue(pigz)) {
            args.append("--pigz ");
        }

        // --base64 : Encode the archive to ASCII in Base64 format (base64 command required).
        if (isTrue(base64)) {
            args.append("--base64 ");
        }

        // --gpg-encrypt : Encrypt the archive using gpg -ac -z $COMPRESS_LEVEL. This will prompt for a password to
        // encrypt with. Assumes that potential users have gpg installed.
        if (isTrue(gpgEncrypt)) {
            args.append("--gpg-encrypt ");
        }

        // --ssl-encrypt : Encrypt the archive using openssl aes-256-cbc -a -salt. This will prompt for a password to
        // encrypt with. Assumes that the potential users have the OpenSSL tools installed.
        if (isTrue(sslEncrypt)) {
            args.append("--ssl-encrypt ");
        }

        // --compress : Use the UNIX compress command to compress the data. This should be the default on all platforms
        // that don't have gzip available.
        if (isTrue(compress)) {
            args.append("--compress ");
        }

        // --nocomp : Do not use any compression for the archive, which will then be an uncompressed TAR.
        if (isTrue(nocomp)) {
            args.append("--nocomp ");
        }

        // --complevel : Specify the compression level for gzip, bzip2, pbzip2, xz, lzo or lz4. (defaults to 9)
        if (complevel != null) {
            args.append("--complevel ").append(complevel).append(" ");
        }

        // --notemp : The generated archive will not extract the files to a temporary directory, but in a new directory
        // created in the current directory. This is better to distribute software packages that may extract and compile
        // by themselves (i.e. launch the compilation through the embedded script).
        if (isTrue(notemp)) {
            args.append("--notemp ");
        }

        // --current : Files will be extracted to the current directory, instead of in a subdirectory. This option
        // implies --notemp above.
        if (isTrue(current)) {
            args.append("--current ");
        }

        // --follow : Follow the symbolic links inside of the archive directory, i.e. store the files that are being
        // pointed to instead of the links themselves.
        if (isTrue(follow)) {
            args.append("--follow ");
        }

        // --append (new in 2.1.x): Append data to an existing archive, instead of creating a new one. In this mode, the
        // settings from the original archive are reused (compression type, label, embedded script), and thus don't need
        // to be specified again on the command line.
        if (isTrue(append)) {
            args.append("--append ");
        }

        // --header : Makeself 2.0 uses a separate file to store the header stub, called makeself-header.sh. By default,
        // it is assumed that it is stored in the same location as makeself.sh. This option can be used to specify its
        // actual location if it is stored someplace else.
        if (headerFile != null) {
            args.append("--header ").append(headerFile).append(" ");
        }

        // --copy : Upon extraction, the archive will first extract itself to a temporary directory. The main
        // application of this is to allow self-contained installers stored in a Makeself archive on a CD, when the
        // installer program will later need to unmount the CD and allow a new one to be inserted. This prevents
        // "Filesystem busy" errors for installers that span multiple CDs.
        if (isTrue(copy)) {
            args.append("--copy ");
        }

        // --nox11 : Disable the automatic spawning of a new terminal in X11.
        if (isTrue(nox11)) {
            args.append("--nox11 ");
        }

        // --nowait : When executed from a new X11 terminal, disable the user prompt at the end of the script execution.
        if (isTrue(nowait)) {
            args.append("--nowait ");
        }

        // --nomd5 : Disable the creation of a MD5 checksum for the archive. This speeds up the extraction process if
        // integrity checking is not necessary.
        if (isTrue(nomd5)) {
            args.append("--nomd5 ");
        }

        // --nocrc : Disable the creation of a CRC checksum for the archive. This speeds up the extraction process if
        // integrity checking is not necessary.
        if (isTrue(nocrc)) {
            args.append("--nocrc ");
        }

        // --lsm file : Provide and LSM file to makeself, that will be embedded in the generated archive. LSM files are
        // describing a software package in a way that is easily parseable. The LSM entry can then be later retrieved
        // using the --lsm argument to the archive. An example of a LSM file is provided with Makeself.
        if (lsmFile != null) {
            args.append("--lsm ").append(lsmFile).append(" ");
        }

        // --tar-extra opt : Append more options to the tar command line.
        //
        // For instance, in order to exclude the .git directory from the packaged archive directory using the GNU tar,
        // one can use makeself.sh --tar-extra "--exclude=.git" ...
        if (tarExtraOpt != null) {
            args.append("--tar-extra ").append(tarExtraOpt).append(" ");
        }

        // --keep-umask : Keep the umask set to shell default, rather than overriding when executing self-extracting
        // archive.
        if (isTrue(keepUmask)) {
            args.append("--keep-umask ");
        }

        // --packaging-date date : Use provided string as the packaging date instead of the current date.
        if (packagingDate != null) {
            args.append("--packaging-date ").append(packagingDate).append(" ");
        }

        // --license : Append a license file.
        if (licenseFile != null) {
            args.append("--license ").append(licenseFile).append(" ");
        }

        // --nooverwrite : Do not extract the archive if the specified target directory already exists.
        if (isTrue(nooverwrite)) {
            args.append("--nooverwrite ");
        }

        // --help-header file : Add a header to the archive's --help output.
        if (helpHeaderFile != null) {
            args.append("--helpHeaderFile ").append(helpHeaderFile).append(" ");
        }

        return args.toString();
    }

    private boolean isTrue(Boolean value) {
        if (value != null) {
            return value.booleanValue();
        }
        return false;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy