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