xref: /OpenGrok/opengrok-indexer/src/main/java/org/opengrok/indexer/history/RepositoryInfo.java (revision 85e5fa688f272c5ec55c4b1bc4eccc6f533b3ee5)
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, 2022, Oracle and/or its affiliates. All rights reserved.
22  * Portions Copyright (c) 2017, 2019, Chris Fraire <cfraire@me.com>.
23  */
24 package org.opengrok.indexer.history;
25 
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.Serializable;
29 import java.nio.file.Paths;
30 import java.util.Objects;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33 
34 import org.opengrok.indexer.configuration.Project;
35 import org.opengrok.indexer.configuration.RuntimeEnvironment;
36 import org.opengrok.indexer.logger.LoggerFactory;
37 import org.opengrok.indexer.util.ClassUtil;
38 import org.opengrok.indexer.util.DTOElement;
39 import org.opengrok.indexer.util.PathUtils;
40 
41 /**
42  * Class to contain the common info for a repository. This object will live on
43  * the server and the client side, so don't add logic that will only work on one
44  * side in this object.
45  *
46  * @author Trond Norbye
47  */
48 public class RepositoryInfo implements Serializable {
49 
50     private static final Logger LOGGER =
51         LoggerFactory.getLogger(RepositoryInfo.class);
52 
53     static {
54         ClassUtil.remarkTransientFields(RepositoryInfo.class);
55     }
56 
57     private static final long serialVersionUID = 3L;
58 
59     @DTOElement
60     private String directoryNameRelative;
61     private transient String directoryNameCanonical;
62 
63     @DTOElement
64     protected Boolean working;
65     @DTOElement
66     protected String type;  // type of the repository, should be unique
67     @DTOElement
68     protected boolean remote;
69     protected String[] datePatterns = new String[0];
70     @DTOElement
71     protected String parent;
72     @DTOElement
73     protected String branch;
74     @DTOElement
75     protected String currentVersion;
76     @DTOElement
77     private boolean handleRenamedFiles;
78     @DTOElement
79     private boolean historyEnabled;
80     @DTOElement
81     private boolean mergeCommitsEnabled;
82     @DTOElement
83     private boolean historyBasedReindex;
84 
85     /**
86      * Empty constructor to support serialization.
87      */
RepositoryInfo()88     public RepositoryInfo() {
89         super();
90     }
91 
RepositoryInfo(RepositoryInfo orig)92     public RepositoryInfo(RepositoryInfo orig) {
93         this.directoryNameRelative = orig.directoryNameRelative;
94         this.type = orig.type;
95         this.working = orig.isWorking();
96         this.remote = orig.isRemote();
97         this.datePatterns = orig.datePatterns;
98         this.parent = orig.parent;
99         this.branch = orig.branch;
100         this.currentVersion = orig.currentVersion;
101         this.historyEnabled = orig.historyEnabled;
102         this.handleRenamedFiles = orig.handleRenamedFiles;
103         this.mergeCommitsEnabled = orig.mergeCommitsEnabled;
104         this.historyBasedReindex = orig.historyBasedReindex;
105     }
106 
107     /**
108      * @return true if the repository handles renamed files, false otherwise.
109      */
isHandleRenamedFiles()110     public boolean isHandleRenamedFiles() {
111         return this.handleRenamedFiles;
112     }
113 
114     /**
115      * @param flag true if the repository should handle renamed files, false otherwise.
116      */
setHandleRenamedFiles(boolean flag)117     public void setHandleRenamedFiles(boolean flag) {
118         this.handleRenamedFiles = flag;
119     }
120 
121     /**
122      * @return true if the repository handles merge commits.
123      */
isMergeCommitsEnabled()124     public boolean isMergeCommitsEnabled() {
125         return this.mergeCommitsEnabled;
126     }
127 
128     /**
129      * @param flag true if the repository should handle merge commits, false otherwise.
130      */
setMergeCommitsEnabled(boolean flag)131     public void setMergeCommitsEnabled(boolean flag) {
132         this.mergeCommitsEnabled = flag;
133     }
134 
135     /**
136      * @return true if history based reindex is enabled for the repository, false otherwise
137      */
isHistoryBasedReindex()138     public boolean isHistoryBasedReindex() {
139         return this.historyBasedReindex;
140     }
141 
142     /**
143      * @param flag if history based reindex should be enabled for the repository
144      */
setHistoryBasedReindex(boolean flag)145     public void setHistoryBasedReindex(boolean flag) {
146         this.historyBasedReindex = flag;
147     }
148 
149     /**
150      * @return true if the repository should have history cache.
151      */
isHistoryEnabled()152     public boolean isHistoryEnabled() {
153         return this.historyEnabled;
154     }
155 
setHistoryEnabled(boolean flag)156     public void setHistoryEnabled(boolean flag) {
157         this.historyEnabled = flag;
158     }
159 
160     /**
161      * @return relative path to source root
162      */
getDirectoryNameRelative()163     public String getDirectoryNameRelative() {
164         return directoryNameRelative;
165     }
166 
167     /**
168      * Set relative path to source root.
169      * @param dir directory
170      */
setDirectoryNameRelative(String dir)171     public void setDirectoryNameRelative(String dir) {
172         this.directoryNameRelative = dir;
173         this.directoryNameCanonical = null;
174     }
175 
176     /**
177      * Get the name of the root directory for this repository.
178      *
179      * @return the name of the root directory
180      */
getDirectoryName()181     public String getDirectoryName() {
182         return Paths.get(RuntimeEnvironment.getInstance().getSourceRootPath(),
183                 directoryNameRelative).toString();
184     }
185 
186     /**
187      * Get the canonical {@link #getDirectoryName()} of the root directory for
188      * this repository.
189      */
getCanonicalDirectoryName()190     String getCanonicalDirectoryName() throws IOException {
191         if (directoryNameCanonical == null) {
192             directoryNameCanonical = new File(getDirectoryName()).getCanonicalPath();
193         }
194         return directoryNameCanonical;
195     }
196 
197     /**
198      * Specify the name of the root directory for this repository.
199      *
200      * @param dir the new root directory
201      */
setDirectoryName(File dir)202     public void setDirectoryName(File dir) {
203         RuntimeEnvironment env = RuntimeEnvironment.getInstance();
204         String rootPath = env.getSourceRootPath();
205         String path;
206         String originalPath = dir.getPath();
207         try {
208             path = PathUtils.getRelativeToCanonical(dir.toPath(), Paths.get(rootPath));
209             // OpenGrok has a weird convention that directoryNameRelative must start with a path separator,
210             // as it is elsewhere directly appended to env.getSourceRootPath() and also stored as such.
211             if (!path.equals(originalPath)) {
212                 path = File.separator + path;
213             }
214         } catch (IOException e) {
215             path = originalPath;
216             LOGGER.log(Level.SEVERE, String.format("Failed to get canonical path for %s", path), e);
217         }
218 
219         if (path.startsWith(rootPath)) {
220             setDirectoryNameRelative(path.substring(rootPath.length()));
221         } else {
222             setDirectoryNameRelative(path);
223         }
224     }
225 
226     /**
227      * Returns true if this repository is usable in this context (for SCM
228      * systems that use external binaries, the binary must be available etc).
229      *
230      * @return true if the HistoryGuru may use the repository
231      */
isWorking()232     public boolean isWorking() {
233         return working != null && working;
234     }
235 
236     /**
237      * Set the property working.
238      *
239      * @param working is repository working
240      */
setWorking(Boolean working)241     public void setWorking(Boolean working) {
242         this.working = working;
243     }
244 
245     /**
246      * Is the history and version information for this repository stored on a
247      * remote server?
248      *
249      * @return true if the history is stored on a remote server.
250      */
isRemote()251     public boolean isRemote() {
252         return remote;
253     }
254 
255     /**
256      * Set the property remote.
257      *
258      * @param remote is remote repository
259      */
setRemote(boolean remote)260     public void setRemote(boolean remote) {
261         this.remote = remote;
262     }
263 
264     /**
265      * Get property type.
266      *
267      * @return type
268      */
getType()269     public String getType() {
270         return type;
271     }
272 
273     /**
274      * Set property type.
275      *
276      * @param type repository type
277      */
setType(String type)278     public void setType(String type) {
279         this.type = type;
280     }
281 
282     /**
283      * Get property parent.
284      *
285      * @return parent
286      */
getParent()287     public String getParent() {
288         return parent;
289     }
290 
291     /**
292      * Set property parent.
293      *
294      * @param parent parent of the repository
295      */
setParent(String parent)296     public void setParent(String parent) {
297         this.parent = parent;
298     }
299 
setDatePatterns(String[] datePatterns)300     public void setDatePatterns(String[] datePatterns) {
301         this.datePatterns = datePatterns;
302     }
303 
getDatePatterns()304     public String[] getDatePatterns() {
305         return datePatterns;
306     }
307 
getBranch()308     public String getBranch() {
309         return branch;
310     }
311 
setBranch(String branch)312     public void setBranch(String branch) {
313         this.branch = branch;
314     }
315 
getCurrentVersion()316     public String getCurrentVersion() {
317         return currentVersion;
318     }
319 
setCurrentVersion(String currentVersion)320     public void setCurrentVersion(String currentVersion) {
321         this.currentVersion = currentVersion;
322     }
323 
324     /**
325      * Fill configurable properties from associated project (if any) or Configuration.
326      */
fillFromProject()327     public void fillFromProject() {
328         Project proj = Project.getProject(getDirectoryNameRelative());
329         if (proj != null) {
330             setHistoryEnabled(proj.isHistoryEnabled());
331             setHandleRenamedFiles(proj.isHandleRenamedFiles());
332             setMergeCommitsEnabled(proj.isMergeCommitsEnabled());
333             setHistoryBasedReindex(proj.isHistoryBasedReindex());
334         } else {
335             RuntimeEnvironment env = RuntimeEnvironment.getInstance();
336 
337             setHistoryEnabled(env.isHistoryEnabled());
338             setHandleRenamedFiles(env.isHandleHistoryOfRenamedFiles());
339             setMergeCommitsEnabled(env.isMergeCommitsEnabled());
340             setHistoryBasedReindex(env.isHistoryBasedReindex());
341         }
342     }
343 
344     @Override
equals(Object obj)345     public boolean equals(Object obj) {
346         if (!(obj instanceof RepositoryInfo)) {
347             return false;
348         }
349 
350         RepositoryInfo ri = (RepositoryInfo) obj;
351 
352         // Directory paths should be unique.
353         if (ri.getDirectoryNameRelative() != null && this.getDirectoryNameRelative() != null) {
354             return ri.getDirectoryNameRelative().equals(this.getDirectoryNameRelative());
355         } else {
356             return (ri.getDirectoryNameRelative() == null && this.getDirectoryNameRelative() == null);
357         }
358     }
359 
360     @Override
hashCode()361     public int hashCode() {
362         int hash = 7;
363         hash = 89 * hash + Objects.hashCode(this.directoryNameRelative);
364         return hash;
365     }
366 
367     @Override
toString()368     public String toString() {
369         StringBuilder stringBuilder = new StringBuilder();
370         stringBuilder.append("{");
371         stringBuilder.append("dir=");
372         stringBuilder.append(this.getDirectoryName());
373         stringBuilder.append(",");
374         stringBuilder.append("type=");
375         stringBuilder.append(getType());
376         stringBuilder.append(",");
377 
378         if (!isHistoryEnabled()) {
379             stringBuilder.append("history=off");
380         } else {
381             stringBuilder.append("history=on,");
382             stringBuilder.append("renamed=");
383             stringBuilder.append(this.isHandleRenamedFiles());
384             stringBuilder.append(",");
385             stringBuilder.append("merge=");
386             stringBuilder.append(this.isMergeCommitsEnabled());
387         }
388         stringBuilder.append("}");
389         return stringBuilder.toString();
390     }
391 }
392