001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.batch;
021
022 import java.io.File;
023 import java.io.IOException;
024 import java.util.List;
025 import java.util.Map;
026
027 import org.apache.maven.project.MavenProject;
028 import org.sonar.api.batch.bootstrap.ProjectDefinition;
029 import org.sonar.api.utils.SonarException;
030
031 import com.google.common.collect.Maps;
032
033 public final class MavenProjectConverter {
034
035 private static final String UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE = "Unable to determine structure of project." +
036 " Probably you use Maven Advanced Reactor Options, which is not supported by Sonar and should not be used.";
037
038 public static ProjectDefinition convert(List<MavenProject> poms, MavenProject root) {
039 Map<String, MavenProject> paths = Maps.newHashMap(); // projects by canonical path to pom.xml
040 Map<MavenProject, ProjectDefinition> defs = Maps.newHashMap();
041
042 try {
043 for (MavenProject pom : poms) {
044 paths.put(pom.getFile().getCanonicalPath(), pom);
045 defs.put(pom, convert(pom));
046 }
047
048 for (Map.Entry<String, MavenProject> entry : paths.entrySet()) {
049 MavenProject pom = entry.getValue();
050 for (Object m : pom.getModules()) {
051 String moduleId = (String) m;
052 File modulePath = new File(pom.getBasedir(), moduleId);
053 if (modulePath.exists() && modulePath.isDirectory()) {
054 modulePath = new File(modulePath, "pom.xml");
055 }
056 MavenProject module = paths.get(modulePath.getCanonicalPath());
057
058 ProjectDefinition parentProject = defs.get(pom);
059 ProjectDefinition subProject = defs.get(module);
060 if (parentProject == null) {
061 throw new IllegalStateException(UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE);
062 }
063 if (subProject == null) {
064 throw new IllegalStateException(UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE);
065 }
066 parentProject.addSubProject(subProject);
067 }
068 }
069 } catch (IOException e) {
070 throw new SonarException(e);
071 }
072
073 ProjectDefinition rootProject = defs.get(root);
074 if (rootProject == null) {
075 throw new IllegalStateException(UNABLE_TO_DETERMINE_PROJECT_STRUCTURE_EXCEPTION_MESSAGE);
076 }
077
078 return rootProject;
079 }
080
081 /**
082 * Visibility has been relaxed for tests.
083 */
084 static ProjectDefinition convert(MavenProject pom) {
085 String key = new StringBuilder().append(pom.getGroupId()).append(":").append(pom.getArtifactId()).toString();
086 ProjectDefinition definition = ProjectDefinition.create();
087 // IMPORTANT NOTE : reference on properties from POM model must not be saved, instead they should be copied explicitly - see SONAR-2896
088 definition
089 .setProperties(pom.getModel().getProperties())
090 .setKey(key)
091 .setVersion(pom.getVersion())
092 .setName(pom.getName())
093 .setDescription(pom.getDescription())
094 .addContainerExtension(pom);
095 synchronizeFileSystem(pom, definition);
096 return definition;
097 }
098
099 public static void synchronizeFileSystem(MavenProject pom, ProjectDefinition into) {
100 into.setBaseDir(pom.getBasedir());
101 into.setWorkDir(new File(resolvePath(pom.getBuild().getDirectory(), pom.getBasedir()), "sonar"));
102 into.setSourceDirs((String[]) pom.getCompileSourceRoots().toArray(new String[pom.getCompileSourceRoots().size()]));
103 into.setTestDirs((String[]) pom.getTestCompileSourceRoots().toArray(new String[pom.getTestCompileSourceRoots().size()]));
104 }
105
106 static File resolvePath(String path, File basedir) {
107 File file = new File(path);
108 if (!file.isAbsolute()) {
109 try {
110 file = new File(basedir, path).getCanonicalFile();
111 } catch (IOException e) {
112 throw new SonarException("Unable to resolve path '" + path + "'", e);
113 }
114 }
115 return file;
116 }
117
118 private MavenProjectConverter() {
119 // only static methods
120 }
121 }