• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

oracle / opengrok / #3691

09 Nov 2023 04:15PM UTC coverage: 74.721% (+8.6%) from 66.08%
#3691

push

web-flow
avoid annotations for binary files (#4476)

fixes #4473

6 of 13 new or added lines in 4 files covered. (46.15%)

258 existing lines in 28 files now uncovered.

43797 of 58614 relevant lines covered (74.72%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.05
/opengrok-indexer/src/main/java/org/opengrok/indexer/history/RepositoryFactory.java
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, 2020, 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.lang.reflect.InvocationTargetException;
29
import java.util.ArrayList;
30
import java.util.HashMap;
31
import java.util.List;
32
import java.util.Locale;
33
import java.util.Map;
34
import java.util.Set;
35
import java.util.logging.Level;
36
import java.util.logging.Logger;
37

38
import org.opengrok.indexer.configuration.CommandTimeoutType;
39
import org.opengrok.indexer.configuration.Configuration;
40
import org.opengrok.indexer.configuration.IgnoredNames;
41
import org.opengrok.indexer.configuration.RuntimeEnvironment;
42
import org.opengrok.indexer.logger.LoggerFactory;
43
import org.opengrok.indexer.util.ForbiddenSymlinkException;
44

45
/**
46
 * This is a factory class for the different repositories.
47
 *
48
 * @author austvik
49
 */
50
public final class RepositoryFactory {
51

52
    private static final Logger LOGGER = LoggerFactory.getLogger(RepositoryFactory.class);
1✔
53

54
    private static final Repository[] repositories = {
1✔
55
            /*
56
             * The following do cheap checks to determine isRepositoryFor(),
57
             * but still put the most popular at the head of the repositories
58
             * array.
59
             */
60
            new GitRepository(),
61
            new MercurialRepository(),
62
            new RepoRepository(),
63
            new BitKeeperRepository(),
64
            new BazaarRepository(),
65
            new MonotoneRepository(),
66
            new SubversionRepository(),
67
            new SCCSRepository(),
68
            new RazorRepository(),
69
            new RCSRepository(),
70
            new CVSRepository(),
71
            new SSCMRepository(),
72
            /*
73
             * The following do expensive checks to determine isRepositoryFor(),
74
             * so put them at the end of the repositories array.
75
             */
76
            new AccuRevRepository(),
77
            new ClearCaseRepository(),
78
            new PerforceRepository()
79
    };
80

81
    private static final Map<String, Class<? extends Repository>> byName = new HashMap<>();
1✔
82

83
    static {
84
        final String REPOSITORY = "Repository";
1✔
85
        for (Repository repository : repositories) {
1✔
86
            Class<? extends Repository> clazz = repository.getClass();
1✔
87
            String repoName = clazz.getSimpleName();
1✔
88
            byName.put(repoName, clazz);
1✔
89
            byName.put(repoName.toLowerCase(Locale.ROOT), clazz);
1✔
90
            if (repoName.endsWith(REPOSITORY)) {
1✔
91
                String shortName = repoName.substring(0, repoName.length() - REPOSITORY.length());
1✔
92
                if (shortName.length() > 0) {
1✔
93
                    byName.put(shortName, clazz);
1✔
94
                    byName.put(shortName.toLowerCase(Locale.ROOT), clazz);
1✔
95
                }
96
            }
97
        }
98
    }
1✔
99

100
    /** Private to enforce static. */
101
    private RepositoryFactory() {
102
    }
103

104
    /**
105
     * Get a list of all available repository handlers.
106
     *
107
     * @return a list that contains non-{@code null} values only
108
     */
109
    public static List<Class<? extends Repository>> getRepositoryClasses() {
110
        ArrayList<Class<? extends Repository>> list = new ArrayList<>(repositories.length);
1✔
111
        for (int i = repositories.length - 1; i >= 0; i--) {
1✔
112
            Class<? extends Repository> clazz = repositories[i].getClass();
1✔
113
            if (isEnabled(clazz)) {
1✔
114
                list.add(clazz);
1✔
115
            }
116
        }
117

118
        return list;
1✔
119
    }
120

121
    /**
122
     * Gets a list of all disabled repository handlers.
123
     * @return a list that contains non-{@code null} values only
124
     */
125
    public static List<Class<? extends Repository>> getDisabledRepositoryClasses() {
126
        ArrayList<Class<? extends Repository>> list = new ArrayList<>();
1✔
127
        for (int i = repositories.length - 1; i >= 0; i--) {
1✔
128
            Class<? extends Repository> clazz = repositories[i].getClass();
1✔
129
            if (!isEnabled(clazz)) {
1✔
130
                list.add(clazz);
×
131
            }
132
        }
133

134
        return list;
1✔
135
    }
136

137
    /**
138
     * Calls {@link #getRepository(File, CommandTimeoutType)} with {@code file} and {@code false}.
139
     */
140
    public static Repository getRepository(File file)
141
            throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException,
142
            IOException, ForbiddenSymlinkException {
143
        return getRepository(file, CommandTimeoutType.INDEXER);
1✔
144
    }
145

146
    /**
147
     * Calls {@link #getRepository(File, CommandTimeoutType, boolean)} with {@code file}, {@code interactive},
148
     * and {@code false}.
149
     * @param file file
150
     * @param cmdType command timeout type
151
     * @return repository object
152
     * @throws IllegalAccessException on error
153
     * @throws InvocationTargetException on error
154
     * @throws ForbiddenSymlinkException on error
155
     * @throws InstantiationException on error
156
     * @throws NoSuchMethodException on error
157
     * @throws IOException on error
158
     */
159
    public static Repository getRepository(File file, CommandTimeoutType cmdType)
160
            throws IllegalAccessException, InvocationTargetException, ForbiddenSymlinkException, InstantiationException,
161
            NoSuchMethodException, IOException {
162
        return getRepository(file, cmdType, false);
1✔
163
    }
164

165
    /**
166
     * Returns a repository for the given file, or null if no repository was found.
167
     * <p>
168
     * Note that the operations performed by this method take quite a long time
169
     * thanks to external commands being executed. For that reason, when run
170
     * on multiple files, it should be parallelized (e.g. like it is done in
171
     * {@code invalidateRepositories()}) and the commands run within should
172
     * use interactive command timeout (as specified in {@code Configuration}).
173
     * </p>
174
     * @param file File that might contain a repository
175
     * @param cmdType command timeout type
176
     * @param isNested a value indicating if a nestable {@link Repository} is required
177
     * @return Correct repository for the given file or {@code null}
178
     * @throws InstantiationException in case we cannot create the repository object
179
     * @throws IllegalAccessException in case no permissions to repository file
180
     * @throws NoSuchMethodException in case we cannot create the repository object
181
     * @throws InvocationTargetException in case we cannot create the repository object
182
     * @throws IOException when resolving repository path
183
     * @throws ForbiddenSymlinkException when resolving repository path
184
     */
185
    public static Repository getRepository(File file, CommandTimeoutType cmdType, boolean isNested)
186
            throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException,
187
            IOException, ForbiddenSymlinkException {
188

189
        RuntimeEnvironment env = RuntimeEnvironment.getInstance();
1✔
190
        String relFile = env.getPathRelativeToSourceRoot(file);
1✔
191

192
        Repository repo = null;
1✔
193
        for (Repository referenceRepo : repositories) {
1✔
194
            Class<? extends Repository> clazz = referenceRepo.getClass();
1✔
195

196
            if ((!isNested || referenceRepo.isNestable()) && isEnabled(clazz) &&
1✔
197
                    referenceRepo.isRepositoryFor(file, cmdType)) {
1✔
198

199
                repo = clazz.getDeclaredConstructor().newInstance();
1✔
200

201
                if (env.isProjectsEnabled() && relFile.equals(File.separator)) {
1✔
202
                    LOGGER.log(Level.WARNING, "{0} was detected as {1} repository however with directory " +
1✔
203
                            "matching source root. This is invalid because projects are enabled. Ignoring this " +
204
                            "repository.",
205
                            new Object[]{file, repo.getType()});
1✔
206
                    return null;
1✔
207
                }
208
                repo.setDirectoryName(file);
1✔
209

210
                if (!repo.isWorking()) {
1✔
211
                    LOGGER.log(Level.WARNING, "{0} not working (missing binaries?): {1}",
1✔
212
                            new Object[]{
213
                                repo.getClass().getSimpleName(),
1✔
214
                                file.getPath()
1✔
215
                            });
216
                }
217

218
                if (repo.getType() == null || repo.getType().length() == 0) {
1✔
219
                    repo.setType(repo.getClass().getSimpleName());
×
220
                }
221

222
                if (repo.getParent() == null || repo.getParent().length() == 0) {
1✔
223
                    try {
224
                        repo.setParent(repo.determineParent(cmdType));
1✔
225
                    } catch (IOException ex) {
1✔
226
                        LOGGER.log(Level.WARNING,
1✔
227
                                "Failed to get parent for {0}: {1}",
228
                                new Object[]{file.getAbsolutePath(), ex});
1✔
229
                    }
1✔
230
                }
231

232
                if (repo.getBranch() == null || repo.getBranch().length() == 0) {
1✔
233
                    try {
234
                        repo.setBranch(repo.determineBranch(cmdType));
1✔
235
                    } catch (IOException ex) {
1✔
236
                        LOGGER.log(Level.WARNING,
1✔
237
                                "Failed to get branch for {0}: {1}",
238
                                new Object[]{file.getAbsolutePath(), ex});
1✔
239
                    }
1✔
240
                }
241

242
                if (repo.getCurrentVersion() == null || repo.getCurrentVersion().length() == 0) {
1✔
243
                    try {
244
                        repo.setCurrentVersion(repo.determineCurrentVersion(cmdType));
1✔
245
                    } catch (IOException ex) {
1✔
246
                        LOGGER.log(Level.WARNING,
1✔
247
                                "Failed to determineCurrentVersion for {0}: {1}",
248
                                new Object[]{file.getAbsolutePath(), ex});
1✔
249
                    }
1✔
250
                }
251

252
                // If this repository displays tags only for files changed by tagged
253
                // revision, we need to prepare list of all tags in advance.
254
                if (cmdType.equals(CommandTimeoutType.INDEXER) && env.isTagsEnabled() && repo.hasFileBasedTags()) {
1✔
UNCOV
255
                    repo.buildTagList(file, cmdType);
×
256
                }
257

258
                repo.fillFromProject();
1✔
259

260
                break;
1✔
261
            }
262
        }
263

264
        return repo;
1✔
265
    }
266

267
    /**
268
     * Returns a repository for the given file, or null if no repository was found.
269
     *
270
     * @param info Information about the repository
271
     * @param cmdType command timeout type
272
     * @return Correct repository for the given file
273
     * @throws InstantiationException in case we cannot create the repository object
274
     * @throws IllegalAccessException in case no permissions to repository
275
     * @throws NoSuchMethodException in case we cannot create the repository object
276
     * @throws InvocationTargetException in case we cannot create the repository object
277
     * @throws IOException when resolving repository path
278
     * @throws ForbiddenSymlinkException when resolving repository path
279
     */
280
    public static Repository getRepository(RepositoryInfo info, CommandTimeoutType cmdType)
281
            throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException,
282
            IOException, ForbiddenSymlinkException {
283
        return getRepository(new File(info.getDirectoryName()), cmdType);
1✔
284
    }
285

286
    /**
287
     * Go through all supported repository types, and add their ignored items to
288
     * the environment's lists of ignored files/directories -- but skip any
289
     * repository types which are named in
290
     * {@link RuntimeEnvironment#getDisabledRepositories()} ()}. This way
291
     * per-repository ignored entries are set inside repository classes rather
292
     * than globally in IgnoredFiles/Dirs.
293
     * <p>
294
     * (Should be called after
295
     * {@link RuntimeEnvironment#setConfiguration(Configuration)}.)
296
     */
297
    public static void initializeIgnoredNames(RuntimeEnvironment env) {
298
        IgnoredNames ignoredNames = env.getIgnoredNames();
1✔
299
        for (Repository repo : repositories) {
1✔
300
            if (isEnabled(repo.getClass())) {
1✔
301
                for (String file : repo.getIgnoredFiles()) {
1✔
302
                    ignoredNames.add("f:" + file);
1✔
303
                }
1✔
304
                for (String dir : repo.getIgnoredDirs()) {
1✔
305
                    ignoredNames.add("d:" + dir);
1✔
306
                }
1✔
307
            }
308
        }
309
    }
1✔
310

311
    /**
312
     * Tries to match a supported repositories by name or nickname -- e.g.
313
     * {@code "CVSRepository"} or {@code "CVS"} or {@code "cvs"}.
314
     * @return a defined, class simple name (e.g. {@code "CVSRepository"} when
315
     * {@code "cvs"} is passed); or {@code null} if no match found
316
     */
317
    public static String matchRepositoryByName(String name) {
318
        Class<? extends Repository> clazz = byName.get(name);
×
319
        if (clazz != null) {
×
320
            return clazz.getSimpleName();
×
321
        }
322
        return null;
×
323
    }
324

325
    private static boolean isEnabled(Class<? extends Repository> clazz) {
326
        Set<String> disabledRepos = RuntimeEnvironment.getInstance().getDisabledRepositories();
1✔
327
        return disabledRepos == null || !disabledRepos.contains(clazz.getSimpleName());
1✔
328
    }
329
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc