1 /*
2 * Copyright (C) 2010, 2013 Google Inc. and others
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Distribution License v. 1.0 which is available at
6 * https://www.eclipse.org/org/documents/edl-v10.php.
7 *
8 * SPDX-License-Identifier: BSD-3-Clause
9 */
10
11 package org.eclipse.jgit.lib;
12
13 import static java.util.stream.Collectors.toList;
14 import static java.util.stream.Collectors.toSet;
15
16 import java.io.IOException;
17 import java.util.ArrayList;
18 import java.util.Collection;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.stream.Collectors;
25 import java.util.stream.Stream;
26
27 import org.eclipse.jgit.annotations.NonNull;
28 import org.eclipse.jgit.annotations.Nullable;
29
30 /**
31 * Abstraction of name to {@link org.eclipse.jgit.lib.ObjectId} mapping.
32 * <p>
33 * A reference database stores a mapping of reference names to
34 * {@link org.eclipse.jgit.lib.ObjectId}. Every
35 * {@link org.eclipse.jgit.lib.Repository} has a single reference database,
36 * mapping names to the tips of the object graph contained by the
37 * {@link org.eclipse.jgit.lib.ObjectDatabase}.
38 */
39 public abstract class RefDatabase {
40 /**
41 * Order of prefixes to search when using non-absolute references.
42 * <p>
43 * {@link #findRef(String)} takes this search space into consideration
44 * when locating a reference by name. The first entry in the path is
45 * always {@code ""}, ensuring that absolute references are resolved
46 * without further mangling.
47 */
48 protected static final String[] SEARCH_PATH = { "", //$NON-NLS-1$
49 Constants.R_REFS, //
50 Constants.R_TAGS, //
51 Constants.R_HEADS, //
52 Constants.R_REMOTES //
53 };
54
55 /**
56 * Maximum number of times a {@link SymbolicRef} can be traversed.
57 * <p>
58 * If the reference is nested deeper than this depth, the implementation
59 * should either fail, or at least claim the reference does not exist.
60 *
61 * @since 4.2
62 */
63 public static final int MAX_SYMBOLIC_REF_DEPTH = 5;
64
65 /**
66 * Magic value for {@link #getRefsByPrefix(String)} to return all
67 * references.
68 */
69 public static final String ALL = "";//$NON-NLS-1$
70
71 /**
72 * Initialize a new reference database at this location.
73 *
74 * @throws java.io.IOException
75 * the database could not be created.
76 */
77 public abstract void create() throws IOException;
78
79 /**
80 * Close any resources held by this database.
81 */
82 public abstract void close();
83
84 /**
85 * With versioning, each reference has a version number that increases on
86 * update. See {@link Ref#getUpdateIndex()}.
87 *
88 * @implSpec This method returns false by default. Implementations
89 * supporting versioning must override it to return true.
90 * @return true if the implementation assigns update indices to references.
91 * @since 5.3
92 */
93 public boolean hasVersioning() {
94 return false;
95 }
96
97 /**
98 * Determine if a proposed reference name overlaps with an existing one.
99 * <p>
100 * Reference names use '/' as a component separator, and may be stored in a
101 * hierarchical storage such as a directory on the local filesystem.
102 * <p>
103 * If the reference "refs/heads/foo" exists then "refs/heads/foo/bar" must
104 * not exist, as a reference cannot have a value and also be a container for
105 * other references at the same time.
106 * <p>
107 * If the reference "refs/heads/foo/bar" exists than the reference
108 * "refs/heads/foo" cannot exist, for the same reason.
109 *
110 * @param name
111 * proposed name.
112 * @return true if the name overlaps with an existing reference; false if
113 * using this name right now would be safe.
114 * @throws java.io.IOException
115 * the database could not be read to check for conflicts.
116 * @see #getConflictingNames(String)
117 */
118 public abstract boolean isNameConflicting(String name) throws IOException;
119
120 /**
121 * Determine if a proposed reference cannot coexist with existing ones. If
122 * the passed name already exists, it's not considered a conflict.
123 *
124 * @param name
125 * proposed name to check for conflicts against
126 * @return a collection of full names of existing refs which would conflict
127 * with the passed ref name; empty collection when there are no
128 * conflicts
129 * @throws java.io.IOException
130 * @since 2.3
131 * @see #isNameConflicting(String)
132 */
133 @NonNull
134 public Collection<String> getConflictingNames(String name)
135 throws IOException {
136 Map<String, Ref> allRefs = getRefs(ALL);
137 // Cannot be nested within an existing reference.
138 int lastSlash = name.lastIndexOf('/');
139 while (0 < lastSlash) {
140 String needle = name.substring(0, lastSlash);
141 if (allRefs.containsKey(needle))
142 return Collections.singletonList(needle);
143 lastSlash = name.lastIndexOf('/', lastSlash - 1);
144 }
145
146 List<String> conflicting = new ArrayList<>();
147 // Cannot be the container of an existing reference.
148 String prefix = name + '/';
149 for (String existing : allRefs.keySet())
150 if (existing.startsWith(prefix))
151 conflicting.add(existing);
152
153 return conflicting;
154 }
155
156 /**
157 * Create a new update command to create, modify or delete a reference.
158 *
159 * @param name
160 * the name of the reference.
161 * @param detach
162 * if {@code true} and {@code name} is currently a
163 * {@link org.eclipse.jgit.lib.SymbolicRef}, the update will
164 * replace it with an {@link org.eclipse.jgit.lib.ObjectIdRef}.
165 * Otherwise, the update will recursively traverse
166 * {@link org.eclipse.jgit.lib.SymbolicRef}s and operate on the
167 * leaf {@link org.eclipse.jgit.lib.ObjectIdRef}.
168 * @return a new update for the requested name; never null.
169 * @throws java.io.IOException
170 * the reference space cannot be accessed.
171 */
172 @NonNull
173 public abstract RefUpdate newUpdate(String name, boolean detach)
174 throws IOException;
175
176 /**
177 * Create a new update command to rename a reference.
178 *
179 * @param fromName
180 * name of reference to rename from
181 * @param toName
182 * name of reference to rename to
183 * @return an update command that knows how to rename a branch to another.
184 * @throws java.io.IOException
185 * the reference space cannot be accessed.
186 */
187 @NonNull
188 public abstract RefRename newRename(String fromName, String toName)
189 throws IOException;
190
191 /**
192 * Create a new batch update to attempt on this database.
193 * <p>
194 * The default implementation performs a sequential update of each command.
195 *
196 * @return a new batch update object.
197 */
198 @NonNull
199 public BatchRefUpdate newBatchUpdate() {
200 return new BatchRefUpdate(this);
201 }
202
203 /**
204 * Whether the database is capable of performing batch updates as atomic
205 * transactions.
206 * <p>
207 * If true, by default {@link org.eclipse.jgit.lib.BatchRefUpdate} instances
208 * will perform updates atomically, meaning either all updates will succeed,
209 * or all updates will fail. It is still possible to turn off this behavior
210 * on a per-batch basis by calling {@code update.setAtomic(false)}.
211 * <p>
212 * If false, {@link org.eclipse.jgit.lib.BatchRefUpdate} instances will
213 * never perform updates atomically, and calling
214 * {@code update.setAtomic(true)} will cause the entire batch to fail with
215 * {@code REJECTED_OTHER_REASON}.
216 * <p>
217 * This definition of atomicity is stronger than what is provided by
218 * {@link org.eclipse.jgit.transport.ReceivePack}. {@code ReceivePack} will
219 * attempt to reject all commands if it knows in advance some commands may
220 * fail, even if the storage layer does not support atomic transactions.
221 * Here, atomicity applies even in the case of unforeseeable errors.
222 *
223 * @return whether transactions are atomic by default.
224 * @since 3.6
225 */
226 public boolean performsAtomicTransactions() {
227 return false;
228 }
229
230 /**
231 * Compatibility synonym for {@link #findRef(String)}.
232 *
233 * @param name
234 * the name of the reference. May be a short name which must be
235 * searched for using the standard {@link #SEARCH_PATH}.
236 * @return the reference (if it exists); else {@code null}.
237 * @throws IOException
238 * the reference space cannot be accessed.
239 * @deprecated Use {@link #findRef(String)} instead.
240 */
241 @Deprecated
242 @Nullable
243 public final Ref getRef(String name) throws IOException {
244 return findRef(name);
245 }
246
247 /**
248 * Read a single reference.
249 * <p>
250 * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be
251 * able to more quickly resolve a single reference name than obtaining the
252 * complete namespace by {@code getRefs(ALL).get(name)}.
253 * <p>
254 * To read a specific reference without using @{link #SEARCH_PATH}, see
255 * {@link #exactRef(String)}.
256 *
257 * @param name
258 * the name of the reference. May be a short name which must be
259 * searched for using the standard {@link #SEARCH_PATH}.
260 * @return the reference (if it exists); else {@code null}.
261 * @throws java.io.IOException
262 * the reference space cannot be accessed.
263 * @since 5.3
264 */
265 @Nullable
266 public final Ref findRef(String name) throws IOException {
267 String[] names = new String[SEARCH_PATH.length];
268 for (int i = 0; i < SEARCH_PATH.length; i++) {
269 names[i] = SEARCH_PATH[i] + name;
270 }
271 return firstExactRef(names);
272 }
273
274 /**
275 * Read a single reference.
276 * <p>
277 * Unlike {@link #findRef}, this method expects an unshortened reference
278 * name and does not search using the standard {@link #SEARCH_PATH}.
279 *
280 * @param name
281 * the unabbreviated name of the reference.
282 * @return the reference (if it exists); else {@code null}.
283 * @throws java.io.IOException
284 * the reference space cannot be accessed.
285 * @since 4.1
286 */
287 @Nullable
288 public abstract Ref exactRef(String name) throws IOException;
289
290 /**
291 * Read the specified references.
292 * <p>
293 * This method expects a list of unshortened reference names and returns
294 * a map from reference names to refs. Any named references that do not
295 * exist will not be included in the returned map.
296 *
297 * @param refs
298 * the unabbreviated names of references to look up.
299 * @return modifiable map describing any refs that exist among the ref
300 * ref names supplied. The map can be an unsorted map.
301 * @throws java.io.IOException
302 * the reference space cannot be accessed.
303 * @since 4.1
304 */
305 @NonNull
306 public Map<String, Ref> exactRef(String... refs) throws IOException {
307 Map<String, Ref> result = new HashMap<>(refs.length);
308 for (String name : refs) {
309 Ref ref = exactRef(name);
310 if (ref != null) {
311 result.put(name, ref);
312 }
313 }
314 return result;
315 }
316
317 /**
318 * Find the first named reference.
319 * <p>
320 * This method expects a list of unshortened reference names and returns
321 * the first that exists.
322 *
323 * @param refs
324 * the unabbreviated names of references to look up.
325 * @return the first named reference that exists (if any); else {@code null}.
326 * @throws java.io.IOException
327 * the reference space cannot be accessed.
328 * @since 4.1
329 */
330 @Nullable
331 public Ref firstExactRef(String... refs) throws IOException {
332 for (String name : refs) {
333 Ref ref = exactRef(name);
334 if (ref != null) {
335 return ref;
336 }
337 }
338 return null;
339 }
340
341 /**
342 * Returns all refs.
343 * <p>
344 * This includes {@code HEAD}, branches under {@code ref/heads/}, tags
345 * under {@code refs/tags/}, etc. It does not include pseudo-refs like
346 * {@code FETCH_HEAD}; for those, see {@link #getAdditionalRefs}.
347 * <p>
348 * Symbolic references to a non-existent ref (for example,
349 * {@code HEAD} pointing to a branch yet to be born) are not included.
350 * <p>
351 * Callers interested in only a portion of the ref hierarchy can call
352 * {@link #getRefsByPrefix} instead.
353 *
354 * @return immutable list of all refs.
355 * @throws java.io.IOException
356 * the reference space cannot be accessed.
357 * @since 5.0
358 */
359 @NonNull
360 public List<Ref> getRefs() throws IOException {
361 return getRefsByPrefix(ALL);
362 }
363
364 /**
365 * Get a section of the reference namespace.
366 *
367 * @param prefix
368 * prefix to search the namespace with; must end with {@code /}.
369 * If the empty string ({@link #ALL}), obtain a complete snapshot
370 * of all references.
371 * @return modifiable map that is a complete snapshot of the current
372 * reference namespace, with {@code prefix} removed from the start
373 * of each key. The map can be an unsorted map.
374 * @throws java.io.IOException
375 * the reference space cannot be accessed.
376 * @deprecated use {@link #getRefsByPrefix} instead
377 */
378 @NonNull
379 @Deprecated
380 public abstract Map<String, Ref> getRefs(String prefix) throws IOException;
381
382 /**
383 * Returns refs whose names start with a given prefix.
384 * <p>
385 * The default implementation uses {@link #getRefs(String)}. Implementors of
386 * {@link RefDatabase} should override this method directly if a better
387 * implementation is possible.
388 *
389 * @param prefix string that names of refs should start with; may be
390 * empty (to return all refs).
391 * @return immutable list of refs whose names start with {@code prefix}.
392 * @throws java.io.IOException
393 * the reference space cannot be accessed.
394 * @since 5.0
395 */
396 @NonNull
397 public List<Ref> getRefsByPrefix(String prefix) throws IOException {
398 Map<String, Ref> coarseRefs;
399 int lastSlash = prefix.lastIndexOf('/');
400 if (lastSlash == -1) {
401 coarseRefs = getRefs(ALL);
402 } else {
403 coarseRefs = getRefs(prefix.substring(0, lastSlash + 1));
404 }
405
406 List<Ref> result;
407 if (lastSlash + 1 == prefix.length()) {
408 result = coarseRefs.values().stream().collect(toList());
409 } else {
410 String p = prefix.substring(lastSlash + 1);
411 result = coarseRefs.entrySet().stream()
412 .filter(e -> e.getKey().startsWith(p))
413 .map(e -> e.getValue())
414 .collect(toList());
415 }
416 return Collections.unmodifiableList(result);
417 }
418
419 /**
420 * Returns refs whose names start with a given prefix excluding all refs that
421 * start with one of the given prefixes.
422 *
423 * <p>
424 * The default implementation is not efficient. Implementors of {@link RefDatabase}
425 * should override this method directly if a better implementation is possible.
426 *
427 * @param include string that names of refs should start with; may be empty.
428 * @param excludes strings that names of refs can't start with; may be empty.
429 * @return immutable list of refs whose names start with {@code prefix} and none
430 * of the strings in {@code exclude}.
431 * @throws java.io.IOException the reference space cannot be accessed.
432 * @since 5.11
433 */
434 @NonNull
435 public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes)
436 throws IOException {
437 Stream<Ref> refs = getRefs(include).values().stream();
438 for(String exclude: excludes) {
439 refs = refs.filter(r -> !r.getName().startsWith(exclude));
440 }
441 return Collections.unmodifiableList(refs.collect(Collectors.toList()));
442 }
443
444 /**
445 * Returns refs whose names start with one of the given prefixes.
446 * <p>
447 * The default implementation uses {@link #getRefsByPrefix(String)}.
448 * Implementors of {@link RefDatabase} should override this method directly
449 * if a better implementation is possible.
450 *
451 * @param prefixes
452 * strings that names of refs should start with.
453 * @return immutable list of refs whose names start with one of
454 * {@code prefixes}. Refs can be unsorted and may contain duplicates
455 * if the prefixes overlap.
456 * @throws java.io.IOException
457 * the reference space cannot be accessed.
458 * @since 5.2
459 */
460 @NonNull
461 public List<Ref> getRefsByPrefix(String... prefixes) throws IOException {
462 List<Ref> result = new ArrayList<>();
463 for (String prefix : prefixes) {
464 result.addAll(getRefsByPrefix(prefix));
465 }
466 return Collections.unmodifiableList(result);
467 }
468
469
470 /**
471 * Returns all refs that resolve directly to the given {@link ObjectId}.
472 * Includes peeled {@link ObjectId}s. This is the inverse lookup of
473 * {@link #exactRef(String...)}.
474 *
475 * <p>
476 * The default implementation uses a linear scan. Implementors of
477 * {@link RefDatabase} should override this method directly if a better
478 * implementation is possible.
479 *
480 * @param id
481 * {@link ObjectId} to resolve
482 * @return a {@link Set} of {@link Ref}s whose tips point to the provided
483 * id.
484 * @throws java.io.IOException
485 * the reference space cannot be accessed.
486 * @since 5.4
487 */
488 @NonNull
489 public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException {
490 return getRefs().stream().filter(r -> id.equals(r.getObjectId())
491 || id.equals(r.getPeeledObjectId())).collect(toSet());
492 }
493
494 /**
495 * If the ref database does not support fast inverse queries, it may
496 * be advantageous to build a complete SHA1 to ref map in advance for
497 * multiple uses. To let applications decide on this decision,
498 * this function indicates whether the inverse map is available.
499 *
500 * @return whether this RefDatabase supports fast inverse ref queries.
501 * @throws IOException on I/O problems.
502 * @since 5.6
503 */
504 public boolean hasFastTipsWithSha1() throws IOException {
505 return false;
506 }
507
508 /**
509 * Check if any refs exist in the ref database.
510 * <p>
511 * This uses the same definition of refs as {@link #getRefs()}. In
512 * particular, returns {@code false} in a new repository with no refs
513 * under {@code refs/} and {@code HEAD} pointing to a branch yet to be
514 * born, and returns {@code true} in a repository with no refs under
515 * {@code refs/} and a detached {@code HEAD} pointing to history.
516 *
517 * @return true if the database has refs.
518 * @throws java.io.IOException
519 * the reference space cannot be accessed.
520 * @since 5.0
521 */
522 public boolean hasRefs() throws IOException {
523 return !getRefs().isEmpty();
524 }
525
526 /**
527 * Get the additional reference-like entities from the repository.
528 * <p>
529 * The result list includes non-ref items such as MERGE_HEAD and
530 * FETCH_RESULT cast to be refs. The names of these refs are not returned by
531 * <code>getRefs()</code> but are accepted by {@link #findRef(String)}
532 * and {@link #exactRef(String)}.
533 *
534 * @return a list of additional refs
535 * @throws java.io.IOException
536 * the reference space cannot be accessed.
537 */
538 @NonNull
539 public abstract List<Ref> getAdditionalRefs() throws IOException;
540
541 /**
542 * Peel a possibly unpeeled reference by traversing the annotated tags.
543 * <p>
544 * If the reference cannot be peeled (as it does not refer to an annotated
545 * tag) the peeled id stays null, but
546 * {@link org.eclipse.jgit.lib.Ref#isPeeled()} will be true.
547 * <p>
548 * Implementors should check {@link org.eclipse.jgit.lib.Ref#isPeeled()}
549 * before performing any additional work effort.
550 *
551 * @param ref
552 * The reference to peel
553 * @return {@code ref} if {@code ref.isPeeled()} is true; otherwise a new
554 * Ref object representing the same data as Ref, but isPeeled() will
555 * be true and getPeeledObjectId() will contain the peeled object
556 * (or {@code null}).
557 * @throws java.io.IOException
558 * the reference space or object space cannot be accessed.
559 */
560 @NonNull
561 public abstract Ref peel(Ref ref) throws IOException;
562
563 /**
564 * Triggers a refresh of all internal data structures.
565 * <p>
566 * In case the RefDatabase implementation has internal caches this method
567 * will trigger that all these caches are cleared.
568 * <p>
569 * Implementors should overwrite this method if they use any kind of caches.
570 */
571 public void refresh() {
572 // nothing
573 }
574
575 /**
576 * Try to find the specified name in the ref map using {@link #SEARCH_PATH}.
577 *
578 * @param map
579 * map of refs to search within. Names should be fully qualified,
580 * e.g. "refs/heads/master".
581 * @param name
582 * short name of ref to find, e.g. "master" to find
583 * "refs/heads/master" in map.
584 * @return The first ref matching the name, or {@code null} if not found.
585 * @since 3.4
586 */
587 @Nullable
588 public static Ref findRef(Map<String, Ref> map, String name) {
589 for (String prefix : SEARCH_PATH) {
590 String fullname = prefix + name;
591 Ref ref = map.get(fullname);
592 if (ref != null)
593 return ref;
594 }
595 return null;
596 }
597 }