import org.sonar.api.measures.Measure;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.batch.duplication.DuplicationCache;
-import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.protocol.output.*;
import org.sonar.batch.protocol.output.BatchReport.Range;
import org.sonar.batch.protocol.output.BatchReport.Scm;
import org.sonar.batch.protocol.output.BatchReport.Scm.Changeset;
import org.sonar.batch.protocol.output.BatchReport.Symbols;
import org.sonar.batch.protocol.output.BatchReport.SyntaxHighlighting;
-import org.sonar.batch.protocol.output.BatchReportReader;
import org.sonar.batch.report.BatchReportUtils;
import org.sonar.batch.report.ReportPublisher;
import org.sonar.batch.scan.measure.MeasureCache;
public byte[] consolidateData(DefaultInputFile inputFile) throws IOException {
FileSourceDb.Data.Builder dataBuilder = createForSource(inputFile);
- applyLineMeasures(inputFile, dataBuilder);
+ if (!inputFile.isEmpty()) {
+ applyLineMeasures(inputFile, dataBuilder);
+ }
applyScm(inputFile, dataBuilder);
applyDuplications(inputFile.key(), dataBuilder);
applyHighlighting(inputFile, dataBuilder);
*/
package org.sonar.batch.index;
-import org.sonar.api.batch.fs.internal.FileMetadata;
-import org.sonar.api.batch.fs.internal.FileMetadata.LineHashConsumer;
-
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
+import org.sonar.api.batch.fs.internal.FileMetadata;
+import org.sonar.api.batch.fs.internal.FileMetadata.LineHashConsumer;
import org.sonar.api.utils.System2;
import org.sonar.batch.ProjectTree;
import org.sonar.batch.scan.filesystem.InputPathCache;
@CheckForNull
private String lineHashesAsMd5Hex(DefaultInputFile f) {
- if (f.lines() == 0) {
- return null;
- }
// A md5 string is 32 char long + '\n' = 33
final StringBuilder result = new StringBuilder(f.lines() * (32 + 1));
private final IssueExclusionsLoader issueExclusionsLoader;
private final IssuesReports issuesReport;
private final LocalIssueTracking localIssueTracking;
- private final ReportPublisher publishReportJob;
+ private final ReportPublisher reportPublisher;
public DatabaseLessPhaseExecutor(Phases phases, InitializersExecutor initializersExecutor, SensorsExecutor sensorsExecutor,
SensorContext sensorContext, DefaultIndex index,
EventBus eventBus, ProjectInitializer pi, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
- IssueExclusionsLoader issueExclusionsLoader, LocalIssueTracking localIssueTracking, ReportPublisher publishReportJob) {
+ IssueExclusionsLoader issueExclusionsLoader, LocalIssueTracking localIssueTracking, ReportPublisher reportPublisher) {
this.phases = phases;
this.initializersExecutor = initializersExecutor;
this.sensorsExecutor = sensorsExecutor;
this.profileVerifier = profileVerifier;
this.issueExclusionsLoader = issueExclusionsLoader;
this.localIssueTracking = localIssueTracking;
- this.publishReportJob = publishReportJob;
+ this.reportPublisher = reportPublisher;
}
/**
private void publishReportJob() {
String stepName = "Publish report";
eventBus.fireEvent(new BatchStepEvent(stepName, true));
- this.publishReportJob.execute();
+ this.reportPublisher.execute();
eventBus.fireEvent(new BatchStepEvent(stepName, false));
}
private final PostJobsExecutor postJobsExecutor;
private final InitializersExecutor initializersExecutor;
private final SensorsExecutor sensorsExecutor;
- private final ReportPublisher publishReportJob;
+ private final ReportPublisher reportPublisher;
private final SensorContext sensorContext;
private final DefaultIndex index;
private final ProjectInitializer pi;
public DatabaseModePhaseExecutor(Phases phases, DecoratorsExecutor decoratorsExecutor,
InitializersExecutor initializersExecutor, PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, ReportPublisher publishReportJob, ProjectInitializer pi,
+ EventBus eventBus, ReportPublisher reportPublisher, ProjectInitializer pi,
ScanPersister[] persisters, FileSystemLogger fsLogger, IssuesReports jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
IssueExclusionsLoader issueExclusionsLoader, DefaultAnalysisMode analysisMode, DatabaseSession session, ResourcePersister resourcePersister) {
this.phases = phases;
this.sensorContext = sensorContext;
this.index = index;
this.eventBus = eventBus;
- this.publishReportJob = publishReportJob;
+ this.reportPublisher = reportPublisher;
this.pi = pi;
this.persisters = persisters;
this.fsLogger = fsLogger;
private void publishReportJob() {
String stepName = "Publish report";
eventBus.fireEvent(new BatchStepEvent(stepName, true));
- this.publishReportJob.execute();
+ this.reportPublisher.execute();
eventBus.fireEvent(new BatchStepEvent(stepName, false));
}
}
private void addIfNotEmpty(List<InputFile> filesToBlame, InputFile f) {
- if (f.lines() > 0) {
+ if (!f.isEmpty()) {
filesToBlame.add(f);
}
}
.property("sonar.xoo.internalKey", "my/internal/key")
.start();
- assertThat(result.issues()).hasSize(10);
+ assertThat(result.issues()).hasSize(11);
}
}
Status status();
/**
- * Number of physical lines. This method supports all end-of-line characters. Returns
- * zero if the file is empty.
+ * Number of physical lines. This method supports all end-of-line characters. Formula is (number of line break + 1). Returns
+ * 1 if the file is empty.</br> Returns 2 for <tt>foo\nbar</tt>. Returns 3 for <tt>foo\nbar\n</tt>.
*/
int lines();
+ /**
+ * Check if the file content is empty (ignore potential BOM).
+ * @since 5.2
+ */
+ boolean isEmpty();
+
/**
* Return a {@link TextPointer} in the given file.
* @param line Line of the pointer. Start at 1.
return lines;
}
+ @Override
+ public boolean isEmpty() {
+ return lastValidOffset == 0;
+ }
+
/**
* Component key.
*/
}
private static class LineCounter extends CharHandler {
- private int lines = 0;
+ private int lines = 1;
private int nonBlankLines = 0;
private boolean blankLine = true;
boolean alreadyLoggedInvalidCharacter = false;
@Override
protected void handleAll(char c) {
- if (this.lines == 0) {
- this.lines = 1;
- }
if (!alreadyLoggedInvalidCharacter && c == '\ufffd') {
LOG.warn("Invalid character encountered in file {} at line {} for encoding {}. Please fix file content or configure the encoding to be used using property '{}'.", file,
lines, encoding, CoreProperties.ENCODING_PROPERTY);
private final MessageDigest lineMd5Digest = DigestUtils.getMd5Digest();
private final StringBuilder sb = new StringBuilder();
private final LineHashConsumer consumer;
- private int line = 0;
+ private int line = 1;
public LineHashComputer(LineHashConsumer consumer) {
this.consumer = consumer;
}
- @Override
- protected void handleAll(char c) {
- if (this.line == 0) {
- this.line = 1;
- }
- }
-
@Override
protected void handleIgnoreEoL(char c) {
if (!Character.isWhitespace(c)) {
FileUtils.touch(tempFile);
FileMetadata.Metadata metadata = new FileMetadata().readMetadata(tempFile, Charsets.UTF_8);
- assertThat(metadata.lines).isEqualTo(0);
+ assertThat(metadata.lines).isEqualTo(1);
assertThat(metadata.nonBlankLines).isEqualTo(0);
assertThat(metadata.hash).isNotEmpty();
assertThat(metadata.originalLineOffsets).containsOnly(0);
case 3:
assertThat(Hex.encodeHexString(hash)).isEqualTo(md5Hex("baz"));
break;
+ default:
+ fail("Invalid line");
}
}
});
@Override
public void consume(int lineIdx, @Nullable byte[] hash) {
- fail("File is empty and should not report any line hash");
+ switch (lineIdx) {
+ case 1:
+ assertThat(hash).isNull();
+ break;
+ default:
+ fail("Invalid line");
+ }
}
});
}