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

com.igormaznitsa.mvnjlink.mojos.MvnJlinkMojo Maven / Gradle / Ivy

Go to download

There is a newer version: 1.2.4
Show newest version
/*
 * Copyright 2019 Igor Maznitsa.
 *
 * 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 com.igormaznitsa.mvnjlink.mojos;

import com.igormaznitsa.meta.annotation.MustNotContainNull;
import com.igormaznitsa.meta.common.utils.GetUtils;
import org.apache.commons.io.FileUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.ProcessResult;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.igormaznitsa.mvnjlink.utils.StringUtils.extractJdepsModuleNames;
import static java.nio.file.Files.isDirectory;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.io.FileUtils.deleteDirectory;

/**
 * Execute JLINK tool from provided JDK.
 */
@Mojo(name = "jlink", defaultPhase = LifecyclePhase.PACKAGE, threadSafe = true)
public class MvnJlinkMojo extends AbstractJdkToolMojo {

  /**
   * Path to the report generated by JDEPS.
   */
  @Parameter(name = "jdepsReportPath")
  private String jdepsReportPath;

  /**
   * Command line options for the tool.
   */
  @Parameter(name = "options")
  private List options = new ArrayList<>();

  /**
   * Path to JDK module folder. If not provided then value from toolJdk path will be used.
   */
  @Parameter(name = "modulePath")
  private String modulePath;

  /**
   * List of modules to be added.
   */
  @Parameter(name = "addModules")
  private List addModules = new ArrayList<>();

  /**
   * Path to place generated image.
   */
  @Parameter(name = "output", required = true)
  private String output;

  @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
  @Nonnull
  @MustNotContainNull
  private static List extractModuleNamesFromJdepsReport(@Nonnull final Optional jdepsReportPath) throws MojoExecutionException {
    if (jdepsReportPath.isPresent()) {
      final Path jdepsFile = jdepsReportPath.get();

      try {
        return extractJdepsModuleNames(FileUtils.readFileToString(jdepsFile.toFile(), Charset.defaultCharset()));
      } catch (IOException ex) {
        throw new MojoExecutionException("Can't read jdeps out file:" + jdepsFile, ex);
      }
    } else {
      return Collections.emptyList();
    }
  }

  @Nonnull
  @MustNotContainNull
  public List getOptions() {
    return this.options;
  }

  public void setOptions(@Nullable @MustNotContainNull final List value) {
    this.options = GetUtils.ensureNonNull(value, new ArrayList<>());
  }

  @Override
  public void onExecute() throws MojoExecutionException, MojoFailureException {
    final Log log = this.getLog();

    final Path providerJdk = this.getSourceJdkFolderFromProvider();

    final Path outputPath = Paths.get(this.output);

    final String pathToJlink = this.findJdkTool("jlink");
    if (pathToJlink == null) {
      throw new MojoExecutionException("Can't find jlink in JDK");
    }
    final Path execJlinkPath = Paths.get(pathToJlink);

    final List modulesFromJdeps = extractModuleNamesFromJdepsReport(ofNullable(this.jdepsReportPath == null ? null : Paths.get(this.jdepsReportPath)));
    final List totalModules = new ArrayList<>(modulesFromJdeps);
    totalModules.addAll(this.addModules);

    final String joinedAddModules = totalModules.stream().map(String::trim).collect(joining(","));

    log.info("List of modules : " + joinedAddModules);

    final List commandLineOptions = new ArrayList<>(this.getOptions());

    commandLineOptions.add("--module-path");
    if (this.modulePath != null) {
      log.debug("Detected non-empty module path in configuration: " + this.modulePath);

      final File modulePathFolder = new File(this.modulePath);

      if (!modulePathFolder.isDirectory()) {
        throw new MojoExecutionException("Can't find folder provided in 'modulePath': " + modulePathFolder.getAbsolutePath());
      }

      commandLineOptions.add(modulePathFolder.getAbsolutePath());
    } else {
      log.info("Provider JDK will be used as module path source: " + providerJdk);

      final Path pathToMods = providerJdk.resolve("jmods");
      if (!Files.isDirectory(pathToMods)) {
        throw new MojoExecutionException("Can't find jmods folder: " + pathToMods.toString());
      }

      commandLineOptions.add(pathToMods.toString());
    }

    final int indexOptions = commandLineOptions.indexOf("--add-modules");
    if (indexOptions < 0) {
      if (joinedAddModules.isEmpty()) {
        throw new MojoExecutionException("There are not provided modules to be added.");
      }
      commandLineOptions.add("--add-modules");
      commandLineOptions.add(joinedAddModules);
    } else {
      if (!joinedAddModules.isEmpty()) {
        commandLineOptions.set(indexOptions + 1, commandLineOptions.get(indexOptions + 1) + ',' + joinedAddModules);
      }
    }

    if (isDirectory(outputPath)) {
      log.warn("Deleting existing output folder: " + outputPath);
      try {
        deleteDirectory(outputPath.toFile());
      } catch (IOException ex) {
        throw new MojoExecutionException("Can't delete output folder: " + outputPath, ex);
      }
    }

    final List commandLine = new ArrayList<>();
    commandLine.add(execJlinkPath.toString());
    commandLine.add("--output");
    commandLine.add(outputPath.toString());
    commandLine.addAll(commandLineOptions);

    this.getLog().info("CLI arguments: " + commandLine.stream().skip(1).collect(Collectors.joining(" ")));

    log.debug("Command line: " + commandLine);

    final ByteArrayOutputStream consoleOut = new ByteArrayOutputStream();
    final ByteArrayOutputStream consoleErr = new ByteArrayOutputStream();

    final ProcessResult executor;
    try {
      executor = new ProcessExecutor(commandLine)
          .readOutput(true)
          .redirectOutput(consoleOut)
          .redirectError(consoleErr)
          .exitValueAny()
          .executeNoTimeout();
    } catch (IOException ex) {
      throw new MojoExecutionException("Error during execution", ex);
    } catch (InterruptedException ex) {
      Thread.currentThread().interrupt();
      throw new MojoFailureException("Execution interrupted", ex);
    }

    if (executor.getExitValue() == 0) {
      log.debug(new String(consoleOut.toByteArray(), Charset.defaultCharset()));
      log.info("Execution completed successfully, the result folder is " + outputPath);
    } else {
      final String textOut = new String(consoleOut.toByteArray(), Charset.defaultCharset());
      final String textErr = new String(consoleErr.toByteArray(), Charset.defaultCharset());

      if (executor.getExitValue() == 1 && textOut.contains("Error: java.lang.IllegalArgumentException")) {
        log.error("It looks like that the current JDK is incompatible with the provided JDK!");
      }

      if (textErr.isEmpty()) {
        log.error(textOut);
      } else {
        log.info(textOut);
        log.error(textErr);
      }

      throw new MojoFailureException("jlink returns error status code: " + executor.getExitValue());
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy