You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

XooBlameCommand.java 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  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.
  10. *
  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.
  15. *
  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.
  19. */
  20. package org.sonar.xoo.scm;
  21. import com.google.common.annotations.VisibleForTesting;
  22. import java.io.File;
  23. import java.io.FileReader;
  24. import java.io.IOException;
  25. import java.util.Date;
  26. import java.util.List;
  27. import org.apache.commons.csv.CSVFormat;
  28. import org.apache.commons.csv.CSVParser;
  29. import org.apache.commons.csv.CSVRecord;
  30. import org.sonar.api.batch.fs.InputFile;
  31. import org.sonar.api.batch.scm.BlameCommand;
  32. import org.sonar.api.batch.scm.BlameLine;
  33. import org.sonar.api.utils.DateUtils;
  34. import static com.google.common.base.Preconditions.checkState;
  35. import static java.util.stream.Collectors.toList;
  36. import static org.apache.commons.lang.StringUtils.trimToNull;
  37. public class XooBlameCommand extends BlameCommand {
  38. private static final String SCM_EXTENSION = ".scm";
  39. @Override
  40. public void blame(BlameInput input, BlameOutput result) {
  41. for (InputFile inputFile : input.filesToBlame()) {
  42. processFile(inputFile, result);
  43. }
  44. }
  45. @VisibleForTesting
  46. protected void processFile(InputFile inputFile, BlameOutput result) {
  47. File ioFile = inputFile.file();
  48. File scmDataFile = new File(ioFile.getParentFile(), ioFile.getName() + SCM_EXTENSION);
  49. if (!scmDataFile.exists()) {
  50. return;
  51. }
  52. try {
  53. List<BlameLine> blame = readFile(scmDataFile);
  54. result.blameResult(inputFile, blame);
  55. } catch (IOException e) {
  56. throw new IllegalStateException(e);
  57. }
  58. }
  59. private static List<BlameLine> readFile(File inputStream) throws IOException {
  60. Date now = new Date();
  61. try (CSVParser csvParser = CSVFormat.RFC4180
  62. .withIgnoreEmptyLines()
  63. .withIgnoreSurroundingSpaces()
  64. .parse(new FileReader(inputStream))) {
  65. List<CSVRecord> records = csvParser.getRecords();
  66. return records.stream()
  67. .map(r -> convertToBlameLine(now, r))
  68. .collect(toList());
  69. }
  70. }
  71. private static BlameLine convertToBlameLine(Date now, CSVRecord csvRecord) {
  72. checkState(csvRecord.size() >= 3, "Not enough fields on line %s", csvRecord);
  73. String revision = trimToNull(csvRecord.get(0));
  74. String author = trimToNull(csvRecord.get(1));
  75. BlameLine blameLine = new BlameLine().revision(revision).author(author);
  76. String dateStr = trimToNull(csvRecord.get(2));
  77. if (dateStr != null) {
  78. // try to load a relative number of days
  79. try {
  80. int days = Integer.parseInt(dateStr);
  81. blameLine.date(DateUtils.addDays(now, days));
  82. } catch (NumberFormatException e) {
  83. Date dateTime = DateUtils.parseDateTimeQuietly(dateStr);
  84. if (dateTime != null) {
  85. blameLine.date(dateTime);
  86. } else {
  87. // Will throw an exception, when date is not in format "yyyy-MM-dd"
  88. blameLine.date(DateUtils.parseDate(dateStr));
  89. }
  90. }
  91. }
  92. return blameLine;
  93. }
  94. }