xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/history/PerforceAnnotationParser.java (revision 0e4c55544f8ea0a68e8bae37b0e502097e008ec1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * See LICENSE.txt included in this distribution for the specific
9  * language governing permissions and limitations under the License.
10  *
11  * When distributing Covered Code, include this CDDL HEADER in each
12  * file and include the License file at LICENSE.txt.
13  * If applicable, add the following below this CDDL HEADER, with the
14  * fields enclosed by brackets "[]" replaced with your own identifying
15  * information: Portions Copyright [yyyy] [name of copyright owner]
16  *
17  * CDDL HEADER END
18  */
19 
20 /*
21  * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2020, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.indexer.history;
25 
26 import java.io.BufferedReader;
27 import java.io.File;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.InputStreamReader;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.logging.Level;
34 import java.util.logging.Logger;
35 import java.util.regex.Matcher;
36 import java.util.regex.Pattern;
37 import org.opengrok.indexer.logger.LoggerFactory;
38 import org.opengrok.indexer.util.Executor;
39 
40 /**
41  * handles parsing the output of the {@code p4 annotate} command
42  * into an annotation object.
43  */
44 public class PerforceAnnotationParser implements Executor.StreamHandler {
45 
46     private static final Logger LOGGER = LoggerFactory.getLogger(PerforceAnnotationParser.class);
47 
48     /**
49      * Store annotation created by processStream.
50      */
51     private final Annotation annotation;
52 
53     private final PerforceRepository repo;
54 
55     private final File file;
56 
57     private static final Pattern ANNOTATION_PATTERN = Pattern.compile("^(\\d+): .*");
58 
59     /**
60      * @param repo defined instance
61      * @param file the file being annotated
62      */
PerforceAnnotationParser(PerforceRepository repo, File file)63     public PerforceAnnotationParser(PerforceRepository repo, File file) {
64         annotation = new Annotation(file.getName());
65         this.repo = repo;
66         this.file = file;
67     }
68 
69     /**
70      * Returns the annotation that has been created.
71      *
72      * @return annotation an annotation object
73      */
getAnnotation()74     public Annotation getAnnotation() {
75         return annotation;
76     }
77 
78     @Override
processStream(InputStream input)79     public void processStream(InputStream input) throws IOException {
80         // Pass null for revision to get all history for the file.
81         PerforceHistoryParser parser = new PerforceHistoryParser(repo);
82         List<HistoryEntry> revisions = parser.getRevisions(file, null).getHistoryEntries();
83         HashMap<String, String> revAuthor = new HashMap<>();
84         for (HistoryEntry entry : revisions) {
85             revAuthor.put(entry.getRevision(), entry.getAuthor());
86         }
87 
88         String line;
89         int lineno = 0;
90         try (BufferedReader reader = new BufferedReader(new InputStreamReader(input))) {
91             while ((line = reader.readLine()) != null) {
92                 ++lineno;
93                 if (line.equals("(... files differ ...)")) {
94                     // Perforce knows as a binary file?
95                     continue;
96                 }
97 
98                 Matcher matcher = ANNOTATION_PATTERN.matcher(line);
99                 if (matcher.find()) {
100                     String revision = matcher.group(1);
101                     String author = revAuthor.get(revision);
102                     annotation.addLine(revision, author, true);
103                 } else {
104                     LOGGER.log(Level.SEVERE,
105                             "Error: did not find annotation in line {0}: [{1}]",
106                             new Object[]{lineno, line});
107                 }
108             }
109         } catch (IOException e) {
110             LOGGER.log(Level.SEVERE,
111                     "Error: Could not read annotations for " + annotation.getFilename(), e);
112         }
113     }
114 }
115