/* * SonarLint for Eclipse * Copyright (C) 2015-2017 SonarSource SA * sonarlint@sonarsource.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.sonarlint.eclipse.core.internal.jobs; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.eclipse.core.resources.WorkspaceJob; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.sonarlint.eclipse.core.SonarLintLogger; import org.sonarlint.eclipse.core.internal.SonarLintCorePlugin; import org.sonarlint.eclipse.core.internal.TriggerType; import org.sonarlint.eclipse.core.internal.jobs.AnalyzeProjectRequest.FileWithDocument; import org.sonarlint.eclipse.core.internal.resources.DefaultSonarLintProjectAdapter; import org.sonarlint.eclipse.core.internal.resources.ProjectsProviderUtils; import org.sonarlint.eclipse.core.resource.ISonarLintFile; import org.sonarlint.eclipse.core.resource.ISonarLintProject; public class AnalyzeChangedFilesJob extends WorkspaceJob { private static final String UNABLE_TO_ANALYZE_CHANGED_FILES = "Unable to analyze changed files"; private final Collection<ISonarLintProject> projects; public AnalyzeChangedFilesJob(Collection<ISonarLintProject> projects) { super("Analyze changeset"); this.projects = projects; } @Override public IStatus runInWorkspace(IProgressMonitor monitor) { SubMonitor global = SubMonitor.convert(monitor, 100); try { global.setTaskName("Collect changed file(s) list"); ProjectsProviderUtils.allProjects().stream() .filter(ISonarLintProject::isOpen) .forEach(p -> p.deleteAllMarkers(SonarLintCorePlugin.MARKER_CHANGESET_ID)); Collection<ISonarLintFile> collectChangedFiles = collectChangedFiles(projects, global.newChild(20)); if (collectChangedFiles.isEmpty()) { SonarLintLogger.get().info("No changed files found"); return Status.OK_STATUS; } Map<ISonarLintProject, List<ISonarLintFile>> changedFilesPerProject = collectChangedFiles.stream().collect(Collectors.groupingBy(ISonarLintFile::getProject)); long fileCount = changedFilesPerProject.values().stream().flatMap(Collection::stream).count(); SonarLintLogger.get().info("Analyzing " + fileCount + " changed file(s) in " + changedFilesPerProject.keySet().size() + " project(s)"); global.setTaskName("Analysis"); SubMonitor analysisMonitor = SubMonitor.convert(global.newChild(80), changedFilesPerProject.entrySet().size()); for (Map.Entry<ISonarLintProject, List<ISonarLintFile>> entry : changedFilesPerProject.entrySet()) { SubMonitor projectAnalysisMonitor = analysisMonitor.newChild(1); ISonarLintProject project = entry.getKey(); if (!project.isOpen()) { continue; } global.setTaskName("Analysing project " + project.getName()); Collection<FileWithDocument> filesToAnalyze = entry.getValue().stream() .map(f -> new FileWithDocument(f, null)) .collect(Collectors.toList()); AnalyzeProjectRequest req = new AnalyzeProjectRequest(project, filesToAnalyze, TriggerType.CHANGESET); AnalyzeProjectJob job = new AnalyzeProjectJob(req); job.runInWorkspace(projectAnalysisMonitor); } } catch (Exception e) { SonarLintLogger.get().error(UNABLE_TO_ANALYZE_CHANGED_FILES, e); return new Status(Status.ERROR, SonarLintCorePlugin.PLUGIN_ID, UNABLE_TO_ANALYZE_CHANGED_FILES, e); } return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS; } private static Collection<ISonarLintFile> collectChangedFiles(Collection<ISonarLintProject> projects, IProgressMonitor monitor) { Collection<ISonarLintFile> changedFiles = new ArrayList<>(); for (ISonarLintProject project : projects) { if (monitor.isCanceled()) { break; } if (project instanceof DefaultSonarLintProjectAdapter) { changedFiles.addAll(((DefaultSonarLintProjectAdapter) project).getScmChangedFiles(monitor)); } } return changedFiles; } }