You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RefDatabase.java 19KB

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