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 SOURCES_PROPERTY = "sonar.sources"; 043 /** 044 * @deprecated since 4.5 use {@link #SOURCES_PROPERTY} 045 */ 046 @Deprecated 047 public static final String SOURCE_DIRS_PROPERTY = SOURCES_PROPERTY; 048 /** 049 * @deprecated since 4.5 use {@link #SOURCES_PROPERTY} 050 */ 051 @Deprecated 052 public static final String SOURCE_FILES_PROPERTY = "sonar.sourceFiles"; 053 054 public static final String TESTS_PROPERTY = "sonar.tests"; 055 /** 056 * @deprecated since 4.5 use {@link #TESTS_PROPERTY} 057 */ 058 @Deprecated 059 public static final String TEST_DIRS_PROPERTY = TESTS_PROPERTY; 060 /** 061 * @deprecated since 4.5 use {@link #TESTS_PROPERTY} 062 */ 063 @Deprecated 064 public static final String TEST_FILES_PROPERTY = "sonar.testFiles"; 065 public static final String BINARIES_PROPERTY = "sonar.binaries"; 066 public static final String LIBRARIES_PROPERTY = "sonar.libraries"; 067 public static final String BUILD_DIR_PROPERTY = "sonar.buildDir"; 068 069 private static final char SEPARATOR = ','; 070 071 private File baseDir, workDir, buildDir; 072 private Properties properties = new Properties(); 073 private ProjectDefinition parent = null; 074 private List<ProjectDefinition> subProjects = Lists.newArrayList(); 075 private List<Object> containerExtensions = Lists.newArrayList(); 076 077 private ProjectDefinition(Properties p) { 078 this.properties = p; 079 } 080 081 /** 082 * @deprecated in 2.12, because it uses external object to represent internal state. 083 * To ensure backward-compatibility with Ant task this method cannot clone properties, 084 * so other callers must explicitly make clone of properties before passing into this method. 085 * Thus better to use {@link #create()} with combination of other methods like {@link #setProperties(Properties)} and {@link #setProperty(String, String)}. 086 */ 087 @Deprecated 088 public static ProjectDefinition create(Properties properties) { 089 return new ProjectDefinition(properties); 090 } 091 092 public static ProjectDefinition create() { 093 return new ProjectDefinition(new Properties()); 094 } 095 096 public ProjectDefinition setBaseDir(File baseDir) { 097 this.baseDir = baseDir; 098 return this; 099 } 100 101 public File getBaseDir() { 102 return baseDir; 103 } 104 105 public ProjectDefinition setWorkDir(@Nullable File workDir) { 106 this.workDir = workDir; 107 return this; 108 } 109 110 @CheckForNull 111 public File getWorkDir() { 112 return workDir; 113 } 114 115 public ProjectDefinition setBuildDir(@Nullable File d) { 116 this.buildDir = d; 117 return this; 118 } 119 120 @CheckForNull 121 public File getBuildDir() { 122 return buildDir; 123 } 124 125 public Properties getProperties() { 126 return properties; 127 } 128 129 /** 130 * Copies specified properties into this object. 131 * 132 * @since 2.12 133 */ 134 public ProjectDefinition setProperties(Properties properties) { 135 this.properties.putAll(properties); 136 return this; 137 } 138 139 public ProjectDefinition setProperty(String key, String value) { 140 properties.setProperty(key, value); 141 return this; 142 } 143 144 public ProjectDefinition setKey(String key) { 145 properties.setProperty(CoreProperties.PROJECT_KEY_PROPERTY, key); 146 return this; 147 } 148 149 public ProjectDefinition setVersion(String s) { 150 properties.setProperty(CoreProperties.PROJECT_VERSION_PROPERTY, StringUtils.defaultString(s)); 151 return this; 152 } 153 154 public ProjectDefinition setName(String s) { 155 properties.setProperty(CoreProperties.PROJECT_NAME_PROPERTY, StringUtils.defaultString(s)); 156 return this; 157 } 158 159 public ProjectDefinition setDescription(String s) { 160 properties.setProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY, StringUtils.defaultString(s)); 161 return this; 162 } 163 164 public String getKey() { 165 return properties.getProperty(CoreProperties.PROJECT_KEY_PROPERTY); 166 } 167 168 /** 169 * @since 4.5 170 */ 171 public String getKeyWithBranch() { 172 String branch = properties.getProperty(CoreProperties.PROJECT_BRANCH_PROPERTY); 173 String projectKey = getKey(); 174 if (StringUtils.isNotBlank(branch)) { 175 projectKey = String.format("%s:%s", projectKey, branch); 176 } 177 return projectKey; 178 } 179 180 public String getVersion() { 181 return properties.getProperty(CoreProperties.PROJECT_VERSION_PROPERTY); 182 } 183 184 public String getName() { 185 String name = properties.getProperty(CoreProperties.PROJECT_NAME_PROPERTY); 186 if (StringUtils.isBlank(name)) { 187 name = "Unnamed - " + getKey(); 188 } 189 return name; 190 } 191 192 public String getDescription() { 193 return properties.getProperty(CoreProperties.PROJECT_DESCRIPTION_PROPERTY); 194 } 195 196 private void appendProperty(String key, String value) { 197 String current = properties.getProperty(key, ""); 198 if (StringUtils.isBlank(current)) { 199 properties.put(key, value); 200 } else { 201 properties.put(key, current + SEPARATOR + value); 202 } 203 } 204 205 /** 206 * @return Source files and folders. 207 */ 208 public List<String> sources() { 209 String sources = properties.getProperty(SOURCES_PROPERTY, ""); 210 return trim(StringUtils.split(sources, SEPARATOR)); 211 } 212 213 /** 214 * @deprecated since 4.5 use {@link #sources()} 215 */ 216 @Deprecated 217 public List<String> getSourceDirs() { 218 return sources(); 219 } 220 221 /** 222 * @param paths paths to file or directory with main sources. 223 * They can be absolute or relative to project base directory. 224 */ 225 public ProjectDefinition addSources(String... paths) { 226 for (String path : paths) { 227 appendProperty(SOURCES_PROPERTY, path); 228 } 229 return this; 230 } 231 232 /** 233 * @deprecated since 4.5 use {@link #addSources(String...)} 234 */ 235 @Deprecated 236 public ProjectDefinition addSourceDirs(String... paths) { 237 return addSources(paths); 238 } 239 240 public ProjectDefinition addSources(File... fileOrDirs) { 241 for (File fileOrDir : fileOrDirs) { 242 addSources(fileOrDir.getAbsolutePath()); 243 } 244 return this; 245 } 246 247 /** 248 * @deprecated since 4.5 use {@link #addSources(File...)} 249 */ 250 @Deprecated 251 public ProjectDefinition addSourceDirs(File... dirs) { 252 return addSources(dirs); 253 } 254 255 public ProjectDefinition resetSources() { 256 properties.remove(SOURCES_PROPERTY); 257 return this; 258 } 259 260 /** 261 * @deprecated since 4.5 use {@link #resetSources()} 262 */ 263 @Deprecated 264 public ProjectDefinition resetSourceDirs() { 265 return resetSources(); 266 } 267 268 public ProjectDefinition setSources(String... paths) { 269 resetSources(); 270 return addSources(paths); 271 } 272 273 /** 274 * @deprecated since 4.5 use {@link #setSources(String...)} 275 */ 276 @Deprecated 277 public ProjectDefinition setSourceDirs(String... paths) { 278 return setSources(paths); 279 } 280 281 public ProjectDefinition setSources(File... filesOrDirs) { 282 resetSources(); 283 for (File fileOrDir : filesOrDirs) { 284 addSources(fileOrDir.getAbsolutePath()); 285 } 286 return this; 287 } 288 289 /** 290 * @deprecated since 4.5 use {@link #setSources(File...)} 291 */ 292 @Deprecated 293 public ProjectDefinition setSourceDirs(File... dirs) { 294 resetSourceDirs(); 295 for (File dir : dirs) { 296 addSourceDirs(dir.getAbsolutePath()); 297 } 298 return this; 299 } 300 301 /** 302 * @deprecated since 4.5 use {@link #addSources(File...)} 303 */ 304 @Deprecated 305 public ProjectDefinition addSourceFiles(String... paths) { 306 // Hack for visual studio project builder that used to add baseDir first as source dir 307 List<String> sourceDirs = getSourceDirs(); 308 if (sourceDirs.size() == 1 && new File(sourceDirs.get(0)).isDirectory()) { 309 resetSources(); 310 } 311 return addSources(paths); 312 } 313 314 /** 315 * @deprecated since 4.5 use {@link #addSources(File...)} 316 */ 317 @Deprecated 318 public ProjectDefinition addSourceFiles(File... files) { 319 // Hack for visual studio project builder that used to add baseDir first as source dir 320 List<String> sourceDirs = getSourceDirs(); 321 if (sourceDirs.size() == 1 && new File(sourceDirs.get(0)).isDirectory()) { 322 resetSources(); 323 } 324 return addSources(files); 325 } 326 327 /** 328 * @deprecated since 4.5 use {@link #sources()} 329 */ 330 @Deprecated 331 public List<String> getSourceFiles() { 332 return sources(); 333 } 334 335 public List<String> tests() { 336 String sources = properties.getProperty(TESTS_PROPERTY, ""); 337 return trim(StringUtils.split(sources, SEPARATOR)); 338 } 339 340 /** 341 * @deprecated since 4.5 use {@link #tests()} 342 */ 343 @Deprecated 344 public List<String> getTestDirs() { 345 return tests(); 346 } 347 348 /** 349 * @param paths path to files or directories with test sources. 350 * It can be absolute or relative to project directory. 351 */ 352 public ProjectDefinition addTests(String... paths) { 353 for (String path : paths) { 354 appendProperty(TESTS_PROPERTY, path); 355 } 356 return this; 357 } 358 359 /** 360 * @deprecated since 4.5 use {@link #addTests(String...)} 361 */ 362 @Deprecated 363 public ProjectDefinition addTestDirs(String... paths) { 364 return addTests(paths); 365 } 366 367 public ProjectDefinition addTests(File... fileOrDirs) { 368 for (File fileOrDir : fileOrDirs) { 369 addTests(fileOrDir.getAbsolutePath()); 370 } 371 return this; 372 } 373 374 /** 375 * @deprecated since 4.5 use {@link #addTests(File...)} 376 */ 377 @Deprecated 378 public ProjectDefinition addTestDirs(File... dirs) { 379 return addTests(dirs); 380 } 381 382 public ProjectDefinition setTests(String... paths) { 383 resetTests(); 384 return addTests(paths); 385 } 386 387 /** 388 * @deprecated since 4.5 use {@link #setTests(String...)} 389 */ 390 @Deprecated 391 public ProjectDefinition setTestDirs(String... paths) { 392 return setTests(paths); 393 } 394 395 public ProjectDefinition setTests(File... fileOrDirs) { 396 resetTests(); 397 for (File dir : fileOrDirs) { 398 addTests(dir.getAbsolutePath()); 399 } 400 return this; 401 } 402 403 /** 404 * @deprecated since 4.5 use {@link #setTests(File...)} 405 */ 406 @Deprecated 407 public ProjectDefinition setTestDirs(File... dirs) { 408 return setTests(dirs); 409 } 410 411 public ProjectDefinition resetTests() { 412 properties.remove(TESTS_PROPERTY); 413 return this; 414 } 415 416 /** 417 * @deprecated since 4.5 use {@link #resetTests()} 418 */ 419 @Deprecated 420 public ProjectDefinition resetTestDirs() { 421 return resetTests(); 422 } 423 424 /** 425 * @deprecated since 4.5 use {@link #addTests(String...)} 426 */ 427 @Deprecated 428 public ProjectDefinition addTestFiles(String... paths) { 429 // Hack for visual studio project builder that used to add baseDir first as test dir 430 List<String> testDirs = getTestDirs(); 431 if (testDirs.size() == 1 && new File(testDirs.get(0)).isDirectory()) { 432 resetTests(); 433 } 434 return addTests(paths); 435 } 436 437 /** 438 * @deprecated since 4.5 use {@link #addTests(File...)} 439 */ 440 @Deprecated 441 public ProjectDefinition addTestFiles(File... files) { 442 return addTests(files); 443 } 444 445 /** 446 * @deprecated since 4.5 use {@link #tests()} 447 */ 448 @Deprecated 449 public List<String> getTestFiles() { 450 return tests(); 451 } 452 453 public List<String> getBinaries() { 454 String sources = properties.getProperty(BINARIES_PROPERTY, ""); 455 return trim(StringUtils.split(sources, SEPARATOR)); 456 } 457 458 /** 459 * @param path path to directory with compiled source. In case of Java this is directory with class files. 460 * It can be absolute or relative to project directory. 461 * TODO currently Sonar supports only one such directory due to dependency on MavenProject 462 */ 463 public ProjectDefinition addBinaryDir(String path) { 464 appendProperty(BINARIES_PROPERTY, path); 465 return this; 466 } 467 468 public ProjectDefinition addBinaryDir(File f) { 469 return addBinaryDir(f.getAbsolutePath()); 470 } 471 472 public List<String> getLibraries() { 473 String sources = properties.getProperty(LIBRARIES_PROPERTY, ""); 474 return trim(StringUtils.split(sources, SEPARATOR)); 475 } 476 477 /** 478 * @param path path to file with third-party library. In case of Java this is path to jar file. 479 * It can be absolute or relative to project directory. 480 */ 481 public void addLibrary(String path) { 482 appendProperty(LIBRARIES_PROPERTY, path); 483 } 484 485 /** 486 * Adds an extension, which would be available in PicoContainer during analysis of this project. 487 * 488 * @since 2.8 489 */ 490 public ProjectDefinition addContainerExtension(Object extension) { 491 containerExtensions.add(extension); 492 return this; 493 } 494 495 /** 496 * @since 2.8 497 */ 498 public List<Object> getContainerExtensions() { 499 return containerExtensions; 500 } 501 502 /** 503 * @since 2.8 504 */ 505 public ProjectDefinition addSubProject(ProjectDefinition child) { 506 subProjects.add(child); 507 child.setParent(this); 508 return this; 509 } 510 511 public ProjectDefinition getParent() { 512 return parent; 513 } 514 515 public void remove() { 516 if (parent != null) { 517 parent.subProjects.remove(this); 518 parent = null; 519 subProjects.clear(); 520 } 521 } 522 523 private void setParent(ProjectDefinition parent) { 524 this.parent = parent; 525 } 526 527 /** 528 * @since 2.8 529 */ 530 public List<ProjectDefinition> getSubProjects() { 531 return subProjects; 532 } 533 534 private static List<String> trim(String[] strings) { 535 List<String> result = Lists.newArrayList(); 536 for (String s : strings) { 537 result.add(StringUtils.trim(s)); 538 } 539 return result; 540 } 541 542 @Override 543 public boolean equals(Object o) { 544 if (this == o) { 545 return true; 546 } 547 if (o == null || getClass() != o.getClass()) { 548 return false; 549 } 550 ProjectDefinition that = (ProjectDefinition) o; 551 String key = getKey(); 552 if (key != null ? !key.equals(that.getKey()) : that.getKey() != null) { 553 return false; 554 } 555 556 return true; 557 } 558 559 @Override 560 public int hashCode() { 561 String key = getKey(); 562 return key != null ? key.hashCode() : 0; 563 } 564 }