001/* 002 * SonarQube 003 * Copyright (C) 2009-2017 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program 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 * This program 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 public static final String TESTS_PROPERTY = "sonar.tests"; 046 047 public static final String BUILD_DIR_PROPERTY = "sonar.buildDir"; 048 049 private static final char SEPARATOR = ','; 050 051 private File baseDir; 052 private File workDir; 053 private File buildDir; 054 private Map<String, String> properties = new HashMap<>(); 055 private ProjectDefinition parent = null; 056 private List<ProjectDefinition> subProjects = new ArrayList<>(); 057 058 private ProjectDefinition(Properties p) { 059 for (Entry<Object, Object> entry : p.entrySet()) { 060 this.properties.put(entry.getKey().toString(), entry.getValue().toString()); 061 } 062 } 063 064 public static ProjectDefinition create() { 065 return new ProjectDefinition(new Properties()); 066 } 067 068 public ProjectDefinition setBaseDir(File baseDir) { 069 this.baseDir = baseDir; 070 return this; 071 } 072 073 public File getBaseDir() { 074 return baseDir; 075 } 076 077 public ProjectDefinition setWorkDir(File workDir) { 078 this.workDir = workDir; 079 return this; 080 } 081 082 public File getWorkDir() { 083 return workDir; 084 } 085 086 /** 087 * @deprecated since 6.1 notion of buildDir is not well defined 088 */ 089 @Deprecated 090 public ProjectDefinition setBuildDir(File d) { 091 this.buildDir = d; 092 return this; 093 } 094 095 /** 096 * @deprecated since 6.1 notion of buildDir is not well defined 097 */ 098 @Deprecated 099 public File getBuildDir() { 100 return buildDir; 101 } 102 103 /** 104 * @deprecated since 5.0 use {@link #properties()} 105 */ 106 @Deprecated 107 public Properties getProperties() { 108 Properties result = new Properties(); 109 for (Map.Entry<String, String> entry : properties.entrySet()) { 110 result.setProperty(entry.getKey(), entry.getValue()); 111 } 112 return result; 113 } 114 115 public Map<String, String> properties() { 116 return properties; 117 } 118 119 /** 120 * Copies specified properties into this object. 121 * 122 * @since 2.12 123 * @deprecated since 5.0 use {@link #setProperties(Map)} 124 */ 125 @Deprecated 126 public ProjectDefinition setProperties(Properties properties) { 127 for (Entry<Object, Object> entry : properties.entrySet()) { 128 this.properties.put(entry.getKey().toString(), entry.getValue().toString()); 129 } 130 return this; 131 } 132 133 public ProjectDefinition setProperties(Map<String, String> properties) { 134 this.properties.putAll(properties); 135 return this; 136 } 137 138 public ProjectDefinition setProperty(String key, String value) { 139 properties.put(key, value); 140 return this; 141 } 142 143 public ProjectDefinition setKey(String key) { 144 properties.put(CoreProperties.PROJECT_KEY_PROPERTY, key); 145 return this; 146 } 147 148 public ProjectDefinition setVersion(String s) { 149 properties.put(CoreProperties.PROJECT_VERSION_PROPERTY, StringUtils.defaultString(s)); 150 return this; 151 } 152 153 public ProjectDefinition setName(String s) { 154 properties.put(CoreProperties.PROJECT_NAME_PROPERTY, StringUtils.defaultString(s)); 155 return this; 156 } 157 158 public ProjectDefinition setDescription(String s) { 159 properties.put(CoreProperties.PROJECT_DESCRIPTION_PROPERTY, StringUtils.defaultString(s)); 160 return this; 161 } 162 163 public String getKey() { 164 return properties.get(CoreProperties.PROJECT_KEY_PROPERTY); 165 } 166 167 /** 168 * @since 4.5 169 */ 170 public String getKeyWithBranch() { 171 String branch = getBranch(); 172 String projectKey = getKey(); 173 if (StringUtils.isNotBlank(branch)) { 174 projectKey = String.format("%s:%s", projectKey, branch); 175 } 176 return projectKey; 177 } 178 179 @CheckForNull 180 public String getBranch() { 181 String branch = properties.get(CoreProperties.PROJECT_BRANCH_PROPERTY); 182 if (StringUtils.isNotBlank(branch)) { 183 return branch; 184 } else if (getParent() != null) { 185 return getParent().getBranch(); 186 } 187 return null; 188 } 189 190 @CheckForNull 191 public String getOriginalVersion() { 192 return properties.get(CoreProperties.PROJECT_VERSION_PROPERTY); 193 } 194 195 public String getVersion() { 196 String version = properties.get(CoreProperties.PROJECT_VERSION_PROPERTY); 197 if (StringUtils.isBlank(version)) { 198 version = "not provided"; 199 } 200 return version; 201 } 202 203 @CheckForNull 204 public String getOriginalName() { 205 return properties.get(CoreProperties.PROJECT_NAME_PROPERTY); 206 } 207 208 public String getName() { 209 String name = properties.get(CoreProperties.PROJECT_NAME_PROPERTY); 210 if (StringUtils.isBlank(name)) { 211 name = getKey(); 212 } 213 return name; 214 } 215 216 public String getDescription() { 217 return properties.get(CoreProperties.PROJECT_DESCRIPTION_PROPERTY); 218 } 219 220 private void appendProperty(String key, String value) { 221 String current = (String) ObjectUtils.defaultIfNull(properties.get(key), ""); 222 if (StringUtils.isBlank(current)) { 223 properties.put(key, value); 224 } else { 225 properties.put(key, current + SEPARATOR + value); 226 } 227 } 228 229 /** 230 * @return Source files and folders. 231 */ 232 public List<String> sources() { 233 String sources = (String) ObjectUtils.defaultIfNull(properties.get(SOURCES_PROPERTY), ""); 234 return trim(StringUtils.split(sources, SEPARATOR)); 235 } 236 237 /** 238 * @param paths paths to file or directory with main sources. 239 * They can be absolute or relative to project base directory. 240 */ 241 public ProjectDefinition addSources(String... paths) { 242 for (String path : paths) { 243 appendProperty(SOURCES_PROPERTY, path); 244 } 245 return this; 246 } 247 248 public ProjectDefinition addSources(File... fileOrDirs) { 249 for (File fileOrDir : fileOrDirs) { 250 addSources(fileOrDir.getAbsolutePath()); 251 } 252 return this; 253 } 254 255 public ProjectDefinition resetSources() { 256 properties.remove(SOURCES_PROPERTY); 257 return this; 258 } 259 260 public ProjectDefinition setSources(String... paths) { 261 resetSources(); 262 return addSources(paths); 263 } 264 265 public ProjectDefinition setSources(File... filesOrDirs) { 266 resetSources(); 267 for (File fileOrDir : filesOrDirs) { 268 addSources(fileOrDir.getAbsolutePath()); 269 } 270 return this; 271 } 272 273 public List<String> tests() { 274 String sources = (String) ObjectUtils.defaultIfNull(properties.get(TESTS_PROPERTY), ""); 275 return trim(StringUtils.split(sources, SEPARATOR)); 276 } 277 278 /** 279 * @param paths path to files or directories with test sources. 280 * It can be absolute or relative to project directory. 281 */ 282 public ProjectDefinition addTests(String... paths) { 283 for (String path : paths) { 284 appendProperty(TESTS_PROPERTY, path); 285 } 286 return this; 287 } 288 289 public ProjectDefinition addTests(File... fileOrDirs) { 290 for (File fileOrDir : fileOrDirs) { 291 addTests(fileOrDir.getAbsolutePath()); 292 } 293 return this; 294 } 295 296 public ProjectDefinition setTests(String... paths) { 297 resetTests(); 298 return addTests(paths); 299 } 300 301 public ProjectDefinition setTests(File... fileOrDirs) { 302 resetTests(); 303 for (File dir : fileOrDirs) { 304 addTests(dir.getAbsolutePath()); 305 } 306 return this; 307 } 308 309 public ProjectDefinition resetTests() { 310 properties.remove(TESTS_PROPERTY); 311 return this; 312 } 313 314 /** 315 * @since 2.8 316 */ 317 public ProjectDefinition addSubProject(ProjectDefinition child) { 318 subProjects.add(child); 319 child.setParent(this); 320 return this; 321 } 322 323 public ProjectDefinition getParent() { 324 return parent; 325 } 326 327 public void remove() { 328 if (parent != null) { 329 parent.subProjects.remove(this); 330 parent = null; 331 subProjects.clear(); 332 } 333 } 334 335 private void setParent(ProjectDefinition parent) { 336 this.parent = parent; 337 } 338 339 /** 340 * @since 2.8 341 */ 342 public List<ProjectDefinition> getSubProjects() { 343 return subProjects; 344 } 345 346 private static List<String> trim(String[] strings) { 347 List<String> result = new ArrayList<>(); 348 for (String s : strings) { 349 result.add(StringUtils.trim(s)); 350 } 351 return result; 352 } 353 354 @Override 355 public boolean equals(Object o) { 356 if (this == o) { 357 return true; 358 } 359 if (o == null || getClass() != o.getClass()) { 360 return false; 361 } 362 ProjectDefinition that = (ProjectDefinition) o; 363 String key = getKey(); 364 return !((key != null) ? !key.equals(that.getKey()) : (that.getKey() != null)); 365 366 } 367 368 @Override 369 public int hashCode() { 370 String key = getKey(); 371 return key != null ? key.hashCode() : 0; 372 } 373}