]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5754 Display a progress status of blame in logs
authorJulien HENRY <julien.henry@sonarsource.com>
Fri, 31 Oct 2014 14:43:53 +0000 (15:43 +0100)
committerJulien HENRY <julien.henry@sonarsource.com>
Fri, 31 Oct 2014 14:44:51 +0000 (15:44 +0100)
sonar-batch/src/main/java/org/sonar/batch/scm/DefaultBlameOutput.java
sonar-batch/src/main/java/org/sonar/batch/scm/ScmConfiguration.java
sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java
sonar-batch/src/main/java/org/sonar/batch/util/ProgressReport.java [new file with mode: 0644]

index de873b135db384b7989910452d84d5f3785ffbb0..9f1e33b423cfa85556549f1368141a6df970b763 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.measures.PropertiesBuilder;
 import org.sonar.api.utils.DateUtils;
+import org.sonar.batch.util.ProgressReport;
 
 import javax.annotation.Nullable;
 
@@ -36,6 +37,7 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
 
 class DefaultBlameOutput implements BlameOutput {
@@ -45,14 +47,21 @@ class DefaultBlameOutput implements BlameOutput {
 
   private final SensorContext context;
   private final Set<InputFile> allFilesToBlame = new HashSet<InputFile>();
+  private ProgressReport progressReport;
+  private int count;
+  private int total;
 
   DefaultBlameOutput(SensorContext context, List<InputFile> filesToBlame) {
     this.context = context;
     this.allFilesToBlame.addAll(filesToBlame);
+    count = 0;
+    total = filesToBlame.size();
+    progressReport = new ProgressReport("Report about progress of SCM blame", TimeUnit.SECONDS.toMillis(10));
+    progressReport.start(total + " files to be analyzed");
   }
 
   @Override
-  public void blameResult(InputFile file, List<BlameLine> lines) {
+  public synchronized void blameResult(InputFile file, List<BlameLine> lines) {
     Preconditions.checkNotNull(file);
     Preconditions.checkNotNull(lines);
     Preconditions.checkArgument(allFilesToBlame.contains(file), "It was not expected to blame file " + file.relativePath());
@@ -73,6 +82,8 @@ class DefaultBlameOutput implements BlameOutput {
     }
     ScmSensor.saveMeasures(context, file, authors.buildData(), dates.buildData(), revisions.buildData());
     allFilesToBlame.remove(file);
+    count++;
+    progressReport.message(count + "/" + total + " files analyzed, last one was " + file.absolutePath());
   }
 
   private String normalizeString(@Nullable String inputString) {
@@ -97,7 +108,10 @@ class DefaultBlameOutput implements BlameOutput {
     return new PropertiesBuilder<Integer, String>(metric);
   }
 
-  public Set<InputFile> remainingFiles() {
-    return allFilesToBlame;
+  public void finish() {
+    if (!allFilesToBlame.isEmpty()) {
+      throw new IllegalStateException("Some files were not blamed");
+    }
+    progressReport.stop(count + "/" + count + " files analyzed");
   }
 }
index bc4e7208f1bcdb49010e5931aa40ff2f2b8016e7..468b29e04a595030c61639002e521ec87a0433be 100644 (file)
@@ -29,8 +29,11 @@ import org.sonar.api.batch.InstantiationStrategy;
 import org.sonar.api.batch.bootstrap.ProjectReactor;
 import org.sonar.api.batch.scm.ScmProvider;
 import org.sonar.api.config.Settings;
+import org.sonar.batch.phases.Phases;
 import org.sonar.core.DryRunIncompatible;
 
+import javax.annotation.Nullable;
+
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -42,23 +45,38 @@ public final class ScmConfiguration implements BatchComponent, Startable {
   private final ProjectReactor projectReactor;
   private final Settings settings;
   private final Map<String, ScmProvider> providerPerKey = new LinkedHashMap<String, ScmProvider>();
+  private final Phases phases;
 
   private ScmProvider provider;
 
-  public ScmConfiguration(ProjectReactor projectReactor, Settings settings, ScmProvider... providers) {
+  public ScmConfiguration(ProjectReactor projectReactor, Settings settings, @Nullable Phases phases, ScmProvider... providers) {
     this.projectReactor = projectReactor;
     this.settings = settings;
+    this.phases = phases;
     for (ScmProvider scmProvider : providers) {
       providerPerKey.put(scmProvider.key(), scmProvider);
     }
   }
 
+  // Scan 2
+  public ScmConfiguration(ProjectReactor projectReactor, Settings settings, ScmProvider... providers) {
+    this(projectReactor, settings, null, providers);
+  }
+
+  public ScmConfiguration(ProjectReactor projectReactor, Settings settings, Phases phases) {
+    this(projectReactor, settings, phases, new ScmProvider[0]);
+  }
+
+  // Scan2
   public ScmConfiguration(ProjectReactor projectReactor, Settings settings) {
-    this(projectReactor, settings, new ScmProvider[0]);
+    this(projectReactor, settings, null, new ScmProvider[0]);
   }
 
   @Override
   public void start() {
+    if (phases != null && !phases.isEnabled(Phases.Phase.SENSOR)) {
+      return;
+    }
     if (isDisabled()) {
       LOG.debug("SCM Step is disabled by configuration");
       return;
index 4480938a7a20362103073e9e15f5e25b49f73a6e..445fd2bf39e21e2f41d91ee505e6c4171884bc9e 100644 (file)
@@ -86,9 +86,7 @@ public final class ScmSensor implements Sensor {
       TimeProfiler profiler = new TimeProfiler().start("Retrieve SCM blame information");
       DefaultBlameOutput output = new DefaultBlameOutput(context, filesToBlame);
       configuration.provider().blameCommand().blame(new DefaultBlameInput(fs, filesToBlame), output);
-      if (!output.remainingFiles().isEmpty()) {
-        throw new IllegalStateException("Some files were not blamed");
-      }
+      output.finish();
       profiler.stop();
     }
   }
@@ -112,10 +110,7 @@ public final class ScmSensor implements Sensor {
     }
   }
 
-  /**
-   * This method is synchronized since it is allowed for plugins to compute blame in parallel.
-   */
-  static synchronized void saveMeasures(SensorContext context, InputFile f, String scmAuthorsByLine, String scmLastCommitDatetimesByLine, String scmRevisionsByLine) {
+  static void saveMeasures(SensorContext context, InputFile f, String scmAuthorsByLine, String scmLastCommitDatetimesByLine, String scmRevisionsByLine) {
     ((DefaultMeasure<String>) context.<String>newMeasure()
       .onFile(f)
       .forMetric(CoreMetrics.SCM_AUTHORS_BY_LINE)
diff --git a/sonar-batch/src/main/java/org/sonar/batch/util/ProgressReport.java b/sonar-batch/src/main/java/org/sonar/batch/util/ProgressReport.java
new file mode 100644 (file)
index 0000000..80be1ce
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.batch.util;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProgressReport implements Runnable {
+
+  private final long period;
+  private final Logger logger;
+  private String message = "";
+  private final Thread thread;
+  private String stopMessage = "";
+
+  public ProgressReport(String threadName, long period, Logger logger) {
+    this.period = period;
+    this.logger = logger;
+    thread = new Thread(this);
+    thread.setName(threadName);
+  }
+
+  public ProgressReport(String threadName, long period) {
+    this(threadName, period, LoggerFactory.getLogger(ProgressReport.class));
+  }
+
+  @Override
+  public void run() {
+    while (!Thread.interrupted()) {
+      try {
+        Thread.sleep(period);
+        log(message);
+      } catch (InterruptedException e) {
+        thread.interrupt();
+      }
+    }
+    log(stopMessage);
+  }
+
+  public void start(String startMessage) {
+    log(startMessage);
+    thread.start();
+  }
+
+  public void message(String message) {
+    this.message = message;
+  }
+
+  public void stop(String stopMessage) {
+    this.stopMessage = stopMessage;
+    thread.interrupt();
+  }
+
+  public void join() throws InterruptedException {
+    thread.join();
+  }
+
+  private void log(String message) {
+    synchronized (logger) {
+      logger.info(message);
+      logger.notifyAll();
+    }
+  }
+
+}