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 java.io.IOException; 47 import java.util.ArrayList; 48 import java.util.Collection; 49 import java.util.Collections; 50 import java.util.HashMap; 51 import java.util.List; 52 import java.util.Map; 53 54 import org.eclipse.jgit.annotations.NonNull; 55 import org.eclipse.jgit.annotations.Nullable; 56 57 /** 58 * Abstraction of name to {@link ObjectId} mapping. 59 * <p> 60 * A reference database stores a mapping of reference names to {@link ObjectId}. 61 * Every {@link Repository} has a single reference database, mapping names to 62 * the tips of the object graph contained by the {@link ObjectDatabase}. 63 */ 64 public abstract class RefDatabase { 65 /** 66 * Order of prefixes to search when using non-absolute references. 67 * <p> 68 * The implementation's {@link #getRef(String)} method must take this search 69 * space into consideration when locating a reference by name. The first 70 * entry in the path is always {@code ""}, ensuring that absolute references 71 * are resolved without further mangling. 72 */ 73 protected static final String[] SEARCH_PATH = { "", //$NON-NLS-1$ 74 Constants.R_REFS, // 75 Constants.R_TAGS, // 76 Constants.R_HEADS, // 77 Constants.R_REMOTES // 78 }; 79 80 /** 81 * Maximum number of times a {@link SymbolicRef} can be traversed. 82 * <p> 83 * If the reference is nested deeper than this depth, the implementation 84 * should either fail, or at least claim the reference does not exist. 85 * 86 * @since 4.2 87 */ 88 public static final int MAX_SYMBOLIC_REF_DEPTH = 5; 89 90 /** Magic value for {@link #getRefs(String)} to return all references. */ 91 public static final String ALL = "";//$NON-NLS-1$ 92 93 /** 94 * Initialize a new reference database at this location. 95 * 96 * @throws IOException 97 * the database could not be created. 98 */ 99 public abstract void create() throws IOException; 100 101 /** Close any resources held by this database. */ 102 public abstract void close(); 103 104 /** 105 * Determine if a proposed reference name overlaps with an existing one. 106 * <p> 107 * Reference names use '/' as a component separator, and may be stored in a 108 * hierarchical storage such as a directory on the local filesystem. 109 * <p> 110 * If the reference "refs/heads/foo" exists then "refs/heads/foo/bar" must 111 * not exist, as a reference cannot have a value and also be a container for 112 * other references at the same time. 113 * <p> 114 * If the reference "refs/heads/foo/bar" exists than the reference 115 * "refs/heads/foo" cannot exist, for the same reason. 116 * 117 * @param name 118 * proposed name. 119 * @return true if the name overlaps with an existing reference; false if 120 * using this name right now would be safe. 121 * @throws IOException 122 * the database could not be read to check for conflicts. 123 * @see #getConflictingNames(String) 124 */ 125 public abstract boolean isNameConflicting(String name) throws IOException; 126 127 /** 128 * Determine if a proposed reference cannot coexist with existing ones. If 129 * the passed name already exists, it's not considered a conflict. 130 * 131 * @param name 132 * proposed name to check for conflicts against 133 * @return a collection of full names of existing refs which would conflict 134 * with the passed ref name; empty collection when there are no 135 * conflicts 136 * @throws IOException 137 * @since 2.3 138 * @see #isNameConflicting(String) 139 */ 140 @NonNull 141 public Collection<String> getConflictingNames(String name) 142 throws IOException { 143 Map<String, Ref> allRefs = getRefs(ALL); 144 // Cannot be nested within an existing reference. 145 int lastSlash = name.lastIndexOf('/'); 146 while (0 < lastSlash) { 147 String needle = name.substring(0, lastSlash); 148 if (allRefs.containsKey(needle)) 149 return Collections.singletonList(needle); 150 lastSlash = name.lastIndexOf('/', lastSlash - 1); 151 } 152 153 List<String> conflicting = new ArrayList<>(); 154 // Cannot be the container of an existing reference. 155 String prefix = name + '/'; 156 for (String existing : allRefs.keySet()) 157 if (existing.startsWith(prefix)) 158 conflicting.add(existing); 159 160 return conflicting; 161 } 162 163 /** 164 * Create a new update command to create, modify or delete a reference. 165 * 166 * @param name 167 * the name of the reference. 168 * @param detach 169 * if {@code true} and {@code name} is currently a 170 * {@link SymbolicRef}, the update will replace it with an 171 * {@link ObjectIdRef}. Otherwise, the update will recursively 172 * traverse {@link SymbolicRef}s and operate on the leaf 173 * {@link ObjectIdRef}. 174 * @return a new update for the requested name; never null. 175 * @throws IOException 176 * the reference space cannot be accessed. 177 */ 178 @NonNull 179 public abstract RefUpdate newUpdate(String name, boolean detach) 180 throws IOException; 181 182 /** 183 * Create a new update command to rename a reference. 184 * 185 * @param fromName 186 * name of reference to rename from 187 * @param toName 188 * name of reference to rename to 189 * @return an update command that knows how to rename a branch to another. 190 * @throws IOException 191 * the reference space cannot be accessed. 192 */ 193 @NonNull 194 public abstract RefRename newRename(String fromName, String toName) 195 throws IOException; 196 197 /** 198 * Create a new batch update to attempt on this database. 199 * <p> 200 * The default implementation performs a sequential update of each command. 201 * 202 * @return a new batch update object. 203 */ 204 @NonNull 205 public BatchRefUpdate newBatchUpdate() { 206 return new BatchRefUpdate(this); 207 } 208 209 /** 210 * Whether the database is capable of performing batch updates as atomic 211 * transactions. 212 * <p> 213 * If true, by default {@link BatchRefUpdate} instances will perform updates 214 * atomically, meaning either all updates will succeed, or all updates will 215 * fail. It is still possible to turn off this behavior on a per-batch basis 216 * by calling {@code update.setAtomic(false)}. 217 * <p> 218 * If false, {@link BatchRefUpdate} instances will never perform updates 219 * atomically, and calling {@code update.setAtomic(true)} will cause the 220 * entire batch to fail with {@code REJECTED_OTHER_REASON}. 221 * <p> 222 * This definition of atomicity is stronger than what is provided by 223 * {@link org.eclipse.jgit.transport.ReceivePack}. {@code ReceivePack} will 224 * attempt to reject all commands if it knows in advance some commands may 225 * fail, even if the storage layer does not support atomic transactions. Here, 226 * atomicity applies even in the case of unforeseeable errors. 227 * 228 * @return whether transactions are atomic by default. 229 * @since 3.6 230 */ 231 public boolean performsAtomicTransactions() { 232 return false; 233 } 234 235 /** 236 * Read a single reference. 237 * <p> 238 * Aside from taking advantage of {@link #SEARCH_PATH}, this method may be 239 * able to more quickly resolve a single reference name than obtaining the 240 * complete namespace by {@code getRefs(ALL).get(name)}. 241 * <p> 242 * To read a specific reference without using @{link #SEARCH_PATH}, see 243 * {@link #exactRef(String)}. 244 * 245 * @param name 246 * the name of the reference. May be a short name which must be 247 * searched for using the standard {@link #SEARCH_PATH}. 248 * @return the reference (if it exists); else {@code null}. 249 * @throws IOException 250 * the reference space cannot be accessed. 251 */ 252 @Nullable 253 public abstract Ref getRef(String name) throws IOException; 254 255 /** 256 * Read a single reference. 257 * <p> 258 * Unlike {@link #getRef}, this method expects an unshortened reference 259 * name and does not search using the standard {@link #SEARCH_PATH}. 260 * 261 * @param name 262 * the unabbreviated name of the reference. 263 * @return the reference (if it exists); else {@code null}. 264 * @throws IOException 265 * the reference space cannot be accessed. 266 * @since 4.1 267 */ 268 @Nullable 269 public Ref exactRef(String name) throws IOException { 270 Ref ref = getRef(name); 271 if (ref == null || !name.equals(ref.getName())) { 272 return null; 273 } 274 return ref; 275 } 276 277 /** 278 * Read the specified references. 279 * <p> 280 * This method expects a list of unshortened reference names and returns 281 * a map from reference names to refs. Any named references that do not 282 * exist will not be included in the returned map. 283 * 284 * @param refs 285 * the unabbreviated names of references to look up. 286 * @return modifiable map describing any refs that exist among the ref 287 * ref names supplied. The map can be an unsorted map. 288 * @throws IOException 289 * the reference space cannot be accessed. 290 * @since 4.1 291 */ 292 @NonNull 293 public Map<String, Ref> exactRef(String... refs) throws IOException { 294 Map<String, Ref> result = new HashMap<>(refs.length); 295 for (String name : refs) { 296 Ref ref = exactRef(name); 297 if (ref != null) { 298 result.put(name, ref); 299 } 300 } 301 return result; 302 } 303 304 /** 305 * Find the first named reference. 306 * <p> 307 * This method expects a list of unshortened reference names and returns 308 * the first that exists. 309 * 310 * @param refs 311 * the unabbreviated names of references to look up. 312 * @return the first named reference that exists (if any); else {@code null}. 313 * @throws IOException 314 * the reference space cannot be accessed. 315 * @since 4.1 316 */ 317 @Nullable 318 public Ref firstExactRef(String... refs) throws IOException { 319 for (String name : refs) { 320 Ref ref = exactRef(name); 321 if (ref != null) { 322 return ref; 323 } 324 } 325 return null; 326 } 327 328 /** 329 * Get a section of the reference namespace. 330 * 331 * @param prefix 332 * prefix to search the namespace with; must end with {@code /}. 333 * If the empty string ({@link #ALL}), obtain a complete snapshot 334 * of all references. 335 * @return modifiable map that is a complete snapshot of the current 336 * reference namespace, with {@code prefix} removed from the start 337 * of each key. The map can be an unsorted map. 338 * @throws IOException 339 * the reference space cannot be accessed. 340 */ 341 @NonNull 342 public abstract Map<String, Ref> getRefs(String prefix) throws IOException; 343 344 /** 345 * Get the additional reference-like entities from the repository. 346 * <p> 347 * The result list includes non-ref items such as MERGE_HEAD and 348 * FETCH_RESULT cast to be refs. The names of these refs are not returned by 349 * <code>getRefs(ALL)</code> but are accepted by {@link #getRef(String)} 350 * and {@link #exactRef(String)}. 351 * 352 * @return a list of additional refs 353 * @throws IOException 354 * the reference space cannot be accessed. 355 */ 356 @NonNull 357 public abstract List<Ref> getAdditionalRefs() throws IOException; 358 359 /** 360 * Peel a possibly unpeeled reference by traversing the annotated tags. 361 * <p> 362 * If the reference cannot be peeled (as it does not refer to an annotated 363 * tag) the peeled id stays null, but {@link Ref#isPeeled()} will be true. 364 * <p> 365 * Implementors should check {@link Ref#isPeeled()} before performing any 366 * additional work effort. 367 * 368 * @param ref 369 * The reference to peel 370 * @return {@code ref} if {@code ref.isPeeled()} is true; otherwise a new 371 * Ref object representing the same data as Ref, but isPeeled() will 372 * be true and getPeeledObjectId() will contain the peeled object 373 * (or {@code null}). 374 * @throws IOException 375 * the reference space or object space cannot be accessed. 376 */ 377 @NonNull 378 public abstract Ref peel(Ref ref) throws IOException; 379 380 /** 381 * Triggers a refresh of all internal data structures. 382 * <p> 383 * In case the RefDatabase implementation has internal caches this method 384 * will trigger that all these caches are cleared. 385 * <p> 386 * Implementors should overwrite this method if they use any kind of caches. 387 */ 388 public void refresh() { 389 // nothing 390 } 391 392 /** 393 * Try to find the specified name in the ref map using {@link #SEARCH_PATH}. 394 * 395 * @param map 396 * map of refs to search within. Names should be fully qualified, 397 * e.g. "refs/heads/master". 398 * @param name 399 * short name of ref to find, e.g. "master" to find 400 * "refs/heads/master" in map. 401 * @return The first ref matching the name, or {@code null} if not found. 402 * @since 3.4 403 */ 404 @Nullable 405 public static Ref findRef(Map<String, Ref> map, String name) { 406 for (String prefix : SEARCH_PATH) { 407 String fullname = prefix + name; 408 Ref ref = map.get(fullname); 409 if (ref != null) 410 return ref; 411 } 412 return null; 413 } 414 }