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