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

de.dagere.peass.execution.maven.pom.MavenPomUtil Maven / Gradle / Ivy

The newest version!
package de.dagere.peass.execution.maven.pom;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.maven.model.Build;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Exclusion;
import org.apache.maven.model.Model;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import de.dagere.peass.config.ExecutionConfig;
import de.dagere.peass.execution.utils.EnvironmentVariables;
import de.dagere.peass.execution.utils.ProjectModules;
import de.dagere.peass.execution.utils.RequiredDependency;
import de.dagere.peass.testtransformation.JUnitVersions;
import de.dagere.peass.utils.StreamGobbler;

public class MavenPomUtil {

   public static final String LOG4J_GROUPID = "org.apache.logging.log4j";
   public static final String LOG4J_SLF4J_IMPL_ARTIFACTID = "log4j-slf4j-impl";
   public static final String LOG4J_TO_SLF4J_ARTIFACTID = "log4j-to-slf4j";
   public static final String KOPEME_VERSION = "1.3.13";
   public static final String KIEKER_VERSION = "1.15.4";
   public static final String ORG_APACHE_MAVEN_PLUGINS = "org.apache.maven.plugins";
   public static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin";
   public static final String COMPILER_ARTIFACTID = "maven-compiler-plugin";

   public static final String COMPILER_PLUGIN_VERSION = "3.12.1";

   public static final String JUPITER_VERSION = "5.10.1";
   public static final String LOG4J_VERSION = "2.22.0";

   private static final Logger LOG = LogManager.getLogger(MavenPomUtil.class);

   public static void cleanType(final File pomFile) {
      try {
         final Model model;
         try (FileInputStream inputStream = new FileInputStream(pomFile)) {
            final MavenXpp3Reader reader = new MavenXpp3Reader();
            model = reader.read(inputStream);
         }
         if (model.getPackaging().equals("pom") && model.getModules() == null || model.getModules().size() == 0) {
            model.setPackaging("jar");
            try (FileWriter fileWriter = new FileWriter(pomFile)) {
               final MavenXpp3Writer writer = new MavenXpp3Writer();
               writer.write(fileWriter, model);
            }
         }
      } catch (IOException | XmlPullParserException e) {
         e.printStackTrace();
      }
   }

   public static void extendDependencies(final Model model, final JUnitVersions versions, final boolean excludeLog4j) {
      updateJUnit(model);

      final List dependencies = model.getDependencies();

      for (RequiredDependency dependency : RequiredDependency.getAll(versions)) {
         if (dependency.getMavenDependency().getArtifactId().contains("slf4j-impl")) {
            addLoggingImplementationDependency(dependencies, dependency);
         } else if (dependency.getMavenDependency().getArtifactId().contains("kopeme")) {
            dependencies.add(0, dependency.getMavenDependency());
            if (excludeLog4j) {
               Exclusion exclusion = new Exclusion();
               exclusion.setArtifactId(LOG4J_SLF4J_IMPL_ARTIFACTID);
               exclusion.setGroupId(LOG4J_GROUPID);
               dependencies.get(0).addExclusion(exclusion);
            }
         } else {
            dependencies.add(dependency.getMavenDependency());
         }

      }
   }

   private static void updateJUnit(final Model model) {
      boolean needsToInsertLog4jApi = false;
      for (final Dependency dependency : model.getDependencies()) {
         updateDependency(dependency);
         
         /** If slf4j is used, we need to insert log4j-api 2.18.0 as direct dependency, since slf4j contains log4j 2.
          * This might also be necessary if a transitive dependency includes slf4j, but for now, this is sufficient (and it might change in newer slf4j versions)
          */
         if (dependency.getGroupId().equals("org.slf4j") && dependency.getArtifactId().equals("slf4j-api")) {
            needsToInsertLog4jApi = true;
         }
      }
      if (needsToInsertLog4jApi) {
         Dependency log4jApi = new Dependency();
         log4jApi.setGroupId(LOG4J_GROUPID);
         log4jApi.setArtifactId("log4j-api");
         log4jApi.setVersion(LOG4J_VERSION);
         model.getDependencies().add(log4jApi);
      }
      
      if (model.getDependencyManagement() != null) {
         for (final Dependency dependency : model.getDependencyManagement().getDependencies()) {
            updateDependency(dependency);
         }
      }
   }

   private static void updateDependency(final Dependency dependency) {
      if (dependency.getArtifactId().equals("junit") && dependency.getGroupId().equals("junit")) {
         dependency.setVersion("4.13.2");
      }
      if (dependency.getArtifactId().equals("junit-jupiter") && dependency.getGroupId().equals("org.junit.jupiter")) {
         dependency.setVersion(JUPITER_VERSION);
      }
      if (dependency.getArtifactId().equals("log4j-api") && dependency.getGroupId().equals(LOG4J_GROUPID)) {
         dependency.setVersion(LOG4J_VERSION);
      }
   }

