LCOV - code coverage report
Current view: top level - server/patch - MagicFile.java (source / functions) Hit Total Coverage
Test: _coverage_report.dat Lines: 74 74 100.0 %
Date: 2022-11-19 15:00:39 Functions: 11 11 100.0 %

          Line data    Source code
       1             : // Copyright (C) 2020 The Android Open Source Project
       2             : //
       3             : // Licensed under the Apache License, Version 2.0 (the "License");
       4             : // you may not use this file except in compliance with the License.
       5             : // You may obtain a copy of the License at
       6             : //
       7             : // http://www.apache.org/licenses/LICENSE-2.0
       8             : //
       9             : // Unless required by applicable law or agreed to in writing, software
      10             : // distributed under the License is distributed on an "AS IS" BASIS,
      11             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12             : // See the License for the specific language governing permissions and
      13             : // limitations under the License.
      14             : 
      15             : package com.google.gerrit.server.patch;
      16             : 
      17             : import com.google.auto.value.AutoValue;
      18             : import com.google.common.base.CharMatcher;
      19             : import com.google.gerrit.git.ObjectIds;
      20             : import java.io.IOException;
      21             : import java.text.SimpleDateFormat;
      22             : import org.eclipse.jgit.lib.AnyObjectId;
      23             : import org.eclipse.jgit.lib.ObjectReader;
      24             : import org.eclipse.jgit.lib.PersonIdent;
      25             : import org.eclipse.jgit.revwalk.RevCommit;
      26             : import org.eclipse.jgit.revwalk.RevWalk;
      27             : 
      28             : /** Representation of a magic file which appears as a file with content to Gerrit users. */
      29             : @AutoValue
      30         104 : public abstract class MagicFile {
      31             : 
      32             :   public static MagicFile forCommitMessage(ObjectReader reader, AnyObjectId commitId)
      33             :       throws IOException {
      34         104 :     try (RevWalk rw = new RevWalk(reader)) {
      35             :       RevCommit c;
      36         104 :       if (commitId instanceof RevCommit) {
      37         104 :         c = (RevCommit) commitId;
      38             :       } else {
      39           3 :         c = rw.parseCommit(commitId);
      40             :       }
      41             : 
      42         104 :       String header = createCommitMessageHeader(reader, rw, c);
      43         104 :       String message = c.getFullMessage();
      44         104 :       return MagicFile.builder().generatedContent(header).modifiableContent(message).build();
      45             :     }
      46             :   }
      47             : 
      48             :   private static String createCommitMessageHeader(ObjectReader reader, RevWalk rw, RevCommit c)
      49             :       throws IOException {
      50         104 :     StringBuilder b = new StringBuilder();
      51         104 :     switch (c.getParentCount()) {
      52             :       case 0:
      53          33 :         break;
      54             :       case 1:
      55             :         {
      56         100 :           RevCommit p = c.getParent(0);
      57         100 :           rw.parseBody(p);
      58         100 :           b.append("Parent:     ");
      59         100 :           b.append(abbreviateName(p, reader));
      60         100 :           b.append(" (");
      61         100 :           b.append(p.getShortMessage());
      62         100 :           b.append(")\n");
      63         100 :           break;
      64             :         }
      65             :       default:
      66          31 :         for (int i = 0; i < c.getParentCount(); i++) {
      67          31 :           RevCommit p = c.getParent(i);
      68          31 :           rw.parseBody(p);
      69          31 :           b.append(i == 0 ? "Merge Of:   " : "            ");
      70          31 :           b.append(abbreviateName(p, reader));
      71          31 :           b.append(" (");
      72          31 :           b.append(p.getShortMessage());
      73          31 :           b.append(")\n");
      74             :         }
      75             :     }
      76         104 :     appendPersonIdent(b, "Author", c.getAuthorIdent());
      77         104 :     appendPersonIdent(b, "Commit", c.getCommitterIdent());
      78         104 :     b.append("\n");
      79         104 :     return b.toString();
      80             :   }
      81             : 
      82             :   public static MagicFile forMergeList(
      83             :       ComparisonType comparisonType, ObjectReader reader, AnyObjectId commitId) throws IOException {
      84          31 :     try (RevWalk rw = new RevWalk(reader)) {
      85          31 :       RevCommit c = rw.parseCommit(commitId);
      86          31 :       StringBuilder b = new StringBuilder();
      87          31 :       switch (c.getParentCount()) {
      88             :         case 0:
      89           1 :           break;
      90             :         case 1:
      91             :           {
      92           1 :             break;
      93             :           }
      94             :         default:
      95             :           int uninterestingParent =
      96          31 :               comparisonType.isAgainstParent() ? comparisonType.getParentNum().get() : 1;
      97             : 
      98          31 :           b.append("Merge List:\n\n");
      99          31 :           for (RevCommit commit : MergeListBuilder.build(rw, c, uninterestingParent)) {
     100          31 :             b.append("* ");
     101          31 :             b.append(abbreviateName(commit, reader));
     102          31 :             b.append(" ");
     103          31 :             b.append(commit.getShortMessage());
     104          31 :             b.append("\n");
     105          31 :           }
     106             :       }
     107          31 :       return MagicFile.builder().generatedContent(b.toString()).build();
     108             :     }
     109             :   }
     110             : 
     111             :   private static String abbreviateName(RevCommit p, ObjectReader reader) throws IOException {
     112         100 :     return ObjectIds.abbreviateName(p, 8, reader);
     113             :   }
     114             : 
     115             :   private static void appendPersonIdent(StringBuilder b, String field, PersonIdent person) {
     116         104 :     if (person != null) {
     117         104 :       b.append(field).append(":    ");
     118         104 :       if (person.getName() != null) {
     119         104 :         b.append(" ");
     120         104 :         b.append(person.getName());
     121             :       }
     122         104 :       if (person.getEmailAddress() != null) {
     123         104 :         b.append(" <");
     124         104 :         b.append(person.getEmailAddress());
     125         104 :         b.append(">");
     126             :       }
     127         104 :       b.append("\n");
     128             : 
     129         104 :       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZ");
     130         104 :       sdf.setTimeZone(person.getTimeZone());
     131         104 :       b.append(field).append("Date: ");
     132         104 :       b.append(sdf.format(person.getWhen()));
     133         104 :       b.append("\n");
     134             :     }
     135         104 :   }
     136             : 
     137             :   /** Generated part of the file. Any generated contents should go here. Can be empty. */
     138             :   public abstract String generatedContent();
     139             : 
     140             :   /**
     141             :    * Non-generated part of the file. This should correspond to some actual content derived from
     142             :    * somewhere else which can also be modified (e.g. by suggested fixes). Can be empty.
     143             :    */
     144             :   public abstract String modifiableContent();
     145             : 
     146             :   /** Whole content of the file as it appears to users. */
     147             :   public String getFileContent() {
     148         104 :     return generatedContent() + modifiableContent();
     149             :   }
     150             : 
     151             :   /** Returns the start line of the modifiable content. Assumes that line counting starts at 1. */
     152             :   public int getStartLineOfModifiableContent() {
     153           3 :     int numHeaderLines = CharMatcher.is('\n').countIn(generatedContent());
     154             :     // Lines start at 1 and not 0. -> Add 1.
     155           3 :     return 1 + numHeaderLines;
     156             :   }
     157             : 
     158             :   static Builder builder() {
     159         104 :     return new AutoValue_MagicFile.Builder().generatedContent("").modifiableContent("");
     160             :   }
     161             : 
     162             :   @AutoValue.Builder
     163         104 :   abstract static class Builder {
     164             : 
     165             :     /** See {@link #generatedContent()}. Use an empty string to denote no such content. */
     166             :     public abstract Builder generatedContent(String content);
     167             : 
     168             :     /** See {@link #modifiableContent()}. Use an empty string to denote no such content. */
     169             :     public abstract Builder modifiableContent(String content);
     170             : 
     171             :     abstract String generatedContent();
     172             : 
     173             :     abstract String modifiableContent();
     174             : 
     175             :     abstract MagicFile autoBuild();
     176             : 
     177             :     public MagicFile build() {
     178             :       // Normalize each content part to end with a newline character, which simplifies further
     179             :       // handling.
     180         104 :       if (!generatedContent().isEmpty() && !generatedContent().endsWith("\n")) {
     181           1 :         generatedContent(generatedContent() + "\n");
     182             :       }
     183         104 :       if (!modifiableContent().isEmpty() && !modifiableContent().endsWith("\n")) {
     184          14 :         modifiableContent(modifiableContent() + "\n");
     185             :       }
     186         104 :       return autoBuild();
     187             :     }
     188             :   }
     189             : }

Generated by: LCOV version 1.16+git.20220603.dfeb750