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 * The implementation's {@link #getRef(String)} method must take this search 73 * space into consideration when locating a reference by name. The first 74 * entry in the path is always {@code ""}, ensuring that absolute references 75 * are resolved 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 * Determine if a proposed reference name overlaps with an existing one. 115 * <p> 116 * Reference names use '/' as a component separator, and may be stored in a 117 * hierarchical storage such as a directory on the local filesystem. 118 * <p> 119 * If the reference "refs/heads/foo" exists then "refs/heads/foo/bar" must 120 * not exist, as a reference cannot have a value and also be a container for 121 * other references at the same time. 122 * <p> 123 * If the reference "refs/heads/foo/bar" exists than the reference 124 * "refs/heads/foo" cannot exist, for the same reason. 125 * 126 * @param name 127 * proposed name. 128 * @return true if the name overlaps with an existing reference; false if 129 * using this name right now would be safe. 130 * @throws java.io.IOException 131 * the database could not be read to check for conflicts. 132 * @see #getConflictingNames(String) 133 */ 134 public abstract boolean isNameConflicting(String name) throws IOException; 135 136 /** 137 * Determine if a proposed reference cannot coexist with existing ones. If 138 * the passed name already exists, it's not considered a conflict. 139 * 140 * @param name 141 * proposed name to check for conflicts against 142 * @return a collection of full names of existing refs which would conflict 143 * with the passed ref name; empty collection when there are no 144 * conflicts 145 * @throws java.io.IOException 146 * @since 2.3 147 * @see #isNameConflicting(String) 148 */ 149 @NonNull 150 public Collection<String> getConflictingNames(String name) 151 throws IOException { 152 Map<String, Ref> allRefs = getRefs(ALL); 153 // Cannot be nested within an existing reference. 154 int lastSlash = name.lastIndexOf('/'); 155 while (0 < lastSlash) { 156 String needle = name.substring(0, lastSlash); 157 if (allRefs.containsKey(needle)) 158 return Collections.singletonList(needle); 159 lastSlash = name.lastIndexOf('/', lastSlash - 1); 160 } 161 162 List<String> conflicting = new ArrayList<>(); 163 // Cannot be the container of an existing reference. 164 String prefix = name + '/'; 165 for (String existing : allRefs.keySet()) 166 if (existing.startsWith(prefix)) 167 conflicting.add(existing); 168 169 return conflicting; 170 } 171 172 /** 173 * Create a new update command to create, modify or delete a reference. 174 * 175 * @param name 176 * the name of the reference. 177 * @param detach 178 * if {@code true} and {@code name} is currently a 179 * {@link org.eclipse.jgit.lib.SymbolicRef}, the update will 180 * replace it with an {@link org.eclipse.jgit.lib.ObjectIdRef}. 181 * Otherwise, the update will recursively traverse 182 * {@link org.eclipse.jgit.lib.SymbolicRef}s and operate on the 183 * leaf {@link org.eclipse.jgit.lib.ObjectIdRef}. 184 * @return a new update for the requested name; never null. 185 * @throws java.io.IOException 186 * the reference space cannot be accessed. 187 */ 188 @NonNull 189 public abstract RefUpdate newUpdate(String name, boolean detach) 190 throws IOException; 191 192 /** 193 * Create a new update command to rename a reference. 194 * 195 * @param fromName 196 * name of reference to rename from 197 * @param toName 198 * name of reference to rename to 199 * @return an update command that knows how to rename a branch to another. 200 * @throws java.io.IOException 201 * the reference space cannot be accessed. 202 */ 203 @NonNull 204 public abstract RefRename newRename(String fromName, String toName) 205 throws IOException; 206 207 /** 208 * Create a new batch update to attempt on this database. 209 * <p> 210 * The default implementation performs a sequential update of each command. 211 * 212 * @return a new batch update object. 213 */ 214 @NonNull 215 public BatchRefUpdate newBatchUpdate() { 216 return new BatchRefUpdate(this); 217 } 218 219 /** 220 * Whether the database is capable of performing batch updates as atomic 221 * transactions. 222 * <p> 223 * If true, by default {@link org.eclipse.jgit.lib.BatchRefUpdate} instances 224 * will perform updates atomically, meaning either all updates will succeed, 225 * or all updates will fail. It is still possible to turn off this behavior 226 * on a per-batch basis by calling {@code update.setAtomic(false)}. 227 * <p> 228 * If false, {@link org.eclipse.jgit.lib.BatchRefUpdate} instances will 229 * never perform updates atomically, and calling 230 * {@code update.setAtomic(true)} will cause the entire batch to fail with 231 * {@code REJECTED_OTHER_REASON}. 232 * <p> 233 * This definition of atomicity is stronger than what is provided by 234 * {@link org.eclipse.jgit.transport.ReceivePack}. {@code ReceivePack} will 235 * attempt to reject all commands if it knows in advance some commands may 236 * fail, even if the storage layer does not support atomic transactions. 237 * Here, atomicity applies even in the case of unforeseeable errors. 238 * 239 * @return whether transactions are atomic by default. 240 * @since 3.6 241 */ 242 public boolean performsAtomicTransactions() { 243 return false; 244 } 245 246 /** 247 * Read a single reference. 248 * <p> 249 * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be 250 * able to more quickly resolve a single reference name than obtaining the 251 * complete namespace by {@code getRefs(ALL).get(name)}. 252 * <p> 253 * To read a specific reference without using @{link #SEARCH_PATH}, see 254 * {@link #exactRef(String)}. 255 * 256 * @param name 257 * the name of the reference. May be a short name which must be 258 * searched for using the standard {@link #SEARCH_PATH}. 259 * @return the reference (if it exists); else {@code null}. 260 * @throws java.io.IOException 261 * the reference space cannot be accessed. 262 */ 263 @Nullable 264 public abstract Ref getRef(String name) throws IOException; 265 266 /** 267 * Read a single reference. 268 * <p> 269 * Unlike {@link #getRef}, this method expects an unshortened reference 270 * name and does not search using the standard {@link #SEARCH_PATH}. 271 * 272 * @param name 273 * the unabbreviated name of the reference. 274 * @return the reference (if it exists); else {@code null}. 275 * @throws java.io.IOException 276 * the reference space cannot be accessed. 277 * @since 4.1 278 */ 279 @Nullable 280 public Ref exactRef(String name) throws IOException { 281 Ref ref = getRef(name); 282 if (ref == null || !name.equals(ref.getName())) { 283 return null; 284 } 285 return ref; 286 } 287 288 /** 289 * Read the specified references. 290 * <p> 291 * This method expects a list of unshortened reference names and returns 292 * a map from reference names to refs. Any named references that do not 293 * exist will not be included in the returned map. 294 * 295 * @param refs 296 * the unabbreviated names of references to look up. 297 * @return modifiable map describing any refs that exist among the ref 298 * ref names supplied. The map can be an unsorted map. 299 * @throws java.io.IOException 300 * the reference space cannot be accessed. 301 * @since 4.1 302 */ 303 @NonNull 304 public Map<String, Ref> exactRef(String... refs) throws IOException { 305 Map<String, Ref> result = new HashMap<>(refs.length); 306 for (String name : refs) { 307 Ref ref = exactRef(name); 308 if (ref != null) { 309 result.put(name, ref); 310 } 311 } 312 return result; 313 } 314 315 /** 316 * Find the first named reference. 317 * <p> 318 * This method expects a list of unshortened reference names and returns 319 * the first that exists. 320 * 321 * @param refs 322 * the unabbreviated names of references to look up. 323 * @return the first named reference that exists (if any); else {@code null}. 324 * @throws java.io.IOException 325 * the reference space cannot be accessed. 326 * @since 4.1 327 */ 328 @Nullable 329 public Ref firstExactRef(String... refs) throws IOException { 330 for (String name : refs) { 331 Ref ref = exactRef(name); 332 if (ref != null) { 333 return ref; 334 } 335 } 336 return null; 337 } 338 339 /** 340 * Returns all refs. 341 * <p> 342 * This includes {@code HEAD}, branches under {@code ref/heads/}, tags 343 * under {@code refs/tags/}, etc. It does not include pseudo-refs like 344 * {@code FETCH_HEAD}; for those, see {@link #getAdditionalRefs}. 345 * <p> 346 * Symbolic references to a non-existent ref (for example, 347 * {@code HEAD} pointing to a branch yet to be born) are not included. 348 * <p> 349 * Callers interested in only a portion of the ref hierarchy can call 350 * {@link #getRefsByPrefix} instead. 351 * 352 * @return immutable list of all refs. 353 * @throws java.io.IOException 354 * the reference space cannot be accessed. 355 * @since 5.0 356 */ 357 @NonNull 358 public List<Ref> getRefs() throws IOException { 359 return getRefsByPrefix(ALL); 360 } 361 362 /** 363 * Get a section of the reference namespace. 364 * 365 * @param prefix 366 * prefix to search the namespace with; must end with {@code /}. 367 * If the empty string ({@link #ALL}), obtain a complete snapshot 368 * of all references. 369 * @return modifiable map that is a complete snapshot of the current 370 * reference namespace, with {@code prefix} removed from the start 371 * of each key. The map can be an unsorted map. 372 * @throws java.io.IOException 373 * the reference space cannot be accessed. 374 * @deprecated use {@link #getRefsByPrefix} instead 375 */ 376 @NonNull 377 @Deprecated 378 public abstract Map<String, Ref> getRefs(String prefix) throws IOException; 379 380 /** 381 * Returns refs whose names start with a given prefix. 382 * <p> 383 * The default implementation uses {@link #getRefs(String)}. Implementors of 384 * {@link RefDatabase} should override this method directly if a better 385 * implementation is possible. 386 * 387 * @param prefix string that names of refs should start with; may be 388 * empty (to return all refs). 389 * @return immutable list of refs whose names start with {@code prefix}. 390 * @throws java.io.IOException 391 * the reference space cannot be accessed. 392 * @since 5.0 393 */ 394 @NonNull 395 public List<Ref> getRefsByPrefix(String prefix) throws IOException { 396 Map<String, Ref> coarseRefs; 397 int lastSlash = prefix.lastIndexOf('/'); 398 if (lastSlash == -1) { 399 coarseRefs = getRefs(ALL); 400 } else { 401 coarseRefs = getRefs(prefix.substring(0, lastSlash + 1)); 402 } 403 404 List<Ref> result; 405 if (lastSlash + 1 == prefix.length()) { 406 result = coarseRefs.values().stream().collect(toList()); 407 } else { 408 String p = prefix.substring(lastSlash + 1); 409 result = coarseRefs.entrySet().stream() 410 .filter(e -> e.getKey().startsWith(p)) 411 .map(e -> e.getValue()) 412 .collect(toList()); 413 } 414 return Collections.unmodifiableList(result); 415 } 416 417 /** 418 * Check if any refs exist in the ref database. 419 * <p> 420 * This uses the same definition of refs as {@link #getRefs()}. In 421 * particular, returns {@code false} in a new repository with no refs 422 * under {@code refs/} and {@code HEAD} pointing to a branch yet to be 423 * born, and returns {@code true} in a repository with no refs under 424 * {@code refs/} and a detached {@code HEAD} pointing to history. 425 * 426 * @return true if the database has refs. 427 * @throws java.io.IOException 428 * the reference space cannot be accessed. 429 * @since 5.0 430 */ 431 public boolean hasRefs() throws IOException { 432 return !getRefs().isEmpty(); 433 } 434 435 /** 436 * Get the additional reference-like entities from the repository. 437 * <p> 438 * The result list includes non-ref items such as MERGE_HEAD and 439 * FETCH_RESULT cast to be refs. The names of these refs are not returned by 440 * <code>getRefs()</code> but are accepted by {@link #getRef(String)} 441 * and {@link #exactRef(String)}. 442 * 443 * @return a list of additional refs 444 * @throws java.io.IOException 445 * the reference space cannot be accessed. 446 */ 447 @NonNull 448 public abstract List<Ref> getAdditionalRefs() throws IOException; 449 450 /** 451 * Peel a possibly unpeeled reference by traversing the annotated tags. 452 * <p> 453 * If the reference cannot be peeled (as it does not refer to an annotated 454 * tag) the peeled id stays null, but 455 * {@link org.eclipse.jgit.lib.Ref#isPeeled()} will be true. 456 * <p> 457 * Implementors should check {@link org.eclipse.jgit.lib.Ref#isPeeled()} 458 * before performing any additional work effort. 459 * 460 * @param ref 461 * The reference to peel 462 * @return {@code ref} if {@code ref.isPeeled()} is true; otherwise a new 463 * Ref object representing the same data as Ref, but isPeeled() will 464 * be true and getPeeledObjectId() will contain the peeled object 465 * (or {@code null}). 466 * @throws java.io.IOException 467 * the reference space or object space cannot be accessed. 468 */ 469 @NonNull 470 public abstract Ref peel(Ref ref) throws IOException; 471 472 /** 473 * Triggers a refresh of all internal data structures. 474 * <p> 475 * In case the RefDatabase implementation has internal caches this method 476 * will trigger that all these caches are cleared. 477 * <p> 478 * Implementors should overwrite this method if they use any kind of caches. 479 */ 480 public void refresh() { 481 // nothing 482 } 483 484 /** 485 * Try to find the specified name in the ref map using {@link #SEARCH_PATH}. 486 * 487 * @param map 488 * map of refs to search within. Names should be fully qualified, 489 * e.g. "refs/heads/master". 490 * @param name 491 * short name of ref to find, e.g. "master" to find 492 * "refs/heads/master" in map. 493 * @return The first ref matching the name, or {@code null} if not found. 494 * @since 3.4 495 */ 496 @Nullable 497 public static Ref findRef(Map<String, Ref> map, String name) { 498 for (String prefix : SEARCH_PATH) { 499 String fullname = prefix + name; 500 Ref ref = map.get(fullname); 501 if (ref != null) 502 return ref; 503 } 504 return null; 505 } 506 }