   private static void addLoggingImplementationDependency(final List dependencies, final RequiredDependency dependency) {
      Dependency originalSlf4j = null;
      for (Dependency original : dependencies) {
         if (original.getArtifactId().contains("slf4j-impl")) {
            originalSlf4j = original;
         }
      }
      if (originalSlf4j != null) {
         originalSlf4j.setScope(null);
      } else {
         dependencies.add(dependency.getMavenDependency());
      }
   }

   public static boolean isMultiModuleProject(final File pom) throws FileNotFoundException, IOException, XmlPullParserException {
      try (FileInputStream inputStream = new FileInputStream(pom)) {
         final MavenXpp3Reader reader = new MavenXpp3Reader();
         final Model model = reader.read(inputStream);
         return model.getModules() != null;
      }
   }

   /**
    * This gets a list of all dependent modules of one maven module, so only these can be included in measurement; since maven does not provide a way to easily determine the
    * project structure, we call the (currently effectless) pre-clean goal and parse the output (relying on constant output format)
    * 
    * @param projectFolder
    * @param pl
    * @return
    * @throws IOException
    */
   public static List getDependentModules(final File projectFolder, final String pl, EnvironmentVariables env) throws IOException {
      ProcessBuilder pb = new ProcessBuilder(env.fetchMavenCall(projectFolder),
            "-B", "pre-clean", "-pl", pl, "-am");
      pb.directory(projectFolder);
      String output = StreamGobbler.getFullProcess(pb.start(), false);
      List modules = new LinkedList<>();
      for (String line : output.split("\n")) {
         if (line.contains("---------------<")) {
            String[] parts = line.split(" ");
            String groupAnArtifactPart = parts[2];
            String artifact = groupAnArtifactPart.split(":")[1];
            modules.add(artifact);

         }
      }
      return modules;
   }

   public static ProjectModules getModules(final File pom, final ExecutionConfig config) {
      ProjectModules modules = null;
      try {
         modules = new ModuleReader().readModuleFiles(pom);
         if (config.getPl() != null && !"".equals(config.getPl())) {
            List includedModuleNames = getIncludedModuleNames(pom, config);

            for (Iterator moduleIterator = modules.getModules().iterator(); moduleIterator.hasNext();) {
               File moduleFile = moduleIterator.next();
               String fileModuleName = moduleFile.getName();
               System.out.println("Name: " + fileModuleName + " " + includedModuleNames);
               String fileArtifactId = modules.getArtifactIds().get(moduleFile);
               System.out.println("Artifactid: " + fileArtifactId);
               if (!includedModuleNames.contains(fileModuleName) && !includedModuleNames.contains(fileArtifactId)) {
                  moduleIterator.remove();
               }
            }
         }

         return modules;
      } catch (IOException | XmlPullParserException e) {
         LOG.error("Was not able to read modules; this commit will not be analyzable!");
         e.printStackTrace();
      }
      return null;
   }

   private static List getIncludedModuleNames(final File pom, final ExecutionConfig config) throws IOException {
      List includedModuleNames = new LinkedList<>();
      ProcessBuilder builder = new ProcessBuilder(EnvironmentVariables.fetchMavenCallGeneric(),
            "--batch-mode", "pre-clean",
            "-pl", config.getPl(), "-am");
      builder.directory(pom.getParentFile());
      Process process = builder.start();
      String output = StreamGobbler.getFullProcess(process, false);
      for (String line : output.split("\n")) {
         int startIndex = line.indexOf("-<");
         int endIndex = line.indexOf(">-");
         System.out.println(line + " " + startIndex);
         if (line.startsWith("[ERROR]")) {
            throw new RuntimeException("Unexpected line when reading modules: " + line);
         }
         if (startIndex != -1) {
            int expectedModuleNameStart = startIndex + 3;
            int expectedModuleNameEnd = endIndex - 1;
            if (expectedModuleNameEnd < expectedModuleNameStart || line.startsWith("[ERROR]")) {
               throw new RuntimeException("Unexpected line when reading modules: " + line);
            }
            String fullModuleName = line.substring(expectedModuleNameStart, expectedModuleNameEnd);
            String moduleName = fullModuleName.split(":")[1];
            includedModuleNames.add(moduleName);
         }
      }
      return includedModuleNames;
   }

   public static Charset getEncoding(final Model model) {
      Charset value = StandardCharsets.UTF_8;
      final Properties properties = model.getProperties();
      if (properties != null) {
         final String encoding = (String) properties.get("project.build.sourceEncoding");
         if (encoding != null) {
            if (encoding.equals("ISO-8859-1")) {
               value = StandardCharsets.ISO_8859_1;
            }
         }
      }
      return value;
   }

