3 * Copyright (C) 2009-2022 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.api.utils.log.Logger;
26 import org.sonar.api.utils.log.Loggers;
27 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolder;
28 import org.sonar.ce.task.projectanalysis.source.SourceHashRepository;
29 import org.sonar.db.source.FileHashesDto;
31 import static com.google.common.base.Preconditions.checkState;
32 import static org.sonar.ce.task.projectanalysis.component.ComponentVisitor.Order.PRE_ORDER;
34 public class FileStatusesImpl implements FileStatuses {
35 private static final Logger LOG = Loggers.get(FileStatusesImpl.class);
37 private final PreviousSourceHashRepository previousSourceHashRepository;
38 private final SourceHashRepository sourceHashRepository;
39 private final AnalysisMetadataHolder analysisMetadataHolder;
40 private final TreeRootHolder treeRootHolder;
41 private Set<String> fileUuidsMarkedAsUnchanged;
42 private int notMarkedAsUnchanged = 0;
44 public FileStatusesImpl(AnalysisMetadataHolder analysisMetadataHolder, TreeRootHolder treeRootHolder, PreviousSourceHashRepository previousSourceHashRepository,
45 SourceHashRepository sourceHashRepository) {
46 this.analysisMetadataHolder = analysisMetadataHolder;
47 this.treeRootHolder = treeRootHolder;
48 this.previousSourceHashRepository = previousSourceHashRepository;
49 this.sourceHashRepository = sourceHashRepository;
52 public void initialize() {
53 fileUuidsMarkedAsUnchanged = new HashSet<>();
54 if (!analysisMetadataHolder.isPullRequest() && !analysisMetadataHolder.isFirstAnalysis()) {
55 new DepthTraversalTypeAwareCrawler(new Visitor()).visit(treeRootHolder.getRoot());
57 LOG.warn("FILES MARKED AS UNCHANGED: " + fileUuidsMarkedAsUnchanged.size());
58 LOG.warn("FILES NOT MARKED AS UNCHANGED: " + notMarkedAsUnchanged);
61 private class Visitor extends TypeAwareVisitorAdapter {
62 private boolean canTrustUnchangedFlags = true;
65 super(CrawlerDepthLimit.FILE, PRE_ORDER);
69 public void visitFile(Component file) {
70 if (file.getStatus() != Component.Status.SAME || !canTrustUnchangedFlags) {
74 canTrustUnchangedFlags = hashEquals(file);
75 if (canTrustUnchangedFlags) {
76 if (file.getFileAttributes().isMarkedAsUnchanged()) {
77 fileUuidsMarkedAsUnchanged.add(file.getUuid());
79 notMarkedAsUnchanged++;
82 LOG.error("FILE HAS DIFFERENT HASH: " + file.getName());
83 fileUuidsMarkedAsUnchanged.clear();
89 public boolean isUnchanged(Component component) {
90 failIfNotInitialized();
91 return component.getStatus() == Component.Status.SAME && hashEquals(component);
95 public boolean isDataUnchanged(Component component) {
96 failIfNotInitialized();
97 return fileUuidsMarkedAsUnchanged.contains(component.getUuid());
100 private boolean hashEquals(Component component) {
101 Optional<String> dbHash = previousSourceHashRepository.getDbFile(component).map(FileHashesDto::getSrcHash);
102 return dbHash.map(hash -> hash.equals(sourceHashRepository.getRawSourceHash(component))).orElse(false);
105 private void failIfNotInitialized() {
106 checkState(fileUuidsMarkedAsUnchanged != null, "Not initialized");