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