123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- /*
- * 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.batch.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.java.api.JavaUtils;
-
- import javax.annotation.Nonnull;
- 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<MavenProject> poms, MavenProject root) {
- // projects by canonical path to pom.xml
- Map<String, MavenProject> paths = Maps.newHashMap();
- Map<MavenProject, ProjectDefinition> 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<String, MavenProject> paths, Map<MavenProject, ProjectDefinition> defs) throws IOException {
- for (Map.Entry<String, MavenProject> 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<MavenProject> poms, Map<String, MavenProject> paths, Map<MavenProject, ProjectDefinition> 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<String, MavenProject> paths) throws IOException {
- if (modulePath.exists() && modulePath.isDirectory()) {
- for (Map.Entry<String, MavenProject> 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.sonarsource.com/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.sonarsource.com/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.properties().get(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());
- }
-
- 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<File> resolvePaths(List<String> paths, File basedir) {
- List<File> result = Lists.newArrayList();
- for (String path : paths) {
- File dir = resolvePath(path, basedir);
- if (dir != null) {
- result.add(dir);
- }
- }
- return result;
- }
-
- private List<File> mainDirs(MavenProject pom) {
- return sourceDirs(pom, ProjectDefinition.SOURCE_DIRS_PROPERTY, pom.getCompileSourceRoots());
- }
-
- private List<File> testDirs(MavenProject pom) {
- return sourceDirs(pom, ProjectDefinition.TEST_DIRS_PROPERTY, pom.getTestCompileSourceRoots());
- }
-
- private List<File> sourceDirs(MavenProject pom, String propertyKey, List mavenDirs) {
- List<String> 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<File> dirs = resolvePaths(mavenDirs, pom.getBasedir());
-
- // Maven provides some directories that do not exist. They
- // should be removed
- return keepExistingDirs(dirs);
- }
-
- private List<File> existingDirsOrFail(List<File> 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<File> keepExistingDirs(List<File> files) {
- return Lists.newArrayList(Collections2.filter(files, new Predicate<File>() {
- @Override
- public boolean apply(File dir) {
- return dir != null && dir.exists() && dir.isDirectory();
- }
- }));
- }
-
- private static String[] toPaths(Collection<File> dirs) {
- Collection<String> paths = Collections2.transform(dirs, new Function<File, String>() {
- @Override
- public String apply(@Nonnull File dir) {
- return dir.getAbsolutePath();
- }
- });
- return paths.toArray(new String[paths.size()]);
- }
- }
|