View Javadoc
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 }