xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/history/History.java (revision a964b78c95d85df4d53a32479f7d0aa2f6799da4)
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) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2019, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.indexer.history;
25 
26 import org.jetbrains.annotations.Nullable;
27 
28 import java.io.Serializable;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Objects;
36 import java.util.Set;
37 import java.util.stream.Collectors;
38 
39 /**
40  * Class representing the history of a file.
41  */
42 public class History implements Serializable {
43 
44     private static final long serialVersionUID = -1;
45 
46     static final String TAGS_SEPARATOR = ", ";
47 
48     /** Entries in the log. The first entry is the most recent one. */
49     private List<HistoryEntry> entries;
50     /**
51      * track renamed files so they can be treated in special way (for some
52      * SCMs) during cache creation.
53      * These are relative to repository root.
54      */
55     private final Set<String> renamedFiles;
56 
57     // revision to tag list. Individual tags are joined via TAGS_SEPARATOR.
58     private Map<String, String> tags = new HashMap<>();
59 
History()60     public History() {
61         this(new ArrayList<>());
62     }
63 
History(List<HistoryEntry> entries)64     History(List<HistoryEntry> entries) {
65         this(entries, Collections.emptyList());
66     }
67 
History(List<HistoryEntry> entries, List<String> renamed)68     History(List<HistoryEntry> entries, List<String> renamed) {
69         this.entries = entries;
70         this.renamedFiles = new HashSet<>(renamed);
71     }
72 
History(List<HistoryEntry> entries, Set<String> renamed)73     History(List<HistoryEntry> entries, Set<String> renamed) {
74         this.entries = entries;
75         this.renamedFiles = renamed;
76     }
77 
78     // Needed for serialization.
getTags()79     public Map<String, String> getTags() {
80         return tags;
81     }
82 
83     // Needed for serialization.
setTags(Map<String, String> tags)84     public void setTags(Map<String, String> tags) {
85         this.tags = tags;
86     }
87 
setEntries(List<HistoryEntry> entries)88     public void setEntries(List<HistoryEntry> entries) {
89         this.entries = entries;
90     }
91 
92     /**
93      * Set the list of log entries for the file. The first entry is the most
94      * recent one.
95      *
96      * @param entries The entries to add to the list
97      */
setHistoryEntries(List<HistoryEntry> entries)98     public void setHistoryEntries(List<HistoryEntry> entries) {
99         this.entries = entries;
100     }
101 
102     /**
103      * Get the list of log entries, most recent first.
104      *
105      * @return The list of entries in this history
106      */
getHistoryEntries()107     public List<HistoryEntry> getHistoryEntries() {
108         return entries;
109     }
110 
111     /**
112      * Get the list of log entries, most recent first.
113      * With parameters
114      * @param limit max number of entries
115      * @param offset starting position
116      *
117      * @return The list of entries in this history
118      */
getHistoryEntries(int limit, int offset)119     public List<HistoryEntry> getHistoryEntries(int limit, int offset) {
120         offset = Math.max(offset, 0);
121         limit = offset + limit > entries.size() ? entries.size() - offset : limit;
122         return entries.subList(offset, offset + limit);
123     }
124 
125     /**
126      * Check if at least one history entry has a file list.
127      *
128      * @return {@code true} if at least one of the entries has a non-empty
129      * file list, {@code false} otherwise
130      */
hasFileList()131     public boolean hasFileList() {
132         return entries.stream()
133                 .map(HistoryEntry::getFiles)
134                 .anyMatch(files -> !files.isEmpty());
135     }
136 
137     /**
138      * Check if at least one history entry has a tag list.
139      *
140      * @return {@code true} if at least one of the entries has a non-empty
141      * tag list, {@code false} otherwise
142      */
hasTags()143     public boolean hasTags() {
144         return !tags.isEmpty();
145     }
146 
addTags(HistoryEntry entry, String newTags)147     public void addTags(HistoryEntry entry, String newTags) {
148         tags.merge(entry.getRevision(), newTags, (a, b) -> a + TAGS_SEPARATOR + b);
149     }
150 
151     /**
152      * Gets a value indicating if {@code file} is in the list of renamed files.
153      * @param file file path
154      * @return is file renamed
155      */
isRenamed(String file)156     public boolean isRenamed(String file) {
157         return renamedFiles.contains(file);
158     }
159 
getRenamedFiles()160     public Set<String> getRenamedFiles() {
161         return renamedFiles;
162     }
163 
164     /**
165      * @return list of revisions
166      */
getRevisionList()167     public List<String> getRevisionList() {
168         return getHistoryEntries().stream().
169                 map(HistoryEntry::getRevision).collect(Collectors.toList());
170     }
171 
172     /**
173      * Strip files and tags.
174      * @see HistoryEntry#strip()
175      */
strip()176     public void strip() {
177         for (HistoryEntry ent : this.getHistoryEntries()) {
178             ent.strip();
179         }
180 
181         tags.clear();
182     }
183 
184     /**
185      * @return last (newest) history entry or null
186      */
getLastHistoryEntry()187     public @Nullable HistoryEntry getLastHistoryEntry() {
188         List<HistoryEntry> historyEntries = getHistoryEntries();
189         if (historyEntries == null || historyEntries.isEmpty()) {
190             return null;
191         }
192 
193         return historyEntries.get(0);
194     }
195 
196     @Override
equals(Object o)197     public boolean equals(Object o) {
198         if (this == o) {
199             return true;
200         }
201         if (o == null || getClass() != o.getClass()) {
202             return false;
203         }
204         History that = (History) o;
205         return Objects.equals(this.getHistoryEntries(), that.getHistoryEntries()) &&
206                 Objects.equals(this.getTags(), that.getTags()) &&
207                 Objects.equals(this.getRenamedFiles(), that.getRenamedFiles());
208     }
209 
210     @Override
hashCode()211     public int hashCode() {
212         return Objects.hash(getHistoryEntries(), getTags(), getRenamedFiles());
213     }
214 
215     @Override
toString()216     public String toString() {
217         return this.getHistoryEntries().toString() + ", renamed files: " + this.getRenamedFiles().toString() +
218                 " , tags: " + getTags();
219     }
220 }
221