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