   public static Plugin findPlugin(final Model model, final String artifactId, final String groupId) {
      Plugin surefire = null;
      if (model.getBuild() == null) {
         model.setBuild(new Build());
      }
      if (model.getBuild().getPlugins() == null) {
         model.getBuild().setPlugins(new LinkedList());
      }
      for (final Plugin plugin : model.getBuild().getPlugins()) {
         if (plugin.getArtifactId().equals(artifactId) && plugin.getGroupId().equals(groupId)) {
            surefire = plugin;
            break;
         }
      }
      if (surefire == null) {
         surefire = new Plugin();
         surefire.setArtifactId(artifactId);
         surefire.setGroupId(groupId);
         model.getBuild().getPlugins().add(surefire);
      }
      return surefire;
   }

   public static void extendSurefire(final String additionalArgLine, final Model model, final boolean updateVersion) {
      final Plugin plugin = MavenPomUtil.findPlugin(model, SUREFIRE_ARTIFACTID, ORG_APACHE_MAVEN_PLUGINS);
      if (plugin.getConfiguration() == null) {
         plugin.setConfiguration(new Xpp3Dom("configuration"));
      }

      if (updateVersion) {
         LOG.trace("Surefire {} {}", plugin.getClass(), plugin.getConfiguration().getClass());
         plugin.setVersion(MavenTestExecutor.SUREFIRE_VERSION);
      }

      final Xpp3Dom conf = (Xpp3Dom) plugin.getConfiguration();
      // MavenPomUtil.addNode(conf, "forkmode", "pertest");
      MavenPomUtil.setConfNode(conf, "forkCount", "1");
      MavenPomUtil.setConfNode(conf, "reuseForks", "false");
      MavenPomUtil.setConfNode(conf, "runOrder", "alphabetical");
      // if (timeout != -1) {
      // MavenPomUtil.setConfNode(conf, "forkedProcessTimeoutInSeconds", "" + timeout);
      // }

      Xpp3Dom argLine = conf.getChild("argLine");
      if (argLine != null) {
         String changedArgLine = argLine.getValue().contains("-Xmx") ? argLine.getValue().replaceAll("-Xmx[0-9]{0,3}[mM]", "-Xmx1g") : argLine.getValue();
         changedArgLine = changedArgLine.replaceAll("$\\{argLine\\}", "");
         argLine.setValue(changedArgLine + " " + additionalArgLine);
      } else {
         argLine = new Xpp3Dom("argLine");
         argLine.setValue(additionalArgLine);
         conf.addChild(argLine);
      }
   }

   public static void extendCompiler(final Plugin plugin, final String boot_class_path) {
      if (boot_class_path == null || !new File(boot_class_path).exists()) {
         throw new RuntimeException("Boot-Classpath " + boot_class_path + " is not defined.");
      }
      if (plugin.getConfiguration() == null) {
         plugin.setConfiguration(new Xpp3Dom("configuration"));
      }
      LOG.debug("Compiler" + plugin.getClass() + " " + plugin.getConfiguration().getClass());
      plugin.setVersion(COMPILER_PLUGIN_VERSION);

      LOG.info("BOOT_LIBS: {}", boot_class_path);

      final Xpp3Dom conf = (Xpp3Dom) plugin.getConfiguration();

      final Xpp3Dom compilerArguments = findChild(conf, "compilerArguments");
      final Xpp3Dom bootclasspath = findChild(compilerArguments, "bootclasspath");
      bootclasspath.setValue(boot_class_path + "/resources.jar${path.separator}" + boot_class_path
            + "/rt.jar${path.separator}" + boot_class_path + "/sunrsasign.jar:" + boot_class_path
            + "/jsse.jar${path.separator}" + boot_class_path + "/jce.jar${path.separator}" + boot_class_path
            + "/charsets.jar${path.separator}" + boot_class_path + "/jfr.jar");

   }

   public static void setIncrementalBuild(final Plugin plugin, final boolean build) {
      if (plugin.getConfiguration() == null) {
         plugin.setConfiguration(new Xpp3Dom("configuration"));
      }
      LOG.debug("Compiler" + plugin.getClass() + " " + plugin.getConfiguration().getClass());
      plugin.setVersion(COMPILER_PLUGIN_VERSION);

      final Xpp3Dom conf = (Xpp3Dom) plugin.getConfiguration();

      final Xpp3Dom compilerArguments = findChild(conf, "useIncrementalCompilation");
      compilerArguments.setValue("" + build);

   }

   private static Xpp3Dom findChild(final Xpp3Dom conf, final String name) {
      Xpp3Dom compilerArguments = conf.getChild(name);
      if (compilerArguments == null) {
         compilerArguments = new Xpp3Dom(name);
         conf.addChild(compilerArguments);
      }
      return compilerArguments;
   }

   public static Xpp3Dom setConfNode(final Xpp3Dom conf, final String nodeName, final String value) {
      Xpp3Dom confProperty = conf.getChild(nodeName);
      if (confProperty != null) {
         confProperty.setValue(value);
      } else if (confProperty == null) {
         confProperty = new Xpp3Dom(nodeName);
         confProperty.setValue(value);
         conf.addChild(confProperty);
      }
      return confProperty;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy