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

org.sonar.plugins.maven.MavenProjectConverter Maven / Gradle / Ivy

There is a newer version: 4.3.3
Show newest version
/*
 * SonarQube, open source software quality management tool.
 * Copyright (C) 2008-2014 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * SonarQube is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * SonarQube 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.plugins.maven;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.model.CiManagement;
import org.apache.maven.model.IssueManagement;
import org.apache.maven.model.Scm;
import org.apache.maven.project.MavenProject;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.SupportedEnvironment;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.maven.MavenUtils;
import org.sonar.api.task.TaskExtension;
import org.sonar.api.utils.MessageException;
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
import org.sonar.java.api.JavaUtils;

import javax.annotation.Nullable;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @deprecated since 4.3 kept only to support old version of SonarQube Mojo
 */
@Deprecated
@SupportedEnvironment("maven")
public class MavenProjectConverter implements TaskExtension {

  private static final String UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE = "Unable to determine structure of project." +
    " Probably you use Maven Advanced Reactor Options, which is not supported by SonarQube and should not be used.";

  public ProjectDefinition configure(List poms, MavenProject root) {
    // projects by canonical path to pom.xml
    Map paths = Maps.newHashMap();
    Map defs = Maps.newHashMap();

    try {
      configureModules(poms, paths, defs);

      rebuildModuleHierarchy(paths, defs);
    } catch (IOException e) {
      throw new IllegalStateException("Cannot configure project", e);
    }

    ProjectDefinition rootProject = defs.get(root);
    if (rootProject == null) {
      throw new IllegalStateException(UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE);
    }
    return rootProject;
  }

  private void rebuildModuleHierarchy(Map paths, Map defs) throws IOException {
    for (Map.Entry entry : paths.entrySet()) {
      MavenProject pom = entry.getValue();
      for (Object m : pom.getModules()) {
        String moduleId = (String) m;
        File modulePath = new File(pom.getBasedir(), moduleId);
        MavenProject module = findMavenProject(modulePath, paths);

        ProjectDefinition parentProject = defs.get(pom);
        if (parentProject == null) {
          throw new IllegalStateException(UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE);
        }
        ProjectDefinition subProject = defs.get(module);
        if (subProject == null) {
          throw new IllegalStateException(UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE);
        }
        parentProject.addSubProject(subProject);
      }
    }
  }

  private void configureModules(List poms, Map paths, Map defs) throws IOException {
    for (MavenProject pom : poms) {
      paths.put(pom.getFile().getCanonicalPath(), pom);
      ProjectDefinition def = ProjectDefinition.create();
      merge(pom, def);
      defs.put(pom, def);
    }
  }

  private static MavenProject findMavenProject(final File modulePath, Map paths) throws IOException {
    if (modulePath.exists() && modulePath.isDirectory()) {
      for (Map.Entry entry : paths.entrySet()) {
        String pomFileParentDir = new File(entry.getKey()).getParent();
        if (pomFileParentDir.equals(modulePath.getCanonicalPath())) {
          return entry.getValue();
        }
      }
      return null;
    }
    return paths.get(modulePath.getCanonicalPath());
  }

  @VisibleForTesting
  void merge(MavenProject pom, ProjectDefinition definition) {
    String key = getSonarKey(pom);
    // IMPORTANT NOTE : reference on properties from POM model must not be saved,
    // instead they should be copied explicitly - see SONAR-2896
    definition
      .setProperties(pom.getModel().getProperties())
      .setKey(key)
      .setVersion(pom.getVersion())
      .setName(pom.getName())
      .setDescription(pom.getDescription())
      .addContainerExtension(pom);
    guessJavaVersion(pom, definition);
    guessEncoding(pom, definition);
    convertMavenLinksToProperties(definition, pom);
    synchronizeFileSystem(pom, definition);
  }

  private static String getSonarKey(MavenProject pom) {
    return new StringBuilder().append(pom.getGroupId()).append(":").append(pom.getArtifactId()).toString();
  }

  private static void guessEncoding(MavenProject pom, ProjectDefinition definition) {
    // See http://jira.codehaus.org/browse/SONAR-2151
    String encoding = MavenUtils.getSourceEncoding(pom);
    if (encoding != null) {
      definition.setProperty(CoreProperties.ENCODING_PROPERTY, encoding);
    }
  }

  private static void guessJavaVersion(MavenProject pom, ProjectDefinition definition) {
    // See http://jira.codehaus.org/browse/SONAR-2148
    // Get Java source and target versions from maven-compiler-plugin.
    String version = MavenUtils.getJavaSourceVersion(pom);
    if (version != null) {
      definition.setProperty(JavaUtils.JAVA_SOURCE_PROPERTY, version);
    }
    version = MavenUtils.getJavaVersion(pom);
    if (version != null) {
      definition.setProperty(JavaUtils.JAVA_TARGET_PROPERTY, version);
    }
  }

  /**
   * For SONAR-3676
   */
  private static void convertMavenLinksToProperties(ProjectDefinition definition, MavenProject pom) {
    setPropertyIfNotAlreadyExists(definition, CoreProperties.LINKS_HOME_PAGE, pom.getUrl());

    Scm scm = pom.getScm();
    if (scm == null) {
      scm = new Scm();
    }
    setPropertyIfNotAlreadyExists(definition, CoreProperties.LINKS_SOURCES, scm.getUrl());
    setPropertyIfNotAlreadyExists(definition, CoreProperties.LINKS_SOURCES_DEV, scm.getDeveloperConnection());

    CiManagement ci = pom.getCiManagement();
    if (ci == null) {
      ci = new CiManagement();
    }
    setPropertyIfNotAlreadyExists(definition, CoreProperties.LINKS_CI, ci.getUrl());

    IssueManagement issues = pom.getIssueManagement();
    if (issues == null) {
      issues = new IssueManagement();
    }
    setPropertyIfNotAlreadyExists(definition, CoreProperties.LINKS_ISSUE_TRACKER, issues.getUrl());
  }

  private static void setPropertyIfNotAlreadyExists(ProjectDefinition definition, String propertyKey, String propertyValue) {
    if (StringUtils.isBlank(definition.getProperties().getProperty(propertyKey))) {
      definition.setProperty(propertyKey, StringUtils.defaultString(propertyValue));
    }
  }

  public void synchronizeFileSystem(MavenProject pom, ProjectDefinition into) {
    into.setBaseDir(pom.getBasedir());
    File buildDir = getBuildDir(pom);
    if (buildDir != null) {
      into.setBuildDir(buildDir);
      into.setWorkDir(getSonarWorkDir(pom));
    }
    into.setSourceDirs(toPaths(mainDirs(pom)));
    into.setTestDirs(toPaths(testDirs(pom)));
    File binaryDir = resolvePath(pom.getBuild().getOutputDirectory(), pom.getBasedir());
    if (binaryDir != null) {
      into.addBinaryDir(binaryDir);
    }
  }

  public static File getSonarWorkDir(MavenProject pom) {
    return new File(getBuildDir(pom), "sonar");
  }

  private static File getBuildDir(MavenProject pom) {
    return resolvePath(pom.getBuild().getDirectory(), pom.getBasedir());
  }

  public void synchronizeFileSystem(MavenProject pom, DefaultModuleFileSystem into) {
    into.resetDirs(
      pom.getBasedir(),
      getBuildDir(pom),
      mainDirs(pom),
      testDirs(pom),
      Arrays.asList(resolvePath(pom.getBuild().getOutputDirectory(), pom.getBasedir())));
  }

  static File resolvePath(@Nullable String path, File basedir) {
    if (path != null) {
      File file = new File(StringUtils.trim(path));
      if (!file.isAbsolute()) {
        try {
          file = new File(basedir, path).getCanonicalFile();
        } catch (IOException e) {
          throw new IllegalStateException("Unable to resolve path '" + path + "'", e);
        }
      }
      return file;
    }
    return null;
  }

  static List resolvePaths(List paths, File basedir) {
    List result = Lists.newArrayList();
    for (String path : paths) {
      File dir = resolvePath(path, basedir);
      if (dir != null) {
        result.add(dir);
      }
    }
    return result;
  }

  private List mainDirs(MavenProject pom) {
    return sourceDirs(pom, ProjectDefinition.SOURCE_DIRS_PROPERTY, pom.getCompileSourceRoots());
  }

  private List testDirs(MavenProject pom) {
    return sourceDirs(pom, ProjectDefinition.TEST_DIRS_PROPERTY, pom.getTestCompileSourceRoots());
  }

  private List sourceDirs(MavenProject pom, String propertyKey, List mavenDirs) {
    List paths;
    String prop = pom.getProperties().getProperty(propertyKey);
    if (prop != null) {
      paths = Arrays.asList(StringUtils.split(prop, ","));
      // do not remove dirs that do not exist. They must be kept in order to
      // notify users that value of sonar.sources has a typo.
      return existingDirsOrFail(resolvePaths(paths, pom.getBasedir()), pom, propertyKey);
    }

    List dirs = resolvePaths(mavenDirs, pom.getBasedir());

    // Maven provides some directories that do not exist. They
    // should be removed
    return keepExistingDirs(dirs);
  }

  private List existingDirsOrFail(List dirs, MavenProject pom, String propertyKey) {
    for (File dir : dirs) {
      if (!dir.isDirectory() || !dir.exists()) {
        throw MessageException.of(String.format(
          "The directory '%s' does not exist for Maven module %s. Please check the property %s",
          dir.getAbsolutePath(), pom.getId(), propertyKey));
      }
    }
    return dirs;
  }

  private static List keepExistingDirs(List files) {
    return Lists.newArrayList(Collections2.filter(files, new Predicate() {
      @Override
      public boolean apply(File dir) {
        return dir != null && dir.exists() && dir.isDirectory();
      }
    }));
  }

  private static String[] toPaths(Collection dirs) {
    Collection paths = Collections2.transform(dirs, new Function() {
      @Override
      public String apply(File dir) {
        return dir.getAbsolutePath();
      }
    });
    return paths.toArray(new String[paths.size()]);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy