3 * Copyright (C) 2009-2023 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.ce.task.projectanalysis.component;
22 import java.util.HashSet;
23 import java.util.Optional;
25 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
26 import org.sonar.ce.task.projectanalysis.source.SourceHashRepository;
27 import org.sonar.db.source.FileHashesDto;
29 import static com.google.common.base.Preconditions.checkState;
30 import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER;
32 public class FileStatusesImpl implements FileStatuses {
33 private final PreviousSourceHashRepository previousSourceHashRepository;
34 private final SourceHashRepository sourceHashRepository;
35 private final AnalysisMetadataHolder analysisMetadataHolder;
36 private final TreeRootHolder treeRootHolder;
37 private Set<String> fileUuidsMarkedAsUnchanged;
39 public FileStatusesImpl(AnalysisMetadataHolder analysisMetadataHolder, TreeRootHolder treeRootHolder, PreviousSourceHashRepository previousSourceHashRepository,
40 SourceHashRepository sourceHashRepository) {
41 this.analysisMetadataHolder = analysisMetadataHolder;
42 this.treeRootHolder = treeRootHolder;
43 this.previousSourceHashRepository = previousSourceHashRepository;
44 this.sourceHashRepository = sourceHashRepository;
47 public void initialize() {
48 fileUuidsMarkedAsUnchanged = new HashSet<>();
49 if (!analysisMetadataHolder.isPullRequest() && !analysisMetadataHolder.isFirstAnalysis()) {
50 new DepthTraversalTypeAwareCrawler(new Visitor()).visit(treeRootHolder.getRoot());
54 private class Visitor extends TypeAwareVisitorAdapter {
55 private boolean canTrustUnchangedFlags = true;
58 super(CrawlerDepthLimit.FILE, PRE_ORDER);
62 public void visitFile(Component file) {
63 if (file.getStatus() != Component.Status.SAME || !canTrustUnchangedFlags) {
67 canTrustUnchangedFlags = hashEquals(file);
68 if (canTrustUnchangedFlags) {
69 if (file.getFileAttributes().isMarkedAsUnchanged()) {
70 fileUuidsMarkedAsUnchanged.add(file.getUuid());
73 fileUuidsMarkedAsUnchanged.clear();
79 public boolean isUnchanged(Component component) {
80 failIfNotInitialized();
81 return component.getStatus() == Component.Status.SAME && hashEquals(component);
85 public boolean isDataUnchanged(Component component) {
86 failIfNotInitialized();
87 return fileUuidsMarkedAsUnchanged.contains(component.getUuid());
90 private boolean hashEquals(Component component) {
91 Optional<String> dbHash = previousSourceHashRepository.getDbFile(component).map(FileHashesDto::getSrcHash);
92 return dbHash.map(hash -> hash.equals(sourceHashRepository.getRawSourceHash(component))).orElse(false);
95 private void failIfNotInitialized() {
96 checkState(fileUuidsMarkedAsUnchanged != null, "Not initialized");