@@ -203,8 +203,8 @@ zip.doFirst { | |||
} | |||
// Check the size of the archive | |||
zip.doLast { | |||
def minLength = 198000000 | |||
def maxLength = 208000000 | |||
def minLength = 185000000 | |||
def maxLength = 199000000 | |||
def length = archiveFile.get().asFile.length() | |||
if (length < minLength) | |||
throw new GradleException("$archiveName size ($length) too small. Min is $minLength") |
@@ -25,12 +25,11 @@ import java.io.InputStream; | |||
import java.nio.charset.Charset; | |||
import java.nio.file.Path; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.api.batch.fs.internal.TestInputFileBuilder; | |||
import org.sonar.api.batch.sensor.SensorDescriptor; | |||
/** | |||
* This layer over {@link java.io.File} adds information for code analyzers. | |||
* For unit testing purpose, use {@link TestInputFileBuilder} and initialize | |||
* For unit testing purpose, use TestInputFileBuilder and initialize | |||
* the needed fields: | |||
* | |||
* <pre> |
@@ -45,14 +45,6 @@ public class DefaultIndexedFile extends DefaultInputComponent implements Indexed | |||
private final Path absolutePath; | |||
private final SensorStrategy sensorStrategy; | |||
/** | |||
* Testing purposes only! | |||
*/ | |||
public DefaultIndexedFile(String projectKey, Path baseDir, String relativePath, @Nullable String language) { | |||
this(baseDir.resolve(relativePath), projectKey, relativePath, relativePath, Type.MAIN, language, TestInputFileBuilder.nextBatchId(), | |||
new SensorStrategy()); | |||
} | |||
public DefaultIndexedFile(Path absolutePath, String projectKey, String projectRelativePath, String moduleRelativePath, Type type, @Nullable String language, int batchId, | |||
SensorStrategy sensorStrategy) { | |||
super(batchId); |
@@ -49,7 +49,7 @@ import static org.sonar.api.utils.Preconditions.checkState; | |||
/** | |||
* @since 4.2 | |||
* To create {@link InputFile} in tests, use {@link TestInputFileBuilder}. | |||
* To create {@link InputFile} in tests, use TestInputFileBuilder. | |||
*/ | |||
public class DefaultInputFile extends DefaultInputComponent implements InputFile { | |||
@@ -22,7 +22,6 @@ package org.sonar.api.batch.sensor; | |||
import org.sonar.api.ExtensionPoint; | |||
import org.sonar.api.batch.InstantiationStrategy; | |||
import org.sonar.api.batch.ScannerSide; | |||
import org.sonar.api.batch.sensor.internal.SensorContextTester; | |||
import org.sonar.api.scanner.sensor.ProjectSensor; | |||
import org.sonarsource.api.sonarlint.SonarLintSide; | |||
@@ -33,7 +32,7 @@ import org.sonarsource.api.sonarlint.SonarLintSide; | |||
* <p> | |||
* For example the Cobertura Sensor parses Cobertura report and saves the first-level of measures on files. | |||
* | |||
* For testing purpose you can use {@link SensorContextTester} | |||
* For testing purpose you can use SensorContextTester | |||
* @since 5.1 | |||
* @since 7.6 use {@link ProjectSensor} instead to make your Sensor run only once per analysis, and no more once per module | |||
*/ |
@@ -30,7 +30,6 @@ import org.sonar.api.batch.sensor.coverage.NewCoverage; | |||
import org.sonar.api.batch.sensor.cpd.NewCpdTokens; | |||
import org.sonar.api.batch.sensor.error.NewAnalysisError; | |||
import org.sonar.api.batch.sensor.highlighting.NewHighlighting; | |||
import org.sonar.api.batch.sensor.internal.SensorContextTester; | |||
import org.sonar.api.batch.sensor.issue.ExternalIssue; | |||
import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.issue.NewExternalIssue; | |||
@@ -48,7 +47,7 @@ import org.sonar.api.utils.Version; | |||
/** | |||
* See {@link Sensor#execute(SensorContext)} | |||
* In order to write unit tests you can use {@link SensorContextTester} | |||
* In order to write unit tests you can use SensorContextTester | |||
* @since 5.1 | |||
*/ | |||
public interface SensorContext { |
@@ -23,7 +23,6 @@ import org.sonar.api.ExtensionPoint; | |||
import org.sonar.api.scanner.ScannerSide; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.batch.sensor.SensorDescriptor; | |||
import org.sonar.api.batch.sensor.internal.SensorContextTester; | |||
import org.sonarsource.api.sonarlint.SonarLintSide; | |||
/** | |||
@@ -32,7 +31,7 @@ import org.sonarsource.api.sonarlint.SonarLintSide; | |||
* <p> | |||
* For example the Cobertura Sensor parses Cobertura report and saves the first-level of measures on files. | |||
* | |||
* For testing purpose you can use {@link SensorContextTester} | |||
* For testing purpose you can use SensorContextTester | |||
* @since 7.6 | |||
*/ | |||
@ScannerSide |
@@ -0,0 +1,161 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.nio.charset.Charset; | |||
import java.nio.file.Files; | |||
import java.nio.file.LinkOption; | |||
import java.nio.file.Path; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.apache.commons.lang.SystemUtils; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
@Immutable | |||
public abstract class AbstractProjectOrModule extends DefaultInputComponent { | |||
private static final Logger LOGGER = Loggers.get(AbstractProjectOrModule.class); | |||
private final Path baseDir; | |||
private final Path workDir; | |||
private final String name; | |||
private final String originalName; | |||
private final String description; | |||
private final String keyWithBranch; | |||
private final String branch; | |||
private final Map<String, String> properties; | |||
private final String key; | |||
private final ProjectDefinition definition; | |||
private final Charset encoding; | |||
public AbstractProjectOrModule(ProjectDefinition definition, int scannerComponentId) { | |||
super(scannerComponentId); | |||
this.baseDir = initBaseDir(definition); | |||
this.workDir = initWorkingDir(definition); | |||
this.name = definition.getName(); | |||
this.originalName = definition.getOriginalName(); | |||
this.description = definition.getDescription(); | |||
this.keyWithBranch = definition.getKeyWithBranch(); | |||
this.branch = definition.getBranch(); | |||
this.properties = Collections.unmodifiableMap(new HashMap<>(definition.properties())); | |||
this.definition = definition; | |||
this.key = definition.getKey(); | |||
this.encoding = initEncoding(definition); | |||
} | |||
private static Charset initEncoding(ProjectDefinition module) { | |||
String encodingStr = module.properties().get(CoreProperties.ENCODING_PROPERTY); | |||
Charset result; | |||
if (StringUtils.isNotEmpty(encodingStr)) { | |||
result = Charset.forName(StringUtils.trim(encodingStr)); | |||
} else { | |||
result = Charset.defaultCharset(); | |||
} | |||
return result; | |||
} | |||
private static Path initBaseDir(ProjectDefinition module) { | |||
Path result; | |||
try { | |||
result = module.getBaseDir().toPath().toRealPath(LinkOption.NOFOLLOW_LINKS); | |||
} catch (IOException e) { | |||
throw new IllegalStateException("Unable to resolve module baseDir", e); | |||
} | |||
return result; | |||
} | |||
private static Path initWorkingDir(ProjectDefinition module) { | |||
File workingDirAsFile = module.getWorkDir(); | |||
Path workingDir = workingDirAsFile.getAbsoluteFile().toPath().normalize(); | |||
if (SystemUtils.IS_OS_WINDOWS) { | |||
try { | |||
Files.createDirectories(workingDir); | |||
Files.setAttribute(workingDir, "dos:hidden", true, LinkOption.NOFOLLOW_LINKS); | |||
} catch (IOException e) { | |||
LOGGER.warn("Failed to set working directory hidden: {}", e.getMessage()); | |||
} | |||
} | |||
return workingDir; | |||
} | |||
/** | |||
* Module key without branch | |||
*/ | |||
@Override | |||
public String key() { | |||
return key; | |||
} | |||
@Override | |||
public boolean isFile() { | |||
return false; | |||
} | |||
public ProjectDefinition definition() { | |||
return definition; | |||
} | |||
public Path getBaseDir() { | |||
return baseDir; | |||
} | |||
public Path getWorkDir() { | |||
return workDir; | |||
} | |||
public String getKeyWithBranch() { | |||
return keyWithBranch; | |||
} | |||
@CheckForNull | |||
public String getBranch() { | |||
return branch; | |||
} | |||
public Map<String, String> properties() { | |||
return properties; | |||
} | |||
@CheckForNull | |||
public String getOriginalName() { | |||
return originalName; | |||
} | |||
public String getName() { | |||
return name; | |||
} | |||
public String getDescription() { | |||
return description; | |||
} | |||
public Charset getEncoding() { | |||
return encoding; | |||
} | |||
} |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -39,6 +39,9 @@ import org.sonar.api.batch.fs.InputDir; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.api.utils.PathUtils; | |||
import org.sonar.scanner.fs.predicates.DefaultFilePredicates; | |||
import org.sonar.scanner.fs.predicates.FileExtensionPredicate; | |||
import org.sonar.scanner.fs.predicates.OptimizedFilePredicateAdapter; | |||
/** | |||
* @since 4.2 |
@@ -0,0 +1,158 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.batch.fs.IndexedFile; | |||
import org.sonar.api.batch.fs.InputFile.Type; | |||
import org.sonar.api.utils.PathUtils; | |||
/** | |||
* @since 6.3 | |||
*/ | |||
@Immutable | |||
public class DefaultIndexedFile extends DefaultInputComponent implements IndexedFile { | |||
private final String projectRelativePath; | |||
private final String moduleRelativePath; | |||
private final String projectKey; | |||
private final String language; | |||
private final Type type; | |||
private final Path absolutePath; | |||
private final SensorStrategy sensorStrategy; | |||
/** | |||
* Testing purposes only! | |||
*/ | |||
public DefaultIndexedFile(String projectKey, Path baseDir, String relativePath, @Nullable String language) { | |||
this(baseDir.resolve(relativePath), projectKey, relativePath, relativePath, Type.MAIN, language, TestInputFileBuilder.nextBatchId(), | |||
new SensorStrategy()); | |||
} | |||
public DefaultIndexedFile(Path absolutePath, String projectKey, String projectRelativePath, String moduleRelativePath, Type type, @Nullable String language, int batchId, | |||
SensorStrategy sensorStrategy) { | |||
super(batchId); | |||
this.projectKey = projectKey; | |||
this.projectRelativePath = PathUtils.sanitize(projectRelativePath); | |||
this.moduleRelativePath = PathUtils.sanitize(moduleRelativePath); | |||
this.type = type; | |||
this.language = language; | |||
this.sensorStrategy = sensorStrategy; | |||
this.absolutePath = absolutePath; | |||
} | |||
@Override | |||
public String relativePath() { | |||
return sensorStrategy.isGlobal() ? projectRelativePath : moduleRelativePath; | |||
} | |||
public String getModuleRelativePath() { | |||
return moduleRelativePath; | |||
} | |||
public String getProjectRelativePath() { | |||
return projectRelativePath; | |||
} | |||
@Override | |||
public String absolutePath() { | |||
return PathUtils.sanitize(path().toString()); | |||
} | |||
@Override | |||
public File file() { | |||
return path().toFile(); | |||
} | |||
@Override | |||
public Path path() { | |||
return absolutePath; | |||
} | |||
@Override | |||
public InputStream inputStream() throws IOException { | |||
return Files.newInputStream(path()); | |||
} | |||
@CheckForNull | |||
@Override | |||
public String language() { | |||
return language; | |||
} | |||
@Override | |||
public Type type() { | |||
return type; | |||
} | |||
/** | |||
* Component key (without branch). | |||
*/ | |||
@Override | |||
public String key() { | |||
return new StringBuilder().append(projectKey).append(":").append(projectRelativePath).toString(); | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (!(o instanceof DefaultIndexedFile)) { | |||
return false; | |||
} | |||
DefaultIndexedFile that = (DefaultIndexedFile) o; | |||
return projectRelativePath.equals(that.projectRelativePath); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return projectRelativePath.hashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return projectRelativePath; | |||
} | |||
@Override | |||
public boolean isFile() { | |||
return true; | |||
} | |||
@Override | |||
public String filename() { | |||
return path().getFileName().toString(); | |||
} | |||
@Override | |||
public URI uri() { | |||
return path().toUri(); | |||
} | |||
} |
@@ -0,0 +1,72 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.util.HashSet; | |||
import java.util.Set; | |||
import org.sonar.api.batch.fs.InputComponent; | |||
import org.sonar.api.batch.measure.Metric; | |||
/** | |||
* @since 5.2 | |||
*/ | |||
public abstract class DefaultInputComponent implements InputComponent { | |||
private int id; | |||
private Set<String> storedMetricKeys = new HashSet<>(); | |||
public DefaultInputComponent(int scannerId) { | |||
this.id = scannerId; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || this.getClass() != o.getClass()) { | |||
return false; | |||
} | |||
DefaultInputComponent that = (DefaultInputComponent) o; | |||
return key().equals(that.key()); | |||
} | |||
public int scannerId() { | |||
return id; | |||
} | |||
@Override | |||
public int hashCode() { | |||
return key().hashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return "[key=" + key() + "]"; | |||
} | |||
public void setHasMeasureFor(Metric metric) { | |||
storedMetricKeys.add(metric.key()); | |||
} | |||
public boolean hasMeasureFor(Metric metric) { | |||
return storedMetricKeys.contains(metric.key()); | |||
} | |||
} |
@@ -0,0 +1,122 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.io.File; | |||
import java.net.URI; | |||
import java.nio.file.Path; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.InputDir; | |||
import org.sonar.api.utils.PathUtils; | |||
/** | |||
* @since 4.5 | |||
*/ | |||
public class DefaultInputDir extends DefaultInputComponent implements InputDir { | |||
private final String relativePath; | |||
private final String moduleKey; | |||
private Path moduleBaseDir; | |||
public DefaultInputDir(String moduleKey, String relativePath) { | |||
super(-1); | |||
this.moduleKey = moduleKey; | |||
this.relativePath = PathUtils.sanitize(relativePath); | |||
} | |||
@Override | |||
public String relativePath() { | |||
return relativePath; | |||
} | |||
@Override | |||
public String absolutePath() { | |||
return PathUtils.sanitize(path().toString()); | |||
} | |||
@Override | |||
public File file() { | |||
return path().toFile(); | |||
} | |||
@Override | |||
public Path path() { | |||
if (moduleBaseDir == null) { | |||
throw new IllegalStateException("Can not return the java.nio.file.Path because module baseDir is not set (see method setModuleBaseDir(java.io.File))"); | |||
} | |||
return moduleBaseDir.resolve(relativePath); | |||
} | |||
public String moduleKey() { | |||
return moduleKey; | |||
} | |||
@Override | |||
public String key() { | |||
StringBuilder sb = new StringBuilder().append(moduleKey).append(":"); | |||
if (StringUtils.isEmpty(relativePath)) { | |||
sb.append("/"); | |||
} else { | |||
sb.append(relativePath); | |||
} | |||
return sb.toString(); | |||
} | |||
/** | |||
* For testing purpose. Will be automatically set when dir is added to {@link DefaultFileSystem} | |||
*/ | |||
public DefaultInputDir setModuleBaseDir(Path moduleBaseDir) { | |||
this.moduleBaseDir = moduleBaseDir.normalize(); | |||
return this; | |||
} | |||
@Override | |||
public boolean isFile() { | |||
return false; | |||
} | |||
@Override | |||
public boolean equals(Object o) { | |||
if (this == o) { | |||
return true; | |||
} | |||
if (o == null || this.getClass() != o.getClass()) { | |||
return false; | |||
} | |||
DefaultInputDir that = (DefaultInputDir) o; | |||
return moduleKey.equals(that.moduleKey) && relativePath.equals(that.relativePath); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return moduleKey.hashCode() + relativePath.hashCode() * 13; | |||
} | |||
@Override | |||
public String toString() { | |||
return "[moduleKey=" + moduleKey + ", relative=" + relativePath + ", basedir=" + moduleBaseDir + "]"; | |||
} | |||
@Override | |||
public URI uri() { | |||
return path().toUri(); | |||
} | |||
} |
@@ -0,0 +1,440 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.net.URI; | |||
import java.nio.charset.Charset; | |||
import java.nio.file.Files; | |||
import java.nio.file.Path; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.BitSet; | |||
import java.util.Collection; | |||
import java.util.Optional; | |||
import java.util.Set; | |||
import java.util.function.Consumer; | |||
import java.util.stream.Collectors; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.apache.commons.io.ByteOrderMark; | |||
import org.apache.commons.io.input.BOMInputStream; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.TextPointer; | |||
import org.sonar.api.batch.fs.TextRange; | |||
import org.sonar.api.batch.fs.internal.Metadata; | |||
import static org.sonar.api.utils.Preconditions.checkArgument; | |||
import static org.sonar.api.utils.Preconditions.checkState; | |||
/** | |||
* @since 4.2 | |||
* To create {@link InputFile} in tests, use {@link TestInputFileBuilder}. | |||
*/ | |||
public class DefaultInputFile extends DefaultInputComponent implements InputFile { | |||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; | |||
private final DefaultIndexedFile indexedFile; | |||
private final String contents; | |||
private final Consumer<DefaultInputFile> metadataGenerator; | |||
private boolean published; | |||
private boolean excludedForCoverage; | |||
private boolean excludedForDuplication; | |||
private boolean ignoreAllIssues; | |||
// Lazy init to save memory | |||
private BitSet noSonarLines; | |||
private Status status; | |||
private Charset charset; | |||
private Metadata metadata; | |||
private Collection<int[]> ignoreIssuesOnlineRanges; | |||
private BitSet executableLines; | |||
public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator) { | |||
this(indexedFile, metadataGenerator, null); | |||
} | |||
// For testing | |||
public DefaultInputFile(DefaultIndexedFile indexedFile, Consumer<DefaultInputFile> metadataGenerator, @Nullable String contents) { | |||
super(indexedFile.scannerId()); | |||
this.indexedFile = indexedFile; | |||
this.metadataGenerator = metadataGenerator; | |||
this.metadata = null; | |||
this.published = false; | |||
this.excludedForCoverage = false; | |||
this.contents = contents; | |||
} | |||
public void checkMetadata() { | |||
if (metadata == null) { | |||
metadataGenerator.accept(this); | |||
} | |||
} | |||
@Override | |||
public InputStream inputStream() throws IOException { | |||
return contents != null ? new ByteArrayInputStream(contents.getBytes(charset())) | |||
: new BOMInputStream(Files.newInputStream(path()), | |||
ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE); | |||
} | |||
@Override | |||
public String contents() throws IOException { | |||
if (contents != null) { | |||
return contents; | |||
} else { | |||
ByteArrayOutputStream result = new ByteArrayOutputStream(); | |||
try (InputStream inputStream = inputStream()) { | |||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; | |||
int length; | |||
while ((length = inputStream.read(buffer)) != -1) { | |||
result.write(buffer, 0, length); | |||
} | |||
} | |||
return result.toString(charset().name()); | |||
} | |||
} | |||
public DefaultInputFile setPublished(boolean published) { | |||
this.published = published; | |||
return this; | |||
} | |||
public boolean isPublished() { | |||
return published; | |||
} | |||
public DefaultInputFile setExcludedForCoverage(boolean excludedForCoverage) { | |||
this.excludedForCoverage = excludedForCoverage; | |||
return this; | |||
} | |||
public boolean isExcludedForCoverage() { | |||
return excludedForCoverage; | |||
} | |||
public DefaultInputFile setExcludedForDuplication(boolean excludedForDuplication) { | |||
this.excludedForDuplication = excludedForDuplication; | |||
return this; | |||
} | |||
public boolean isExcludedForDuplication() { | |||
return excludedForDuplication; | |||
} | |||
/** | |||
* @deprecated since 6.6 | |||
*/ | |||
@Deprecated | |||
@Override | |||
public String relativePath() { | |||
return indexedFile.relativePath(); | |||
} | |||
public String getModuleRelativePath() { | |||
return indexedFile.getModuleRelativePath(); | |||
} | |||
public String getProjectRelativePath() { | |||
return indexedFile.getProjectRelativePath(); | |||
} | |||
@Override | |||
public String absolutePath() { | |||
return indexedFile.absolutePath(); | |||
} | |||
@Override | |||
public File file() { | |||
return indexedFile.file(); | |||
} | |||
@Override | |||
public Path path() { | |||
return indexedFile.path(); | |||
} | |||
@CheckForNull | |||
@Override | |||
public String language() { | |||
return indexedFile.language(); | |||
} | |||
@Override | |||
public Type type() { | |||
return indexedFile.type(); | |||
} | |||
/** | |||
* Component key (without branch). | |||
*/ | |||
@Override | |||
public String key() { | |||
return indexedFile.key(); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return indexedFile.hashCode(); | |||
} | |||
@Override | |||
public String toString() { | |||
return indexedFile.toString(); | |||
} | |||
/** | |||
* {@link #setStatus(Status)} | |||
*/ | |||
@Override | |||
public Status status() { | |||
checkMetadata(); | |||
return status; | |||
} | |||
@Override | |||
public int lines() { | |||
checkMetadata(); | |||
return metadata.lines(); | |||
} | |||
@Override | |||
public boolean isEmpty() { | |||
checkMetadata(); | |||
return metadata.isEmpty(); | |||
} | |||
@Override | |||
public Charset charset() { | |||
checkMetadata(); | |||
return charset; | |||
} | |||
public int lastValidOffset() { | |||
checkMetadata(); | |||
return metadata.lastValidOffset(); | |||
} | |||
/** | |||
* Digest hash of the file. | |||
*/ | |||
public String hash() { | |||
checkMetadata(); | |||
return metadata.hash(); | |||
} | |||
public int nonBlankLines() { | |||
checkMetadata(); | |||
return metadata.nonBlankLines(); | |||
} | |||
public int[] originalLineStartOffsets() { | |||
checkMetadata(); | |||
checkState(metadata.originalLineStartOffsets() != null, "InputFile is not properly initialized."); | |||
checkState(metadata.originalLineStartOffsets().length == metadata.lines(), | |||
"InputFile is not properly initialized. 'originalLineStartOffsets' property length should be equal to 'lines'"); | |||
return metadata.originalLineStartOffsets(); | |||
} | |||
public int[] originalLineEndOffsets() { | |||
checkMetadata(); | |||
checkState(metadata.originalLineEndOffsets() != null, "InputFile is not properly initialized."); | |||
checkState(metadata.originalLineEndOffsets().length == metadata.lines(), | |||
"InputFile is not properly initialized. 'originalLineEndOffsets' property length should be equal to 'lines'"); | |||
return metadata.originalLineEndOffsets(); | |||
} | |||
@Override | |||
public TextPointer newPointer(int line, int lineOffset) { | |||
checkMetadata(); | |||
DefaultTextPointer textPointer = new DefaultTextPointer(line, lineOffset); | |||
checkValid(textPointer, "pointer"); | |||
return textPointer; | |||
} | |||
@Override | |||
public TextRange newRange(TextPointer start, TextPointer end) { | |||
checkMetadata(); | |||
checkValid(start, "start pointer"); | |||
checkValid(end, "end pointer"); | |||
return newRangeValidPointers(start, end, false); | |||
} | |||
@Override | |||
public TextRange newRange(int startLine, int startLineOffset, int endLine, int endLineOffset) { | |||
checkMetadata(); | |||
TextPointer start = newPointer(startLine, startLineOffset); | |||
TextPointer end = newPointer(endLine, endLineOffset); | |||
return newRangeValidPointers(start, end, false); | |||
} | |||
@Override | |||
public TextRange selectLine(int line) { | |||
checkMetadata(); | |||
TextPointer startPointer = newPointer(line, 0); | |||
TextPointer endPointer = newPointer(line, lineLength(line)); | |||
return newRangeValidPointers(startPointer, endPointer, true); | |||
} | |||
public void validate(TextRange range) { | |||
checkMetadata(); | |||
checkValid(range.start(), "start pointer"); | |||
checkValid(range.end(), "end pointer"); | |||
} | |||
/** | |||
* Create Range from global offsets. Used for backward compatibility with older API. | |||
*/ | |||
public TextRange newRange(int startOffset, int endOffset) { | |||
checkMetadata(); | |||
return newRangeValidPointers(newPointer(startOffset), newPointer(endOffset), false); | |||
} | |||
public TextPointer newPointer(int globalOffset) { | |||
checkMetadata(); | |||
checkArgument(globalOffset >= 0, "%s is not a valid offset for a file", globalOffset); | |||
checkArgument(globalOffset <= lastValidOffset(), "%s is not a valid offset for file %s. Max offset is %s", globalOffset, this, lastValidOffset()); | |||
int line = findLine(globalOffset); | |||
int startLineOffset = originalLineStartOffsets()[line - 1]; | |||
// In case the global offset is between \r and \n, move the pointer to a valid location | |||
return new DefaultTextPointer(line, Math.min(globalOffset, originalLineEndOffsets()[line - 1]) - startLineOffset); | |||
} | |||
public DefaultInputFile setStatus(Status status) { | |||
this.status = status; | |||
return this; | |||
} | |||
public DefaultInputFile setCharset(Charset charset) { | |||
this.charset = charset; | |||
return this; | |||
} | |||
private void checkValid(TextPointer pointer, String owner) { | |||
checkArgument(pointer.line() >= 1, "%s is not a valid line for a file", pointer.line()); | |||
checkArgument(pointer.line() <= this.metadata.lines(), "%s is not a valid line for %s. File %s has %s line(s)", pointer.line(), owner, this, metadata.lines()); | |||
checkArgument(pointer.lineOffset() >= 0, "%s is not a valid line offset for a file", pointer.lineOffset()); | |||
int lineLength = lineLength(pointer.line()); | |||
checkArgument(pointer.lineOffset() <= lineLength, | |||
"%s is not a valid line offset for %s. File %s has %s character(s) at line %s", pointer.lineOffset(), owner, this, lineLength, pointer.line()); | |||
} | |||
private int lineLength(int line) { | |||
return originalLineEndOffsets()[line - 1] - originalLineStartOffsets()[line - 1]; | |||
} | |||
private static TextRange newRangeValidPointers(TextPointer start, TextPointer end, boolean acceptEmptyRange) { | |||
checkArgument(acceptEmptyRange ? (start.compareTo(end) <= 0) : (start.compareTo(end) < 0), | |||
"Start pointer %s should be before end pointer %s", start, end); | |||
return new DefaultTextRange(start, end); | |||
} | |||
private int findLine(int globalOffset) { | |||
return Math.abs(Arrays.binarySearch(originalLineStartOffsets(), globalOffset) + 1); | |||
} | |||
public DefaultInputFile setMetadata(Metadata metadata) { | |||
this.metadata = metadata; | |||
return this; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (obj == null) { | |||
return false; | |||
} | |||
if (this.getClass() != obj.getClass()) { | |||
return false; | |||
} | |||
DefaultInputFile that = (DefaultInputFile) obj; | |||
return this.getProjectRelativePath().equals(that.getProjectRelativePath()); | |||
} | |||
@Override | |||
public boolean isFile() { | |||
return true; | |||
} | |||
@Override | |||
public String filename() { | |||
return indexedFile.filename(); | |||
} | |||
@Override | |||
public URI uri() { | |||
return indexedFile.uri(); | |||
} | |||
public void noSonarAt(Set<Integer> noSonarLines) { | |||
if (this.noSonarLines == null) { | |||
this.noSonarLines = new BitSet(lines()); | |||
} | |||
noSonarLines.forEach(l -> this.noSonarLines.set(l - 1)); | |||
} | |||
public boolean hasNoSonarAt(int line) { | |||
if (this.noSonarLines == null) { | |||
return false; | |||
} | |||
return this.noSonarLines.get(line - 1); | |||
} | |||
public boolean isIgnoreAllIssues() { | |||
return ignoreAllIssues; | |||
} | |||
public void setIgnoreAllIssues(boolean ignoreAllIssues) { | |||
this.ignoreAllIssues = ignoreAllIssues; | |||
} | |||
public void addIgnoreIssuesOnLineRanges(Collection<int[]> lineRanges) { | |||
if (this.ignoreIssuesOnlineRanges == null) { | |||
this.ignoreIssuesOnlineRanges = new ArrayList<>(); | |||
} | |||
this.ignoreIssuesOnlineRanges.addAll(lineRanges); | |||
} | |||
public boolean isIgnoreAllIssuesOnLine(@Nullable Integer line) { | |||
if (line == null || ignoreIssuesOnlineRanges == null) { | |||
return false; | |||
} | |||
return ignoreIssuesOnlineRanges.stream().anyMatch(r -> r[0] <= line && line <= r[1]); | |||
} | |||
public void setExecutableLines(Set<Integer> executableLines) { | |||
checkState(this.executableLines == null, "Executable lines have already been saved for file: {}", this.toString()); | |||
this.executableLines = new BitSet(lines()); | |||
executableLines.forEach(l -> this.executableLines.set(l - 1)); | |||
} | |||
public Optional<Set<Integer>> getExecutableLines() { | |||
if (this.executableLines == null) { | |||
return Optional.empty(); | |||
} | |||
return Optional.of(this.executableLines.stream().map(i -> i + 1).boxed().collect(Collectors.toSet())); | |||
} | |||
} |
@@ -0,0 +1,81 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.io.File; | |||
import java.nio.file.Path; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import java.util.Optional; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.InputModule; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import static org.sonar.api.config.internal.MultivalueProperty.parseAsCsv; | |||
@Immutable | |||
public class DefaultInputModule extends AbstractProjectOrModule implements InputModule { | |||
private final List<Path> sourceDirsOrFiles; | |||
private final List<Path> testDirsOrFiles; | |||
/** | |||
* For testing only! | |||
*/ | |||
public DefaultInputModule(ProjectDefinition definition) { | |||
this(definition, 0); | |||
} | |||
public DefaultInputModule(ProjectDefinition definition, int scannerComponentId) { | |||
super(definition, scannerComponentId); | |||
this.sourceDirsOrFiles = initSources(definition, ProjectDefinition.SOURCES_PROPERTY); | |||
this.testDirsOrFiles = initSources(definition, ProjectDefinition.TESTS_PROPERTY); | |||
} | |||
@CheckForNull | |||
private List<Path> initSources(ProjectDefinition module, String propertyKey) { | |||
if (!module.properties().containsKey(propertyKey)) { | |||
return null; | |||
} | |||
List<Path> result = new ArrayList<>(); | |||
PathResolver pathResolver = new PathResolver(); | |||
String srcPropValue = module.properties().get(propertyKey); | |||
if (srcPropValue != null) { | |||
for (String sourcePath : parseAsCsv(propertyKey, srcPropValue)) { | |||
File dirOrFile = pathResolver.relativeFile(getBaseDir().toFile(), sourcePath); | |||
if (dirOrFile.exists()) { | |||
result.add(dirOrFile.toPath()); | |||
} | |||
} | |||
} | |||
return result; | |||
} | |||
public Optional<List<Path>> getSourceDirsOrFiles() { | |||
return Optional.ofNullable(sourceDirsOrFiles); | |||
} | |||
public Optional<List<Path>> getTestDirsOrFiles() { | |||
return Optional.ofNullable(testDirsOrFiles); | |||
} | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.scanner.fs.InputProject; | |||
@Immutable | |||
public class DefaultInputProject extends AbstractProjectOrModule implements InputProject { | |||
/** | |||
* For testing only! | |||
*/ | |||
public DefaultInputProject(ProjectDefinition definition) { | |||
super(definition, 0); | |||
} | |||
public DefaultInputProject(ProjectDefinition definition, int scannerComponentId) { | |||
super(definition, scannerComponentId); | |||
} | |||
} |
@@ -0,0 +1,74 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import org.sonar.api.batch.fs.TextPointer; | |||
/** | |||
* @since 5.2 | |||
*/ | |||
public class DefaultTextPointer implements TextPointer { | |||
private final int line; | |||
private final int lineOffset; | |||
public DefaultTextPointer(int line, int lineOffset) { | |||
this.line = line; | |||
this.lineOffset = lineOffset; | |||
} | |||
@Override | |||
public int line() { | |||
return line; | |||
} | |||
@Override | |||
public int lineOffset() { | |||
return lineOffset; | |||
} | |||
@Override | |||
public String toString() { | |||
return "[line=" + line + ", lineOffset=" + lineOffset + "]"; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof DefaultTextPointer)) { | |||
return false; | |||
} | |||
DefaultTextPointer other = (DefaultTextPointer) obj; | |||
return other.line == this.line && other.lineOffset == this.lineOffset; | |||
} | |||
@Override | |||
public int hashCode() { | |||
return 37 * this.line + lineOffset; | |||
} | |||
@Override | |||
public int compareTo(TextPointer o) { | |||
if (this.line == o.line()) { | |||
return Integer.compare(this.lineOffset, o.lineOffset()); | |||
} | |||
return Integer.compare(this.line, o.line()); | |||
} | |||
} |
@@ -0,0 +1,74 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import org.sonar.api.batch.fs.TextPointer; | |||
import org.sonar.api.batch.fs.TextRange; | |||
/** | |||
* @since 5.2 | |||
*/ | |||
public class DefaultTextRange implements TextRange { | |||
private final TextPointer start; | |||
private final TextPointer end; | |||
public DefaultTextRange(TextPointer start, TextPointer end) { | |||
this.start = start; | |||
this.end = end; | |||
} | |||
@Override | |||
public TextPointer start() { | |||
return start; | |||
} | |||
@Override | |||
public TextPointer end() { | |||
return end; | |||
} | |||
@Override | |||
public boolean overlap(TextRange another) { | |||
// [A,B] and [C,D] | |||
// B > C && D > A | |||
return this.end.compareTo(another.start()) > 0 && another.end().compareTo(this.start) > 0; | |||
} | |||
@Override | |||
public String toString() { | |||
return "Range[from " + start + " to " + end + "]"; | |||
} | |||
@Override | |||
public boolean equals(Object obj) { | |||
if (!(obj instanceof DefaultTextRange)) { | |||
return false; | |||
} | |||
DefaultTextRange other = (DefaultTextRange) obj; | |||
return start.equals(other.start) && end.equals(other.end); | |||
} | |||
@Override | |||
public int hashCode() { | |||
return start.hashCode() * 17 + end.hashCode(); | |||
} | |||
} |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs; | |||
import java.io.BufferedReader; | |||
import java.io.IOException; | |||
@@ -29,11 +29,12 @@ import java.nio.charset.StandardCharsets; | |||
import javax.annotation.Nullable; | |||
import javax.annotation.concurrent.Immutable; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.charhandler.CharHandler; | |||
import org.sonar.api.batch.fs.internal.charhandler.FileHashComputer; | |||
import org.sonar.api.batch.fs.internal.charhandler.LineCounter; | |||
import org.sonar.api.batch.fs.internal.charhandler.LineHashComputer; | |||
import org.sonar.api.batch.fs.internal.charhandler.LineOffsetCounter; | |||
import org.sonar.api.batch.fs.internal.Metadata; | |||
import org.sonar.scanner.fs.charhandler.CharHandler; | |||
import org.sonar.scanner.fs.charhandler.FileHashComputer; | |||
import org.sonar.scanner.fs.charhandler.LineCounter; | |||
import org.sonar.scanner.fs.charhandler.LineHashComputer; | |||
import org.sonar.scanner.fs.charhandler.LineOffsetCounter; | |||
/** | |||
* Computes hash of files. Ends of Lines are ignored, so files with |
@@ -0,0 +1,42 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.util.Collection; | |||
import javax.annotation.CheckForNull; | |||
import javax.annotation.concurrent.Immutable; | |||
@Immutable | |||
public interface InputModuleHierarchy { | |||
DefaultInputModule root(); | |||
boolean isRoot(DefaultInputModule module); | |||
Collection<DefaultInputModule> children(DefaultInputModule module); | |||
@CheckForNull | |||
DefaultInputModule parent(DefaultInputModule module); | |||
@CheckForNull | |||
String relativePath(DefaultInputModule module); | |||
@CheckForNull | |||
String relativePathToRoot(DefaultInputModule module); | |||
} |
@@ -0,0 +1,136 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import java.nio.file.Path; | |||
import javax.annotation.concurrent.ThreadSafe; | |||
import org.apache.commons.io.FilenameUtils; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.utils.PathUtils; | |||
import org.sonar.api.utils.WildcardPattern; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
@ThreadSafe | |||
public abstract class PathPattern { | |||
private static final Logger LOG = Loggers.get(PathPattern.class); | |||
/** | |||
* @deprecated since 6.6 | |||
*/ | |||
@Deprecated | |||
private static final String ABSOLUTE_PATH_PATTERN_PREFIX = "file:"; | |||
final WildcardPattern pattern; | |||
PathPattern(String pattern) { | |||
this.pattern = WildcardPattern.create(pattern); | |||
} | |||
public abstract boolean match(Path absolutePath, Path relativePath); | |||
public abstract boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension); | |||
public static PathPattern create(String s) { | |||
String trimmed = StringUtils.trim(s); | |||
if (StringUtils.startsWithIgnoreCase(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX)) { | |||
LOG.warn("Using absolute path pattern is deprecated. Please use relative path instead of '" + trimmed + "'"); | |||
return new AbsolutePathPattern(StringUtils.substring(trimmed, ABSOLUTE_PATH_PATTERN_PREFIX.length())); | |||
} | |||
return new RelativePathPattern(trimmed); | |||
} | |||
public static PathPattern[] create(String[] s) { | |||
PathPattern[] result = new PathPattern[s.length]; | |||
for (int i = 0; i < s.length; i++) { | |||
result[i] = create(s[i]); | |||
} | |||
return result; | |||
} | |||
/** | |||
* @deprecated since 6.6 | |||
*/ | |||
@Deprecated | |||
private static class AbsolutePathPattern extends PathPattern { | |||
private AbsolutePathPattern(String pattern) { | |||
super(pattern); | |||
} | |||
@Override | |||
public boolean match(Path absolutePath, Path relativePath) { | |||
return match(absolutePath, relativePath, true); | |||
} | |||
@Override | |||
public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) { | |||
String path = PathUtils.sanitize(absolutePath.toString()); | |||
if (!caseSensitiveFileExtension) { | |||
String extension = sanitizeExtension(FilenameUtils.getExtension(path)); | |||
if (StringUtils.isNotBlank(extension)) { | |||
path = StringUtils.removeEndIgnoreCase(path, extension); | |||
path = path + extension; | |||
} | |||
} | |||
return pattern.match(path); | |||
} | |||
@Override | |||
public String toString() { | |||
return ABSOLUTE_PATH_PATTERN_PREFIX + pattern.toString(); | |||
} | |||
} | |||
/** | |||
* Path relative to module basedir | |||
*/ | |||
private static class RelativePathPattern extends PathPattern { | |||
private RelativePathPattern(String pattern) { | |||
super(pattern); | |||
} | |||
@Override | |||
public boolean match(Path absolutePath, Path relativePath) { | |||
return match(absolutePath, relativePath, true); | |||
} | |||
@Override | |||
public boolean match(Path absolutePath, Path relativePath, boolean caseSensitiveFileExtension) { | |||
String path = PathUtils.sanitize(relativePath.toString()); | |||
if (!caseSensitiveFileExtension) { | |||
String extension = sanitizeExtension(FilenameUtils.getExtension(path)); | |||
if (StringUtils.isNotBlank(extension)) { | |||
path = StringUtils.removeEndIgnoreCase(path, extension); | |||
path = path + extension; | |||
} | |||
} | |||
return path != null && pattern.match(path); | |||
} | |||
@Override | |||
public String toString() { | |||
return pattern.toString(); | |||
} | |||
} | |||
static String sanitizeExtension(String suffix) { | |||
return StringUtils.lowerCase(StringUtils.removeStart(suffix, ".")); | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.fs; | |||
import org.sonar.api.batch.fs.InputFile; | |||
/** | |||
* A shared, mutable object in the project container. | |||
* It's used during the execution of sensors to decide whether | |||
* sensors should be executed once for the entire project, or per-module. | |||
* It is also injected into each InputFile to change the behavior of {@link InputFile#relativePath()} | |||
*/ | |||
public class SensorStrategy { | |||
private boolean global = true; | |||
public boolean isGlobal() { | |||
return global; | |||
} | |||
public void setGlobal(boolean global) { | |||
this.global = global; | |||
} | |||
} |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs; | |||
import java.io.File; | |||
import java.io.IOException; | |||
@@ -31,6 +31,7 @@ import javax.annotation.CheckForNull; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.Metadata; | |||
import org.sonar.api.utils.PathUtils; | |||
/** |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal.charhandler; | |||
package org.sonar.scanner.fs.charhandler; | |||
public abstract class CharHandler { | |||
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal.charhandler; | |||
package org.sonar.scanner.fs.charhandler; | |||
import java.nio.ByteBuffer; | |||
import java.nio.CharBuffer; | |||
@@ -26,7 +26,6 @@ import java.nio.charset.CharsetEncoder; | |||
import java.nio.charset.CodingErrorAction; | |||
import java.nio.charset.StandardCharsets; | |||
import java.security.MessageDigest; | |||
import org.apache.commons.codec.binary.Hex; | |||
import org.apache.commons.codec.digest.DigestUtils; | |||
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal.charhandler; | |||
package org.sonar.scanner.fs.charhandler; | |||
import java.util.Arrays; | |||
import java.util.Collection; |
@@ -17,10 +17,9 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal.charhandler; | |||
package org.sonar.scanner.fs.charhandler; | |||
import java.nio.charset.Charset; | |||
import org.sonar.api.CoreProperties; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal.charhandler; | |||
package org.sonar.scanner.fs.charhandler; | |||
import java.io.File; | |||
import java.nio.ByteBuffer; | |||
@@ -27,19 +27,18 @@ import java.nio.charset.CharsetEncoder; | |||
import java.nio.charset.CodingErrorAction; | |||
import java.nio.charset.StandardCharsets; | |||
import java.security.MessageDigest; | |||
import org.apache.commons.codec.digest.DigestUtils; | |||
import org.sonar.api.batch.fs.internal.FileMetadata.LineHashConsumer; | |||
import org.sonar.scanner.fs.FileMetadata; | |||
public class LineHashComputer extends CharHandler { | |||
private final MessageDigest lineMd5Digest = DigestUtils.getMd5Digest(); | |||
private final CharsetEncoder encoder; | |||
private final StringBuilder sb = new StringBuilder(); | |||
private final LineHashConsumer consumer; | |||
private final FileMetadata.LineHashConsumer consumer; | |||
private final File file; | |||
private int line = 1; | |||
public LineHashComputer(LineHashConsumer consumer, File f) { | |||
public LineHashComputer(FileMetadata.LineHashConsumer consumer, File f) { | |||
this.consumer = consumer; | |||
this.file = f; | |||
this.encoder = StandardCharsets.UTF_8.newEncoder() |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal.charhandler; | |||
package org.sonar.scanner.fs.charhandler; | |||
public class LineOffsetCounter extends CharHandler { | |||
private long currentOriginalLineStartOffset = 0; |
@@ -18,7 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.api.batch.fs.internal.charhandler; | |||
package org.sonar.scanner.fs.charhandler; | |||
import javax.annotation.ParametersAreNonnullByDefault; | |||
@@ -0,0 +1,24 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.scanner.fs; | |||
import javax.annotation.ParametersAreNonnullByDefault; | |||
@@ -17,17 +17,16 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
import org.sonar.api.batch.fs.FileSystem.Index; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.api.utils.PathUtils; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.io.File; | |||
import java.nio.file.Path; | |||
import java.util.Arrays; | |||
import java.util.Collections; | |||
import org.sonar.api.batch.fs.FileSystem.Index; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.scan.filesystem.PathResolver; | |||
import org.sonar.api.utils.PathUtils; | |||
/** | |||
* @since 4.2 |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.stream.StreamSupport; | |||
import org.sonar.api.batch.fs.FileSystem.Index; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.ArrayList; | |||
import java.util.Collection; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.io.File; | |||
import java.net.URI; | |||
@@ -30,9 +30,10 @@ import org.sonar.api.batch.fs.FilePredicate; | |||
import org.sonar.api.batch.fs.FilePredicates; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.InputFile.Status; | |||
import org.sonar.scanner.fs.PathPattern; | |||
/** | |||
* Factory of {@link org.sonar.api.batch.fs.FilePredicate} | |||
* Factory of {@link FilePredicate} | |||
* | |||
* @since 4.2 | |||
*/ |
@@ -17,14 +17,13 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.Collections; | |||
import org.sonar.api.batch.fs.FilePredicate; | |||
import org.sonar.api.batch.fs.FileSystem.Index; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import java.util.Collections; | |||
class FalsePredicate extends AbstractFilePredicate { | |||
static final FilePredicate FALSE = new FalsePredicate(); |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.Locale; | |||
import org.sonar.api.batch.fs.FileSystem; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import org.sonar.api.batch.fs.FileSystem; | |||
import org.sonar.api.batch.fs.InputFile; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import org.sonar.api.batch.fs.InputFile; | |||
@@ -17,12 +17,14 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import org.sonar.api.batch.fs.FilePredicate; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.scanner.fs.predicates.AbstractFilePredicate; | |||
import org.sonar.scanner.fs.predicates.OperatorPredicate; | |||
/** | |||
* @since 4.2 |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.List; | |||
import org.sonar.api.batch.fs.FilePredicate; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import org.sonar.api.batch.fs.FilePredicate; | |||
import org.sonar.api.batch.fs.FileSystem; |
@@ -17,12 +17,12 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import org.sonar.api.batch.fs.FilePredicate; | |||
import org.sonar.api.batch.fs.InputFile; | |||
class OptimizedFilePredicateAdapter extends AbstractFilePredicate { | |||
public class OptimizedFilePredicateAdapter extends AbstractFilePredicate { | |||
private FilePredicate unoptimizedPredicate; | |||
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.ArrayList; | |||
import java.util.Collection; |
@@ -17,10 +17,11 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.nio.file.Paths; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.scanner.fs.PathPattern; | |||
/** | |||
* @since 4.2 |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.util.Collections; | |||
import javax.annotation.Nullable; |
@@ -17,10 +17,11 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.scanner.fs.predicates.AbstractFilePredicate; | |||
/** | |||
* @deprecated since 7.8 |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import org.sonar.api.batch.fs.FilePredicate; | |||
import org.sonar.api.batch.fs.FileSystem.Index; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import org.sonar.api.batch.fs.InputFile; | |||
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.fs.internal; | |||
package org.sonar.scanner.fs.predicates; | |||
import java.net.URI; | |||
import java.nio.file.Path; |
@@ -0,0 +1,122 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.issue; | |||
import java.nio.file.Path; | |||
import java.util.ArrayList; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Objects; | |||
import java.util.Optional; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.batch.fs.InputComponent; | |||
import org.sonar.api.batch.fs.internal.DefaultInputDir; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.api.batch.sensor.internal.DefaultStorable; | |||
import org.sonar.api.batch.sensor.internal.SensorStorage; | |||
import org.sonar.api.batch.sensor.issue.Issue.Flow; | |||
import org.sonar.api.batch.sensor.issue.IssueLocation; | |||
import org.sonar.api.batch.sensor.issue.NewIssueLocation; | |||
import org.sonar.api.utils.PathUtils; | |||
import static java.util.Collections.unmodifiableList; | |||
import static java.util.stream.Collectors.toList; | |||
import static org.sonar.api.utils.Preconditions.checkArgument; | |||
import static org.sonar.api.utils.Preconditions.checkState; | |||
public abstract class AbstractDefaultIssue<T extends AbstractDefaultIssue> extends DefaultStorable { | |||
protected IssueLocation primaryLocation; | |||
protected List<List<IssueLocation>> flows = new ArrayList<>(); | |||
protected DefaultInputProject project; | |||
protected AbstractDefaultIssue(DefaultInputProject project) { | |||
this(project, null); | |||
} | |||
public AbstractDefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) { | |||
super(storage); | |||
this.project = project; | |||
} | |||
public IssueLocation primaryLocation() { | |||
return primaryLocation; | |||
} | |||
public List<Flow> flows() { | |||
return this.flows.stream() | |||
.<Flow>map(l -> () -> unmodifiableList(new ArrayList<>(l))) | |||
.collect(toList()); | |||
} | |||
public NewIssueLocation newLocation() { | |||
return new DefaultIssueLocation(); | |||
} | |||
public T at(NewIssueLocation primaryLocation) { | |||
checkArgument(primaryLocation != null, "Cannot use a location that is null"); | |||
checkState(this.primaryLocation == null, "at() already called"); | |||
this.primaryLocation = rewriteLocation((DefaultIssueLocation) primaryLocation); | |||
checkArgument(this.primaryLocation.inputComponent() != null, "Cannot use a location with no input component"); | |||
return (T) this; | |||
} | |||
public T addLocation(NewIssueLocation secondaryLocation) { | |||
flows.add(Collections.singletonList(rewriteLocation((DefaultIssueLocation) secondaryLocation))); | |||
return (T) this; | |||
} | |||
public T addFlow(Iterable<NewIssueLocation> locations) { | |||
List<IssueLocation> flowAsList = new ArrayList<>(); | |||
for (NewIssueLocation issueLocation : locations) { | |||
flowAsList.add(rewriteLocation((DefaultIssueLocation) issueLocation)); | |||
} | |||
flows.add(flowAsList); | |||
return (T) this; | |||
} | |||
private DefaultIssueLocation rewriteLocation(DefaultIssueLocation location) { | |||
InputComponent component = location.inputComponent(); | |||
Optional<Path> dirOrModulePath = Optional.empty(); | |||
if (component instanceof DefaultInputDir) { | |||
DefaultInputDir dirComponent = (DefaultInputDir) component; | |||
dirOrModulePath = Optional.of(project.getBaseDir().relativize(dirComponent.path())); | |||
} else if (component instanceof DefaultInputModule && !Objects.equals(project.key(), component.key())) { | |||
DefaultInputModule moduleComponent = (DefaultInputModule) component; | |||
dirOrModulePath = Optional.of(project.getBaseDir().relativize(moduleComponent.getBaseDir())); | |||
} | |||
if (dirOrModulePath.isPresent()) { | |||
String path = PathUtils.sanitize(dirOrModulePath.get().toString()); | |||
DefaultIssueLocation fixedLocation = new DefaultIssueLocation(); | |||
fixedLocation.on(project); | |||
StringBuilder fullMessage = new StringBuilder(); | |||
if (path != null && !path.isEmpty()) { | |||
fullMessage.append("[").append(path).append("] "); | |||
} | |||
fullMessage.append(location.message()); | |||
fixedLocation.message(fullMessage.toString()); | |||
return fixedLocation; | |||
} else { | |||
return location; | |||
} | |||
} | |||
} |
@@ -0,0 +1,93 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.issue; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.api.batch.rule.Severity; | |||
import org.sonar.api.batch.sensor.internal.SensorStorage; | |||
import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.issue.IssueLocation; | |||
import org.sonar.api.batch.sensor.issue.NewIssue; | |||
import org.sonar.api.rule.RuleKey; | |||
import static java.lang.String.format; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.sonar.api.utils.Preconditions.checkArgument; | |||
import static org.sonar.api.utils.Preconditions.checkState; | |||
public class DefaultIssue extends AbstractDefaultIssue<DefaultIssue> implements Issue, NewIssue { | |||
private RuleKey ruleKey; | |||
private Double gap; | |||
private Severity overriddenSeverity; | |||
public DefaultIssue(DefaultInputProject project) { | |||
this(project, null); | |||
} | |||
public DefaultIssue(DefaultInputProject project, @Nullable SensorStorage storage) { | |||
super(project, storage); | |||
} | |||
public DefaultIssue forRule(RuleKey ruleKey) { | |||
this.ruleKey = ruleKey; | |||
return this; | |||
} | |||
public RuleKey ruleKey() { | |||
return this.ruleKey; | |||
} | |||
@Override | |||
public DefaultIssue gap(@Nullable Double gap) { | |||
checkArgument(gap == null || gap >= 0, format("Gap must be greater than or equal 0 (got %s)", gap)); | |||
this.gap = gap; | |||
return this; | |||
} | |||
@Override | |||
public DefaultIssue overrideSeverity(@Nullable Severity severity) { | |||
this.overriddenSeverity = severity; | |||
return this; | |||
} | |||
@Override | |||
public Severity overriddenSeverity() { | |||
return this.overriddenSeverity; | |||
} | |||
@Override | |||
public Double gap() { | |||
return this.gap; | |||
} | |||
@Override | |||
public IssueLocation primaryLocation() { | |||
return primaryLocation; | |||
} | |||
@Override | |||
public void doSave() { | |||
requireNonNull(this.ruleKey, "ruleKey is mandatory on issue"); | |||
checkState(primaryLocation != null, "Primary location is mandatory on every issue"); | |||
storage.store(this); | |||
} | |||
} |
@@ -0,0 +1,92 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.scanner.issue; | |||
import javax.annotation.Nullable; | |||
import org.sonar.api.batch.fs.InputComponent; | |||
import org.sonar.api.batch.fs.TextRange; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.sensor.issue.IssueLocation; | |||
import org.sonar.api.batch.sensor.issue.NewIssueLocation; | |||
import static java.util.Objects.requireNonNull; | |||
import static org.apache.commons.lang.StringUtils.abbreviate; | |||
import static org.apache.commons.lang.StringUtils.trim; | |||
import static org.sonar.api.utils.Preconditions.checkArgument; | |||
import static org.sonar.api.utils.Preconditions.checkState; | |||
public class DefaultIssueLocation implements NewIssueLocation, IssueLocation { | |||
private InputComponent component; | |||
private TextRange textRange; | |||
private String message; | |||
@Override | |||
public DefaultIssueLocation on(InputComponent component) { | |||
checkArgument(component != null, "Component can't be null"); | |||
checkState(this.component == null, "on() already called"); | |||
this.component = component; | |||
return this; | |||
} | |||
@Override | |||
public DefaultIssueLocation at(TextRange location) { | |||
checkState(this.component != null, "at() should be called after on()"); | |||
checkState(this.component.isFile(), "at() should be called only for an InputFile."); | |||
DefaultInputFile file = (DefaultInputFile) this.component; | |||
file.validate(location); | |||
this.textRange = location; | |||
return this; | |||
} | |||
@Override | |||
public DefaultIssueLocation message(String message) { | |||
requireNonNull(message, "Message can't be null"); | |||
if (message.contains("\u0000")) { | |||
throw new IllegalArgumentException(unsupportedCharacterError(message, component)); | |||
} | |||
this.message = abbreviate(trim(message), MESSAGE_MAX_SIZE); | |||
return this; | |||
} | |||
private static String unsupportedCharacterError(String message, @Nullable InputComponent component) { | |||
String error = "Character \\u0000 is not supported in issue message '" + message + "'"; | |||
if (component != null) { | |||
error += ", on component: " + component.toString(); | |||
} | |||
return error; | |||
} | |||
@Override | |||
public InputComponent inputComponent() { | |||
return this.component; | |||
} | |||
@Override | |||
public TextRange textRange() { | |||
return textRange; | |||
} | |||
@Override | |||
public String message() { | |||
return this.message; | |||
} | |||
} |
@@ -24,10 +24,10 @@ import java.util.List; | |||
import javax.annotation.CheckForNull; | |||
import org.apache.commons.lang.StringUtils; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.fs.internal.charhandler.CharHandler; | |||
import org.sonar.api.notifications.AnalysisWarnings; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.scanner.fs.charhandler.CharHandler; | |||
import org.sonar.scanner.issue.ignore.IgnoreIssuesFilter; | |||
import org.sonar.scanner.issue.ignore.pattern.BlockIssuePattern; | |||
import org.sonar.scanner.issue.ignore.pattern.IssueExclusionPatternInitializer; |
@@ -26,9 +26,9 @@ import java.util.Set; | |||
import java.util.regex.Pattern; | |||
import java.util.stream.Collectors; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.fs.internal.charhandler.CharHandler; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.scanner.fs.charhandler.CharHandler; | |||
import org.sonar.scanner.issue.ignore.pattern.LineRange; | |||
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader.DoubleRegexpMatcher; | |||
@@ -24,7 +24,6 @@ import javax.annotation.Nullable; | |||
import org.sonar.api.SonarEdition; | |||
import org.sonar.api.SonarRuntime; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.FileMetadata; | |||
import org.sonar.api.batch.fs.internal.InputModuleHierarchy; | |||
import org.sonar.api.batch.fs.internal.SensorStrategy; | |||
import org.sonar.api.batch.rule.CheckFactory; | |||
@@ -67,6 +66,7 @@ import org.sonar.scanner.cpd.CpdSettings; | |||
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex; | |||
import org.sonar.scanner.deprecated.test.TestPlanBuilder; | |||
import org.sonar.scanner.deprecated.test.TestableBuilder; | |||
import org.sonar.scanner.fs.FileMetadata; | |||
import org.sonar.scanner.issue.IssueFilters; | |||
import org.sonar.scanner.issue.IssuePublisher; | |||
import org.sonar.scanner.issue.ignore.EnforceIssuesFilter; |
@@ -20,7 +20,7 @@ | |||
package org.sonar.scanner.scan.filesystem; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.AbstractFilePredicate; | |||
import org.sonar.scanner.fs.predicates.AbstractFilePredicate; | |||
/** | |||
* Additional {@link org.sonar.api.batch.fs.FilePredicate}s that are |
@@ -20,8 +20,8 @@ | |||
package org.sonar.scanner.scan.filesystem; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import org.sonar.api.batch.fs.internal.DefaultFileSystem; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.scanner.fs.DefaultFileSystem; | |||
public class DefaultModuleFileSystem extends DefaultFileSystem { | |||
@@ -20,8 +20,8 @@ | |||
package org.sonar.scanner.scan.filesystem; | |||
import com.google.common.annotations.VisibleForTesting; | |||
import org.sonar.api.batch.fs.internal.DefaultFileSystem; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
import org.sonar.scanner.fs.DefaultFileSystem; | |||
public class DefaultProjectFileSystem extends DefaultFileSystem { | |||
@@ -35,10 +35,10 @@ import java.util.stream.Stream; | |||
import javax.annotation.CheckForNull; | |||
import org.sonar.api.batch.fs.InputComponent; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultFileSystem; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.FileExtensionPredicate; | |||
import org.sonar.scanner.fs.DefaultFileSystem; | |||
import org.sonar.scanner.fs.predicates.FileExtensionPredicate; | |||
import org.sonar.scanner.scan.branch.BranchConfiguration; | |||
/** |
@@ -24,10 +24,10 @@ import java.io.InputStream; | |||
import java.nio.charset.Charset; | |||
import org.sonar.api.batch.fs.InputFile.Type; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.fs.internal.FileMetadata; | |||
import org.sonar.api.batch.fs.internal.Metadata; | |||
import org.sonar.api.utils.log.Logger; | |||
import org.sonar.api.utils.log.Loggers; | |||
import org.sonar.scanner.fs.FileMetadata; | |||
import org.sonar.scanner.issue.ignore.scanner.IssueExclusionsLoader; | |||
public class MetadataGenerator { |
@@ -23,8 +23,8 @@ import java.util.SortedSet; | |||
import org.sonar.api.batch.ScannerSide; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.InputModule; | |||
import org.sonar.api.batch.fs.internal.DefaultFileSystem; | |||
import org.sonar.api.batch.fs.internal.SensorStrategy; | |||
import org.sonar.scanner.fs.DefaultFileSystem; | |||
@ScannerSide | |||
public class ModuleInputComponentStore extends DefaultFileSystem.Cache { |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.sensor.internal; | |||
package org.sonar.scanner.sensor; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
@@ -30,6 +30,7 @@ import org.sonar.api.batch.sensor.coverage.internal.DefaultCoverage; | |||
import org.sonar.api.batch.sensor.cpd.internal.DefaultCpdTokens; | |||
import org.sonar.api.batch.sensor.error.AnalysisError; | |||
import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; | |||
import org.sonar.api.batch.sensor.internal.SensorStorage; | |||
import org.sonar.api.batch.sensor.issue.ExternalIssue; | |||
import org.sonar.api.batch.sensor.issue.Issue; | |||
import org.sonar.api.batch.sensor.issue.internal.DefaultExternalIssue; |
@@ -17,7 +17,7 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.api.batch.sensor.internal; | |||
package org.sonar.scanner.sensor; | |||
import java.io.File; | |||
import java.io.Serializable; | |||
@@ -39,7 +39,6 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.fs.InputModule; | |||
import org.sonar.api.batch.fs.TextRange; | |||
import org.sonar.api.batch.fs.internal.DefaultFileSystem; | |||
import org.sonar.api.batch.fs.internal.DefaultInputFile; | |||
import org.sonar.api.batch.fs.internal.DefaultInputModule; | |||
import org.sonar.api.batch.fs.internal.DefaultInputProject; | |||
@@ -86,6 +85,7 @@ import org.sonar.api.measures.Metric; | |||
import org.sonar.api.scanner.fs.InputProject; | |||
import org.sonar.api.utils.System2; | |||
import org.sonar.api.utils.Version; | |||
import org.sonar.scanner.fs.DefaultFileSystem; | |||
import static java.util.Collections.unmodifiableMap; | |||