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 */ 020package org.sonar.api.batch.bootstrap; 021 022import com.google.common.collect.Lists; 023import org.apache.commons.lang.StringUtils; 024import org.sonar.api.BatchComponent; 025import org.sonar.api.CoreProperties; 026 027import java.io.File; 028import java.util.List; 029import java.util.Properties; 030 031/** 032 * Defines project metadata (key, name, source directories, ...). It's generally used by the 033 * {@link org.sonar.api.batch.bootstrap.ProjectBuilder extension point} and must not be used 034 * by other standard extensions. 035 * 036 * @since 2.9 037 */ 038public final class ProjectDefinition implements BatchComponent { 039 040 public static final String SOURCE_DIRS_PROPERTY = "sonar.sources"; 041 public static final String SOURCE_FILES_PROPERTY = "sonar.sourceFiles"; 042 public static final String TEST_DIRS_PROPERTY = "sonar.tests"; 043 public static final String TEST_FILES_PROPERTY = "sonar.testFiles"; 044 public static final String BINARIES_PROPERTY = "sonar.binaries"; 045 public static final String LIBRARIES_PROPERTY = "sonar.libraries"; 046 047 private static final char SEPARATOR = ','; 048 049 private File baseDir; 050 private File workDir; 051 private Properties properties = new Properties(); 052 private ProjectDefinition parent = null; 053 private List<ProjectDefinition> subProjects = Lists.newArrayList(); 054 private List<Object> containerExtensions = Lists.newArrayList(); 055 056 private ProjectDefinition(Properties p) { 057 this.properties = p; 058 } 059 060 /** 061 * @deprecated in 2.12, because it uses external object to represent internal state. 062 * To ensure backward-compatibility with Ant task this method cannot clone properties, 063 * so other callers must explicitly make clone of properties before passing into this method. 064 * Thus better to use {@link #create()} with combination of other methods like {@link #setProperties(Properties)} and {@link #setProperty(String, String)}. 065 */ 066 @Deprecated 067 public static ProjectDefinition create(Properties properties) { 068 return new ProjectDefinition(properties); 069 } 070 071 public static ProjectDefinition create() { 072 return new ProjectDefinition(new Properties()); 073 } 074 075 public ProjectDefinition setBaseDir(File baseDir) { 076 this.baseDir = baseDir; 077 return this; 078 } 079 080 public File getBaseDir() { 081 return baseDir; 082 } 083 084 public ProjectDefinition setWorkDir(File workDir) { 085 this.workDir = workDir; 086 return this; 087 } 088 089 public File getWorkDir() { 090 return workDir; 091 } 092 093 public Properties getProperties() { 094 return properties; 095 } 096 097 /** 098 * Copies specified properties into this object. 099 * 100 * @since 2.12 101 */ 102 public ProjectDefinition setProperties(Properties properties) { 103 this.properties.putAll(properties); 104 return this; 105 } 106 107 public ProjectDefinition setProperty(String key, String value) { 108 properties.setProperty(key, value); 109 return this; 110 } 111 112 public ProjectDefinition setKey(String key) { 113 properties.setProperty(CoreProperties.PROJECT_KEY_PROPERTY, key); 114 return this; 115 } 116 117 public ProjectDefinition setVersion(String s) { 118 properties.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, StringUtils.defaultString(s)); 119 return this; 120 } 121 122 public ProjectDefinition setName(String s) { 123 properties.setProperty(CoreProperties.PROJECT_NAME_PROPERTY, StringUtils.defaultString(s)); 124 return this; 125 } 126 127 public ProjectDefinition setDescription(String s) { 128 properties.setProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY, StringUtils.defaultString(s)); 129 return this; 130 } 131 132 public String getKey() { 133 return properties.getProperty(CoreProperties.PROJECT_KEY_PROPERTY); 134 } 135 136 public String getVersion() { 137 return properties.getProperty(CoreProperties.PROJECT_VERSION_PROPERTY); 138 } 139 140 public String getName() { 141 String name = properties.getProperty(CoreProperties.PROJECT_NAME_PROPERTY); 142 if (StringUtils.isBlank(name)) { 143 name = "Unnamed - " + getKey(); 144 } 145 return name; 146 } 147 148 public String getDescription() { 149 return properties.getProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY); 150 } 151 152 private void appendProperty(String key, String value) { 153 String newValue = properties.getProperty(key, "") + SEPARATOR + value; 154 properties.put(key, newValue); 155 } 156 157 public List<String> getSourceDirs() { 158 String sources = properties.getProperty(SOURCE_DIRS_PROPERTY, ""); 159 return trim(StringUtils.split(sources, SEPARATOR)); 160 } 161 162 /** 163 * @param paths paths to directory with main sources. 164 * They can be absolute or relative to project base directory. 165 */ 166 public ProjectDefinition addSourceDirs(String... paths) { 167 for (String path : paths) { 168 appendProperty(SOURCE_DIRS_PROPERTY, path); 169 } 170 return this; 171 } 172 173 public ProjectDefinition addSourceDirs(File... dirs) { 174 for (File dir : dirs) { 175 addSourceDirs(dir.getAbsolutePath()); 176 } 177 return this; 178 } 179 180 public ProjectDefinition resetSourceDirs() { 181 properties.remove(SOURCE_DIRS_PROPERTY); 182 return this; 183 } 184 185 public ProjectDefinition setSourceDirs(String... paths) { 186 resetSourceDirs(); 187 return addSourceDirs(paths); 188 } 189 190 public ProjectDefinition setSourceDirs(File... dirs) { 191 resetSourceDirs(); 192 for (File dir : dirs) { 193 addSourceDirs(dir.getAbsolutePath()); 194 } 195 return this; 196 } 197 198 /** 199 * Adding source files is possible only if no source directories have been set. 200 * Absolute path or relative path from project base dir. 201 */ 202 public ProjectDefinition addSourceFiles(String... paths) { 203 for (String path : paths) { 204 appendProperty(SOURCE_FILES_PROPERTY, path); 205 } 206 return this; 207 } 208 209 /** 210 * Adding source files is possible only if no source directories have been set. 211 */ 212 public ProjectDefinition addSourceFiles(File... files) { 213 for (File file : files) { 214 addSourceFiles(file.getAbsolutePath()); 215 } 216 return this; 217 } 218 219 public List<String> getSourceFiles() { 220 String sources = properties.getProperty(SOURCE_FILES_PROPERTY, ""); 221 return trim(StringUtils.split(sources, SEPARATOR)); 222 } 223 224 public List<String> getTestDirs() { 225 String sources = properties.getProperty(TEST_DIRS_PROPERTY, ""); 226 return trim(StringUtils.split(sources, SEPARATOR)); 227 } 228 229 /** 230 * @param paths path to directory with test sources. 231 * It can be absolute or relative to project directory. 232 */ 233 public ProjectDefinition addTestDirs(String... paths) { 234 for (String path : paths) { 235 appendProperty(TEST_DIRS_PROPERTY, path); 236 } 237 return this; 238 } 239 240 public ProjectDefinition addTestDirs(File... dirs) { 241 for (File dir : dirs) { 242 addTestDirs(dir.getAbsolutePath()); 243 } 244 return this; 245 } 246 247 public ProjectDefinition setTestDirs(String... paths) { 248 resetTestDirs(); 249 return addTestDirs(paths); 250 } 251 252 public ProjectDefinition setTestDirs(File... dirs) { 253 resetTestDirs(); 254 for (File dir : dirs) { 255 addTestDirs(dir.getAbsolutePath()); 256 } 257 return this; 258 } 259 260 public ProjectDefinition resetTestDirs() { 261 properties.remove(TEST_DIRS_PROPERTY); 262 return this; 263 } 264 265 /** 266 * Adding source files is possible only if no source directories have been set. 267 * Absolute path or relative path from project base dir. 268 */ 269 public ProjectDefinition addTestFiles(String... paths) { 270 for (String path : paths) { 271 appendProperty(TEST_FILES_PROPERTY, path); 272 } 273 return this; 274 } 275 276 /** 277 * Adding source files is possible only if no source directories have been set. 278 */ 279 public ProjectDefinition addTestFiles(File... files) { 280 for (File file : files) { 281 addTestFiles(file.getAbsolutePath()); 282 } 283 return this; 284 } 285 286 public List<String> getTestFiles() { 287 String sources = properties.getProperty(TEST_FILES_PROPERTY, ""); 288 return trim(StringUtils.split(sources, SEPARATOR)); 289 } 290 291 public List<String> getBinaries() { 292 String sources = properties.getProperty(BINARIES_PROPERTY, ""); 293 return trim(StringUtils.split(sources, SEPARATOR)); 294 } 295 296 /** 297 * @param path path to directory with compiled source. In case of Java this is directory with class files. 298 * It can be absolute or relative to project directory. 299 * @TODO currently Sonar supports only one such directory due to dependency on MavenProject 300 */ 301 public ProjectDefinition addBinaryDir(String path) { 302 appendProperty(BINARIES_PROPERTY, path); 303 return this; 304 } 305 306 public ProjectDefinition addBinaryDir(File f) { 307 return addBinaryDir(f.getAbsolutePath()); 308 } 309 310 public List<String> getLibraries() { 311 String sources = properties.getProperty(LIBRARIES_PROPERTY, ""); 312 return trim(StringUtils.split(sources, SEPARATOR)); 313 } 314 315 /** 316 * @param path path to file with third-party library. In case of Java this is path to jar file. 317 * It can be absolute or relative to project directory. 318 */ 319 public void addLibrary(String path) { 320 appendProperty(LIBRARIES_PROPERTY, path); 321 } 322 323 /** 324 * Adds an extension, which would be available in PicoContainer during analysis of this project. 325 * 326 * @since 2.8 327 */ 328 public ProjectDefinition addContainerExtension(Object extension) { 329 containerExtensions.add(extension); 330 return this; 331 } 332 333 /** 334 * @since 2.8 335 */ 336 public List<Object> getContainerExtensions() { 337 return containerExtensions; 338 } 339 340 /** 341 * @since 2.8 342 */ 343 public ProjectDefinition addSubProject(ProjectDefinition child) { 344 subProjects.add(child); 345 child.setParent(this); 346 return this; 347 } 348 349 public ProjectDefinition getParent() { 350 return parent; 351 } 352 353 private void setParent(ProjectDefinition parent) { 354 this.parent = parent; 355 } 356 357 /** 358 * @since 2.8 359 */ 360 public List<ProjectDefinition> getSubProjects() { 361 return subProjects; 362 } 363 364 private static List<String> trim(String[] strings) { 365 List<String> result = Lists.newArrayList(); 366 for (String s : strings) { 367 result.add(StringUtils.trim(s)); 368 } 369 return result; 370 } 371}