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