From 9030b566aa37558726e14138c292326f93699f8f Mon Sep 17 00:00:00 2001 From: Julien HENRY Date: Tue, 20 Jan 2015 12:18:37 +0100 Subject: [PATCH] SONAR-5077 Special case of empty files --- .../DefaultInputFileValueCoder.java | 2 ++ .../batch/scan/filesystem/FileMetadata.java | 14 +++++---- .../scan/filesystem/InputFileBuilder.java | 1 + .../java/org/sonar/batch/scm/ScmSensor.java | 9 +++++- .../batch/mediumtest/scm/ScmMediumTest.java | 30 +++++++++++++++++++ .../scan/filesystem/FileMetadataTest.java | 8 +++-- .../batch/fs/internal/DefaultInputFile.java | 14 +++++++-- 7 files changed, 66 insertions(+), 12 deletions(-) diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java index 3ce3c5872c7..7b6b4911191 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/DefaultInputFileValueCoder.java @@ -47,6 +47,7 @@ class DefaultInputFileValueCoder implements ValueCoder { putUTFOrNull(value, f.hash()); value.put(f.lines()); putUTFOrNull(value, f.encoding()); + value.put(f.isEmpty()); value.putLongArray(f.originalLineOffsets()); for (int i = 0; i < f.lines(); i++) { value.putByteArray(f.lineHashes()[i]); @@ -76,6 +77,7 @@ class DefaultInputFileValueCoder implements ValueCoder { file.setHash(value.getString()); file.setLines(value.getInt()); file.setEncoding(value.getString()); + file.setEmpty(value.getBoolean()); file.setOriginalLineOffsets(value.getLongArray()); byte[][] lineHashes = new byte[file.lines()][]; for (int i = 0; i < file.lines(); i++) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileMetadata.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileMetadata.java index afa4735d77e..d90e026f16b 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileMetadata.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/FileMetadata.java @@ -55,8 +55,8 @@ class FileMetadata { long currentOriginalOffset = 0; List originalLineOffsets = new ArrayList(); List lineHashes = new ArrayList(); - int lines = 0; - char c = (char) -1; + int lines = 1; + char c = (char) 0; try (Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding))) { MessageDigest globalMd5Digest = DigestUtils.getMd5Digest(); MessageDigest lineMd5Digest = DigestUtils.getMd5Digest(); @@ -102,11 +102,11 @@ class FileMetadata { } if (c != (char) -1) { // Last line - lines++; lineHashes.add(blankline ? null : lineMd5Digest.digest()); } - String filehash = Hex.encodeHexString(globalMd5Digest.digest()); - return new Metadata(lines, filehash, originalLineOffsets, lineHashes.toArray(new byte[0][])); + boolean empty = lines == 1 && blankline; + String filehash = empty ? null : Hex.encodeHexString(globalMd5Digest.digest()); + return new Metadata(lines, filehash, originalLineOffsets, lineHashes.toArray(new byte[0][]), empty); } catch (IOException e) { throw new IllegalStateException(String.format("Fail to read file '%s' with encoding '%s'", file.getAbsolutePath(), encoding), e); @@ -131,10 +131,12 @@ class FileMetadata { final String hash; final long[] originalLineOffsets; final byte[][] lineHashes; + final boolean empty; - private Metadata(int lines, String hash, List originalLineOffsets, byte[][] lineHashes) { + private Metadata(int lines, String hash, List originalLineOffsets, byte[][] lineHashes, boolean empty) { this.lines = lines; this.hash = hash; + this.empty = empty; this.originalLineOffsets = Longs.toArray(originalLineOffsets); this.lineHashes = lineHashes; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilder.java index 49303a056fd..b3aba4f61b0 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/filesystem/InputFileBuilder.java @@ -112,6 +112,7 @@ class InputFileBuilder { inputFile.setHash(metadata.hash); inputFile.setOriginalLineOffsets(metadata.originalLineOffsets); inputFile.setLineHashes(metadata.lineHashes); + inputFile.setEmpty(metadata.empty); inputFile.setStatus(statusDetection.status(inputFile.moduleKey(), inputFile.relativePath(), metadata.hash)); if (analysisMode.isIncremental() && inputFile.status() == InputFile.Status.SAME) { return null; diff --git a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java index 56e477ec9c7..00f6839bfdb 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scm/ScmSensor.java @@ -26,6 +26,7 @@ import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile.Status; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; @@ -92,7 +93,7 @@ public final class ScmSensor implements Sensor { if (f.status() == Status.SAME && fileData != null) { if (fileData.needBlame()) { - filesToBlame.add(f); + addIfNotEmpty(filesToBlame, f); } else { // Copy previous measures String scmAuthorsByLine = fileData.scmAuthorsByLine(); @@ -105,6 +106,12 @@ public final class ScmSensor implements Sensor { } } } else { + addIfNotEmpty(filesToBlame, f); + } + } + + private void addIfNotEmpty(List filesToBlame, InputFile f) { + if (!((DefaultInputFile) f).isEmpty()) { filesToBlame.add(f); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java index 4a6e1a79cef..c8456c6c803 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/scm/ScmMediumTest.java @@ -94,6 +94,36 @@ public class ScmMediumTest { .withValue("1=;2=julien;3=julien;4=julien;5=simon")); } + @Test + public void noScmOnEmptyFile() throws IOException { + + File baseDir = prepareProject(); + + // Clear file content + FileUtils.write(new File(baseDir, "src/sample.xoo"), ""); + + TaskResult result = tester.newTask() + .properties(ImmutableMap.builder() + .put("sonar.task", "scan") + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.projectName", "Foo Project") + .put("sonar.projectVersion", "1.0-SNAPSHOT") + .put("sonar.projectDescription", "Description of Foo Project") + .put("sonar.sources", "src") + .put("sonar.scm.provider", "xoo") + .build()) + .start(); + + // lines + qprofile + assertThat(result.measures()).hasSize(2); + + assertThat(result.measures()).contains(new DefaultMeasure() + .forMetric(CoreMetrics.LINES) + .onFile(new DefaultInputFile("com.foo.project", "src/sample.xoo")) + .withValue(1)); + } + @Test public void failIfMissingFile() throws IOException { diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileMetadataTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileMetadataTest.java index 3b9cec76fdb..e6c73e80fd7 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileMetadataTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/filesystem/FileMetadataTest.java @@ -46,10 +46,11 @@ public class FileMetadataTest { FileUtils.touch(tempFile); FileMetadata.Metadata metadata = new FileMetadata().read(tempFile, Charsets.UTF_8); - assertThat(metadata.lines).isEqualTo(0); - assertThat(metadata.hash).isNotEmpty(); + assertThat(metadata.lines).isEqualTo(1); + assertThat(metadata.hash).isNull(); assertThat(metadata.originalLineOffsets).containsOnly(0); - assertThat(metadata.lineHashes).isEmpty(); + assertThat(metadata.lineHashes[0]).isNull(); + assertThat(metadata.empty).isTrue(); } @Test @@ -64,6 +65,7 @@ public class FileMetadataTest { assertThat(metadata.lineHashes[0]).containsOnly(md5("foo")); assertThat(metadata.lineHashes[1]).containsOnly(md5("bar")); assertThat(metadata.lineHashes[2]).containsOnly(md5("baz")); + assertThat(metadata.empty).isFalse(); } @Test diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java index 391ac575f32..411e3f8389b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputFile.java @@ -39,8 +39,9 @@ public class DefaultInputFile implements InputFile, Serializable { private String hash; private int lines; private String encoding; - long[] originalLineOffsets; - byte[][] lineHashes; + private long[] originalLineOffsets; + private byte[][] lineHashes; + private boolean empty; public DefaultInputFile(String moduleKey, String relativePath) { this.moduleKey = moduleKey; @@ -168,6 +169,15 @@ public class DefaultInputFile implements InputFile, Serializable { return this; } + public boolean isEmpty() { + return this.empty; + } + + public DefaultInputFile setEmpty(boolean empty) { + this.empty = empty; + return this; + } + @Override public boolean equals(Object o) { if (this == o) { -- 2.39.5