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 }