Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

AbstractTreeIterator.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. /*
  2. * Copyright (C) 2008-2009, Google Inc.
  3. * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
  4. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  5. * and other copyright owners as documented in the project's IP log.
  6. *
  7. * This program and the accompanying materials are made available
  8. * under the terms of the Eclipse Distribution License v1.0 which
  9. * accompanies this distribution, is reproduced below, and is
  10. * available at http://www.eclipse.org/org/documents/edl-v10.php
  11. *
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or
  15. * without modification, are permitted provided that the following
  16. * conditions are met:
  17. *
  18. * - Redistributions of source code must retain the above copyright
  19. * notice, this list of conditions and the following disclaimer.
  20. *
  21. * - Redistributions in binary form must reproduce the above
  22. * copyright notice, this list of conditions and the following
  23. * disclaimer in the documentation and/or other materials provided
  24. * with the distribution.
  25. *
  26. * - Neither the name of the Eclipse Foundation, Inc. nor the
  27. * names of its contributors may be used to endorse or promote
  28. * products derived from this software without specific prior
  29. * written permission.
  30. *
  31. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  32. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  33. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  34. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  36. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  37. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  38. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  39. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  40. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  41. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  42. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  43. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. */
  45. package org.eclipse.jgit.treewalk;
  46. import java.io.IOException;
  47. import java.nio.ByteBuffer;
  48. import java.nio.CharBuffer;
  49. import org.eclipse.jgit.errors.CorruptObjectException;
  50. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  51. import org.eclipse.jgit.lib.Constants;
  52. import org.eclipse.jgit.lib.FileMode;
  53. import org.eclipse.jgit.lib.MutableObjectId;
  54. import org.eclipse.jgit.lib.ObjectId;
  55. import org.eclipse.jgit.lib.Repository;
  56. import org.eclipse.jgit.lib.WindowCursor;
  57. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  58. /**
  59. * Walks a Git tree (directory) in Git sort order.
  60. * <p>
  61. * A new iterator instance should be positioned on the first entry, or at eof.
  62. * Data for the first entry (if not at eof) should be available immediately.
  63. * <p>
  64. * Implementors must walk a tree in the Git sort order, which has the following
  65. * odd sorting:
  66. * <ol>
  67. * <li>A.c</li>
  68. * <li>A/c</li>
  69. * <li>A0c</li>
  70. * </ol>
  71. * <p>
  72. * In the second item, <code>A</code> is the name of a subtree and
  73. * <code>c</code> is a file within that subtree. The other two items are files
  74. * in the root level tree.
  75. *
  76. * @see CanonicalTreeParser
  77. */
  78. public abstract class AbstractTreeIterator {
  79. /** Default size for the {@link #path} buffer. */
  80. protected static final int DEFAULT_PATH_SIZE = 128;
  81. /** A dummy object id buffer that matches the zero ObjectId. */
  82. protected static final byte[] zeroid = new byte[Constants.OBJECT_ID_LENGTH];
  83. /** Iterator for the parent tree; null if we are the root iterator. */
  84. final AbstractTreeIterator parent;
  85. /** The iterator this current entry is path equal to. */
  86. AbstractTreeIterator matches;
  87. /**
  88. * Number of entries we moved forward to force a D/F conflict match.
  89. *
  90. * @see NameConflictTreeWalk
  91. */
  92. int matchShift;
  93. /**
  94. * Mode bits for the current entry.
  95. * <p>
  96. * A numerical value from FileMode is usually faster for an iterator to
  97. * obtain from its data source so this is the preferred representation.
  98. *
  99. * @see org.eclipse.jgit.lib.FileMode
  100. */
  101. protected int mode;
  102. /**
  103. * Path buffer for the current entry.
  104. * <p>
  105. * This buffer is pre-allocated at the start of walking and is shared from
  106. * parent iterators down into their subtree iterators. The sharing allows
  107. * the current entry to always be a full path from the root, while each
  108. * subtree only needs to populate the part that is under their control.
  109. */
  110. protected byte[] path;
  111. /**
  112. * Position within {@link #path} this iterator starts writing at.
  113. * <p>
  114. * This is the first offset in {@link #path} that this iterator must
  115. * populate during {@link #next}. At the root level (when {@link #parent}
  116. * is null) this is 0. For a subtree iterator the index before this position
  117. * should have the value '/'.
  118. */
  119. protected final int pathOffset;
  120. /**
  121. * Total length of the current entry's complete path from the root.
  122. * <p>
  123. * This is the number of bytes within {@link #path} that pertain to the
  124. * current entry. Values at this index through the end of the array are
  125. * garbage and may be randomly populated from prior entries.
  126. */
  127. protected int pathLen;
  128. /** Create a new iterator with no parent. */
  129. protected AbstractTreeIterator() {
  130. parent = null;
  131. path = new byte[DEFAULT_PATH_SIZE];
  132. pathOffset = 0;
  133. }
  134. /**
  135. * Create a new iterator with no parent and a prefix.
  136. * <p>
  137. * The prefix path supplied is inserted in front of all paths generated by
  138. * this iterator. It is intended to be used when an iterator is being
  139. * created for a subsection of an overall repository and needs to be
  140. * combined with other iterators that are created to run over the entire
  141. * repository namespace.
  142. *
  143. * @param prefix
  144. * position of this iterator in the repository tree. The value
  145. * may be null or the empty string to indicate the prefix is the
  146. * root of the repository. A trailing slash ('/') is
  147. * automatically appended if the prefix does not end in '/'.
  148. */
  149. protected AbstractTreeIterator(final String prefix) {
  150. parent = null;
  151. if (prefix != null && prefix.length() > 0) {
  152. final ByteBuffer b;
  153. b = Constants.CHARSET.encode(CharBuffer.wrap(prefix));
  154. pathLen = b.limit();
  155. path = new byte[Math.max(DEFAULT_PATH_SIZE, pathLen + 1)];
  156. b.get(path, 0, pathLen);
  157. if (path[pathLen - 1] != '/')
  158. path[pathLen++] = '/';
  159. pathOffset = pathLen;
  160. } else {
  161. path = new byte[DEFAULT_PATH_SIZE];
  162. pathOffset = 0;
  163. }
  164. }
  165. /**
  166. * Create a new iterator with no parent and a prefix.
  167. * <p>
  168. * The prefix path supplied is inserted in front of all paths generated by
  169. * this iterator. It is intended to be used when an iterator is being
  170. * created for a subsection of an overall repository and needs to be
  171. * combined with other iterators that are created to run over the entire
  172. * repository namespace.
  173. *
  174. * @param prefix
  175. * position of this iterator in the repository tree. The value
  176. * may be null or the empty array to indicate the prefix is the
  177. * root of the repository. A trailing slash ('/') is
  178. * automatically appended if the prefix does not end in '/'.
  179. */
  180. protected AbstractTreeIterator(final byte[] prefix) {
  181. parent = null;
  182. if (prefix != null && prefix.length > 0) {
  183. pathLen = prefix.length;
  184. path = new byte[Math.max(DEFAULT_PATH_SIZE, pathLen + 1)];
  185. System.arraycopy(prefix, 0, path, 0, pathLen);
  186. if (path[pathLen - 1] != '/')
  187. path[pathLen++] = '/';
  188. pathOffset = pathLen;
  189. } else {
  190. path = new byte[DEFAULT_PATH_SIZE];
  191. pathOffset = 0;
  192. }
  193. }
  194. /**
  195. * Create an iterator for a subtree of an existing iterator.
  196. *
  197. * @param p
  198. * parent tree iterator.
  199. */
  200. protected AbstractTreeIterator(final AbstractTreeIterator p) {
  201. parent = p;
  202. path = p.path;
  203. pathOffset = p.pathLen + 1;
  204. try {
  205. path[pathOffset - 1] = '/';
  206. } catch (ArrayIndexOutOfBoundsException e) {
  207. growPath(p.pathLen);
  208. path[pathOffset - 1] = '/';
  209. }
  210. }
  211. /**
  212. * Create an iterator for a subtree of an existing iterator.
  213. * <p>
  214. * The caller is responsible for setting up the path of the child iterator.
  215. *
  216. * @param p
  217. * parent tree iterator.
  218. * @param childPath
  219. * path array to be used by the child iterator. This path must
  220. * contain the path from the top of the walk to the first child
  221. * and must end with a '/'.
  222. * @param childPathOffset
  223. * position within <code>childPath</code> where the child can
  224. * insert its data. The value at
  225. * <code>childPath[childPathOffset-1]</code> must be '/'.
  226. */
  227. protected AbstractTreeIterator(final AbstractTreeIterator p,
  228. final byte[] childPath, final int childPathOffset) {
  229. parent = p;
  230. path = childPath;
  231. pathOffset = childPathOffset;
  232. }
  233. /**
  234. * Grow the path buffer larger.
  235. *
  236. * @param len
  237. * number of live bytes in the path buffer. This many bytes will
  238. * be moved into the larger buffer.
  239. */
  240. protected void growPath(final int len) {
  241. setPathCapacity(path.length << 1, len);
  242. }
  243. /**
  244. * Ensure that path is capable to hold at least {@code capacity} bytes
  245. *
  246. * @param capacity
  247. * the amount of bytes to hold
  248. * @param len
  249. * the amount of live bytes in path buffer
  250. */
  251. protected void ensurePathCapacity(final int capacity, final int len) {
  252. if (path.length >= capacity)
  253. return;
  254. final byte[] o = path;
  255. int current = o.length;
  256. int newCapacity = current;
  257. while (newCapacity < capacity && newCapacity > 0)
  258. newCapacity <<= 1;
  259. setPathCapacity(newCapacity, len);
  260. }
  261. /**
  262. * Set path buffer capacity to the specified size
  263. *
  264. * @param capacity
  265. * the new size
  266. * @param len
  267. * the amount of bytes to copy
  268. */
  269. private void setPathCapacity(int capacity, int len) {
  270. final byte[] o = path;
  271. final byte[] n = new byte[capacity];
  272. System.arraycopy(o, 0, n, 0, len);
  273. for (AbstractTreeIterator p = this; p != null && p.path == o; p = p.parent)
  274. p.path = n;
  275. }
  276. /**
  277. * Compare the path of this current entry to another iterator's entry.
  278. *
  279. * @param p
  280. * the other iterator to compare the path against.
  281. * @return -1 if this entry sorts first; 0 if the entries are equal; 1 if
  282. * p's entry sorts first.
  283. */
  284. public int pathCompare(final AbstractTreeIterator p) {
  285. return pathCompare(p, p.mode);
  286. }
  287. int pathCompare(final AbstractTreeIterator p, final int pMode) {
  288. final byte[] a = path;
  289. final byte[] b = p.path;
  290. final int aLen = pathLen;
  291. final int bLen = p.pathLen;
  292. int cPos;
  293. // Its common when we are a subtree for both parents to match;
  294. // when this happens everything in path[0..cPos] is known to
  295. // be equal and does not require evaluation again.
  296. //
  297. cPos = alreadyMatch(this, p);
  298. for (; cPos < aLen && cPos < bLen; cPos++) {
  299. final int cmp = (a[cPos] & 0xff) - (b[cPos] & 0xff);
  300. if (cmp != 0)
  301. return cmp;
  302. }
  303. if (cPos < aLen)
  304. return (a[cPos] & 0xff) - lastPathChar(pMode);
  305. if (cPos < bLen)
  306. return lastPathChar(mode) - (b[cPos] & 0xff);
  307. return lastPathChar(mode) - lastPathChar(pMode);
  308. }
  309. private static int alreadyMatch(AbstractTreeIterator a,
  310. AbstractTreeIterator b) {
  311. for (;;) {
  312. final AbstractTreeIterator ap = a.parent;
  313. final AbstractTreeIterator bp = b.parent;
  314. if (ap == null || bp == null)
  315. return 0;
  316. if (ap.matches == bp.matches)
  317. return a.pathOffset;
  318. a = ap;
  319. b = bp;
  320. }
  321. }
  322. private static int lastPathChar(final int mode) {
  323. return FileMode.TREE.equals(mode) ? '/' : '\0';
  324. }
  325. /**
  326. * Check if the current entry of both iterators has the same id.
  327. * <p>
  328. * This method is faster than {@link #getEntryObjectId()} as it does not
  329. * require copying the bytes out of the buffers. A direct {@link #idBuffer}
  330. * compare operation is performed.
  331. *
  332. * @param otherIterator
  333. * the other iterator to test against.
  334. * @return true if both iterators have the same object id; false otherwise.
  335. */
  336. public boolean idEqual(final AbstractTreeIterator otherIterator) {
  337. return ObjectId.equals(idBuffer(), idOffset(),
  338. otherIterator.idBuffer(), otherIterator.idOffset());
  339. }
  340. /**
  341. * Get the object id of the current entry.
  342. *
  343. * @return an object id for the current entry.
  344. */
  345. public ObjectId getEntryObjectId() {
  346. return ObjectId.fromRaw(idBuffer(), idOffset());
  347. }
  348. /**
  349. * Obtain the ObjectId for the current entry.
  350. *
  351. * @param out
  352. * buffer to copy the object id into.
  353. */
  354. public void getEntryObjectId(final MutableObjectId out) {
  355. out.fromRaw(idBuffer(), idOffset());
  356. }
  357. /** @return the file mode of the current entry. */
  358. public FileMode getEntryFileMode() {
  359. return FileMode.fromBits(mode);
  360. }
  361. /** @return the file mode of the current entry as bits */
  362. public int getEntryRawMode() {
  363. return mode;
  364. }
  365. /** @return path of the current entry, as a string. */
  366. public String getEntryPathString() {
  367. return TreeWalk.pathOf(this);
  368. }
  369. /**
  370. * Get the byte array buffer object IDs must be copied out of.
  371. * <p>
  372. * The id buffer contains the bytes necessary to construct an ObjectId for
  373. * the current entry of this iterator. The buffer can be the same buffer for
  374. * all entries, or it can be a unique buffer per-entry. Implementations are
  375. * encouraged to expose their private buffer whenever possible to reduce
  376. * garbage generation and copying costs.
  377. *
  378. * @return byte array the implementation stores object IDs within.
  379. * @see #getEntryObjectId()
  380. */
  381. public abstract byte[] idBuffer();
  382. /**
  383. * Get the position within {@link #idBuffer()} of this entry's ObjectId.
  384. *
  385. * @return offset into the array returned by {@link #idBuffer()} where the
  386. * ObjectId must be copied out of.
  387. */
  388. public abstract int idOffset();
  389. /**
  390. * Create a new iterator for the current entry's subtree.
  391. * <p>
  392. * The parent reference of the iterator must be <code>this</code>,
  393. * otherwise the caller would not be able to exit out of the subtree
  394. * iterator correctly and return to continue walking <code>this</code>.
  395. *
  396. * @param repo
  397. * repository to load the tree data from.
  398. * @return a new parser that walks over the current subtree.
  399. * @throws IncorrectObjectTypeException
  400. * the current entry is not actually a tree and cannot be parsed
  401. * as though it were a tree.
  402. * @throws IOException
  403. * a loose object or pack file could not be read.
  404. */
  405. public abstract AbstractTreeIterator createSubtreeIterator(Repository repo)
  406. throws IncorrectObjectTypeException, IOException;
  407. /**
  408. * Create a new iterator as though the current entry were a subtree.
  409. *
  410. * @return a new empty tree iterator.
  411. */
  412. public EmptyTreeIterator createEmptyTreeIterator() {
  413. return new EmptyTreeIterator(this);
  414. }
  415. /**
  416. * Create a new iterator for the current entry's subtree.
  417. * <p>
  418. * The parent reference of the iterator must be <code>this</code>, otherwise
  419. * the caller would not be able to exit out of the subtree iterator
  420. * correctly and return to continue walking <code>this</code>.
  421. *
  422. * @param repo
  423. * repository to load the tree data from.
  424. * @param idBuffer
  425. * temporary ObjectId buffer for use by this method.
  426. * @param curs
  427. * window cursor to use during repository access.
  428. * @return a new parser that walks over the current subtree.
  429. * @throws IncorrectObjectTypeException
  430. * the current entry is not actually a tree and cannot be parsed
  431. * as though it were a tree.
  432. * @throws IOException
  433. * a loose object or pack file could not be read.
  434. */
  435. public AbstractTreeIterator createSubtreeIterator(final Repository repo,
  436. final MutableObjectId idBuffer, final WindowCursor curs)
  437. throws IncorrectObjectTypeException, IOException {
  438. return createSubtreeIterator(repo);
  439. }
  440. /**
  441. * Is this tree iterator positioned on its first entry?
  442. * <p>
  443. * An iterator is positioned on the first entry if <code>back(1)</code>
  444. * would be an invalid request as there is no entry before the current one.
  445. * <p>
  446. * An empty iterator (one with no entries) will be
  447. * <code>first() &amp;&amp; eof()</code>.
  448. *
  449. * @return true if the iterator is positioned on the first entry.
  450. */
  451. public abstract boolean first();
  452. /**
  453. * Is this tree iterator at its EOF point (no more entries)?
  454. * <p>
  455. * An iterator is at EOF if there is no current entry.
  456. *
  457. * @return true if we have walked all entries and have none left.
  458. */
  459. public abstract boolean eof();
  460. /**
  461. * Move to next entry, populating this iterator with the entry data.
  462. * <p>
  463. * The delta indicates how many moves forward should occur. The most common
  464. * delta is 1 to move to the next entry.
  465. * <p>
  466. * Implementations must populate the following members:
  467. * <ul>
  468. * <li>{@link #mode}</li>
  469. * <li>{@link #path} (from {@link #pathOffset} to {@link #pathLen})</li>
  470. * <li>{@link #pathLen}</li>
  471. * </ul>
  472. * as well as any implementation dependent information necessary to
  473. * accurately return data from {@link #idBuffer()} and {@link #idOffset()}
  474. * when demanded.
  475. *
  476. * @param delta
  477. * number of entries to move the iterator by. Must be a positive,
  478. * non-zero integer.
  479. * @throws CorruptObjectException
  480. * the tree is invalid.
  481. */
  482. public abstract void next(int delta) throws CorruptObjectException;
  483. /**
  484. * Move to prior entry, populating this iterator with the entry data.
  485. * <p>
  486. * The delta indicates how many moves backward should occur.The most common
  487. * delta is 1 to move to the prior entry.
  488. * <p>
  489. * Implementations must populate the following members:
  490. * <ul>
  491. * <li>{@link #mode}</li>
  492. * <li>{@link #path} (from {@link #pathOffset} to {@link #pathLen})</li>
  493. * <li>{@link #pathLen}</li>
  494. * </ul>
  495. * as well as any implementation dependent information necessary to
  496. * accurately return data from {@link #idBuffer()} and {@link #idOffset()}
  497. * when demanded.
  498. *
  499. * @param delta
  500. * number of entries to move the iterator by. Must be a positive,
  501. * non-zero integer.
  502. * @throws CorruptObjectException
  503. * the tree is invalid.
  504. */
  505. public abstract void back(int delta) throws CorruptObjectException;
  506. /**
  507. * Advance to the next tree entry, populating this iterator with its data.
  508. * <p>
  509. * This method behaves like <code>seek(1)</code> but is called by
  510. * {@link TreeWalk} only if a {@link TreeFilter} was used and ruled out the
  511. * current entry from the results. In such cases this tree iterator may
  512. * perform special behavior.
  513. *
  514. * @throws CorruptObjectException
  515. * the tree is invalid.
  516. */
  517. public void skip() throws CorruptObjectException {
  518. next(1);
  519. }
  520. /**
  521. * Indicates to the iterator that no more entries will be read.
  522. * <p>
  523. * This is only invoked by TreeWalk when the iteration is aborted early due
  524. * to a {@link org.eclipse.jgit.errors.StopWalkException} being thrown from
  525. * within a TreeFilter.
  526. */
  527. public void stopWalk() {
  528. // Do nothing by default. Most iterators do not care.
  529. }
  530. /**
  531. * @return the length of the name component of the path for the current entry
  532. */
  533. public int getNameLength() {
  534. return pathLen - pathOffset;
  535. }
  536. /**
  537. * Get the name component of the current entry path into the provided buffer.
  538. *
  539. * @param buffer the buffer to get the name into, it is assumed that buffer can hold the name
  540. * @param offset the offset of the name in the buffer
  541. * @see #getNameLength()
  542. */
  543. public void getName(byte[] buffer, int offset) {
  544. System.arraycopy(path, pathOffset, buffer, offset, pathLen - pathOffset);
  545. }
  546. }