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