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