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 20KB

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