org.sonar.scanner.scan.filesystem.InputComponentStore Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sonar-scanner-engine Show documentation
Show all versions of sonar-scanner-engine Show documentation
Open source platform for continuous inspection of code quality
/*
* SonarQube
* Copyright (C) 2009-2023 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.scan.filesystem;
import com.google.common.collect.ImmutableMap;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import javax.annotation.CheckForNull;
import org.sonar.api.SonarEdition;
import org.sonar.api.SonarRuntime;
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.predicates.FileExtensionPredicate;
import org.sonar.core.language.UnanalyzedLanguages;
import org.sonar.scanner.scan.branch.BranchConfiguration;
import static org.sonar.api.utils.Preconditions.checkNotNull;
import static org.sonar.api.utils.Preconditions.checkState;
/**
* Store of all files and dirs. Inclusion and
* exclusion patterns are already applied.
*/
public class InputComponentStore extends DefaultFileSystem.Cache {
private static final Map FILE_PATTERN_BY_LANGUAGE = ImmutableMap.of(
UnanalyzedLanguages.C, Pattern.compile(".*\\.c", Pattern.CASE_INSENSITIVE),
UnanalyzedLanguages.CPP, Pattern.compile(".*\\.cpp|.*\\.cc|.*\\.cxx|.*\\.c\\+\\+", Pattern.CASE_INSENSITIVE));
private final SortedSet globalLanguagesCache = new TreeSet<>();
private final Map> languagesCache = new HashMap<>();
private final Map globalInputFileCache = new HashMap<>();
private final Map> inputFileByModuleCache = new LinkedHashMap<>();
private final Map inputModuleKeyByFileCache = new HashMap<>();
private final Map inputModuleCache = new HashMap<>();
private final Map inputComponents = new HashMap<>();
private final Map> filesByNameCache = new HashMap<>();
private final Map> filesByExtensionCache = new HashMap<>();
private final BranchConfiguration branchConfiguration;
private final SonarRuntime sonarRuntime;
private final Map notAnalysedFilesByLanguage = new HashMap<>();
public InputComponentStore(BranchConfiguration branchConfiguration, SonarRuntime sonarRuntime) {
this.branchConfiguration = branchConfiguration;
this.sonarRuntime = sonarRuntime;
}
public Collection all() {
return inputComponents.values();
}
private Stream allFilesToPublishStream() {
return globalInputFileCache.values().stream()
.map(f -> (DefaultInputFile) f)
.filter(DefaultInputFile::isPublished);
}
public Iterable allFilesToPublish() {
return allFilesToPublishStream()::iterator;
}
public Iterable allChangedFilesToPublish() {
return allFilesToPublishStream()
.filter(f -> !branchConfiguration.isPullRequest() || f.status() != InputFile.Status.SAME)::iterator;
}
@Override
public Collection inputFiles() {
return globalInputFileCache.values();
}
public InputComponent getByKey(String key) {
return inputComponents.get(key);
}
public Iterable filesByModule(String moduleKey) {
return inputFileByModuleCache.getOrDefault(moduleKey, Collections.emptyMap()).values();
}
public InputComponentStore put(String moduleKey, InputFile inputFile) {
DefaultInputFile file = (DefaultInputFile) inputFile;
updateNotAnalysedCAndCppFileCount(file);
addToLanguageCache(moduleKey, file);
inputFileByModuleCache.computeIfAbsent(moduleKey, x -> new HashMap<>()).put(file.getModuleRelativePath(), inputFile);
inputModuleKeyByFileCache.put(inputFile, moduleKey);
globalInputFileCache.put(file.getProjectRelativePath(), inputFile);
inputComponents.put(inputFile.key(), inputFile);
filesByNameCache.computeIfAbsent(inputFile.filename(), x -> new LinkedHashSet<>()).add(inputFile);
filesByExtensionCache.computeIfAbsent(FileExtensionPredicate.getExtension(inputFile), x -> new LinkedHashSet<>()).add(inputFile);
return this;
}
private void addToLanguageCache(String moduleKey, DefaultInputFile inputFile) {
String language = inputFile.language();
if (language != null) {
globalLanguagesCache.add(language);
languagesCache.computeIfAbsent(moduleKey, k -> new TreeSet<>()).add(language);
}
}
@CheckForNull
public InputFile getFile(String moduleKey, String relativePath) {
return inputFileByModuleCache.getOrDefault(moduleKey, Collections.emptyMap())
.get(relativePath);
}
@Override
@CheckForNull
public InputFile inputFile(String relativePath) {
return globalInputFileCache.get(relativePath);
}
public DefaultInputModule findModule(DefaultInputFile file) {
return Optional.ofNullable(inputModuleKeyByFileCache.get(file)).map(inputModuleCache::get)
.orElseThrow(() -> new IllegalStateException("No modules for file '" + file.toString() + "'"));
}
public void put(DefaultInputModule inputModule) {
String key = inputModule.key();
checkNotNull(inputModule);
checkState(!inputComponents.containsKey(key), "Module '%s' already indexed", key);
checkState(!inputModuleCache.containsKey(key), "Module '%s' already indexed", key);
inputComponents.put(key, inputModule);
inputModuleCache.put(key, inputModule);
}
@Override
public Iterable getFilesByName(String filename) {
return filesByNameCache.getOrDefault(filename, Collections.emptySet());
}
@Override
public Iterable getFilesByExtension(String extension) {
return filesByExtensionCache.getOrDefault(extension, Collections.emptySet());
}
@Override
public SortedSet languages() {
return globalLanguagesCache;
}
public SortedSet languages(String moduleKey) {
return languagesCache.getOrDefault(moduleKey, Collections.emptySortedSet());
}
public Collection allModules() {
return inputModuleCache.values();
}
@Override
protected void doAdd(InputFile inputFile) {
throw new UnsupportedOperationException();
}
private void updateNotAnalysedCAndCppFileCount(DefaultInputFile inputFile) {
if (!SonarEdition.COMMUNITY.equals(sonarRuntime.getEdition())) {
return;
}
FILE_PATTERN_BY_LANGUAGE.forEach((language, filePattern) -> {
if (filePattern.matcher(inputFile.filename()).matches()) {
notAnalysedFilesByLanguage.put(language.toString(), notAnalysedFilesByLanguage.getOrDefault(language.toString(), 0) + 1);
}
});
}
public Map getNotAnalysedFilesByLanguage() {
return ImmutableMap.copyOf(notAnalysedFilesByLanguage);
}
}