/// <summary>Create an iterator for a subtree of an existing iterator.</summary> /// <remarks> /// Create an iterator for a subtree of an existing iterator. /// <p> /// The caller is responsible for setting up the path of the child iterator. /// </remarks> /// <param name="p">parent tree iterator.</param> /// <param name="childPath"> /// path array to be used by the child iterator. This path must /// contain the path from the top of the walk to the first child /// and must end with a '/'. /// </param> /// <param name="childPathOffset"> /// position within <code>childPath</code> where the child can /// insert its data. The value at /// <code>childPath[childPathOffset-1]</code> must be '/'. /// </param> protected internal AbstractTreeIterator(NGit.Treewalk.AbstractTreeIterator p, byte [] childPath, int childPathOffset) { parent = p; path = childPath; pathOffset = childPathOffset; }
/// <summary>Reset this walker to run over a single existing tree.</summary> /// <remarks>Reset this walker to run over a single existing tree.</remarks> /// <param name="id"> /// the tree we need to parse. The walker will execute over this /// single tree if the reset is successful. /// </param> /// <exception cref="NGit.Errors.MissingObjectException">the given tree object does not exist in this repository. /// </exception> /// <exception cref="NGit.Errors.IncorrectObjectTypeException"> /// the given object id does not denote a tree, but instead names /// some other non-tree type of object. Note that commits are not /// trees, even if they are sometimes called a "tree-ish". /// </exception> /// <exception cref="NGit.Errors.CorruptObjectException"> /// the object claimed to be a tree, but its contents did not /// appear to be a tree. The repository may have data corruption. /// </exception> /// <exception cref="System.IO.IOException">a loose object or pack file could not be read. /// </exception> public virtual void Reset(AnyObjectId id) { if (trees.Length == 1) { AbstractTreeIterator o = trees[0]; while (o.parent != null) { o = o.parent; } if (o is CanonicalTreeParser) { o.matches = null; o.matchShift = 0; ((CanonicalTreeParser)o).Reset(reader, id); trees[0] = o; } else { trees[0] = ParserFor(id); } } else { trees = new AbstractTreeIterator[] { ParserFor(id) }; } advance = false; depth = 0; }
/// <summary>Obtain the tree iterator for the current entry.</summary> /// <remarks> /// Obtain the tree iterator for the current entry. /// <p> /// Entering into (or exiting out of) a subtree causes the current tree /// iterator instance to be changed for the nth tree. This allows the tree /// iterators to manage only one list of items, with the diving handled by /// recursive trees. /// </remarks> /// <?></?> /// <param name="nth">tree to obtain the current iterator of.</param> /// <param name="clazz">type of the tree iterator expected by the caller.</param> /// <returns> /// r the current iterator of the requested type; null if the tree /// has no entry to match the current path. /// </returns> public virtual T GetTree <T>(int nth) where T : AbstractTreeIterator { System.Type clazz = typeof(T); AbstractTreeIterator t = trees[nth]; return(t.matches == currentHead ? (T)t : null); }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> internal override AbstractTreeIterator Min() { for (; ;) { AbstractTreeIterator minRef = FastMin(); if (fastMinHasMatch) { return(minRef); } if (IsTree(minRef)) { if (SkipEntry(minRef)) { foreach (AbstractTreeIterator t in trees) { if (t.matches == minRef) { t.Next(1); t.matches = null; } } continue; } return(minRef); } return(CombineDF(minRef)); } }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> internal override void SkipEntriesEqual() { AbstractTreeIterator ch = currentHead; for (int i = 0; i < trees.Length; i++) { AbstractTreeIterator t = trees[i]; if (t.matches == ch) { if (t.matchShift == 0) { t.Skip(); } else { t.Back(t.matchShift); t.matchShift = 0; } t.matches = null; } } if (ch == dfConflict) { dfConflict = null; } }
internal virtual int PathCompare(NGit.Treewalk.AbstractTreeIterator p, int pMode) { // Its common when we are a subtree for both parents to match; // when this happens everything in path[0..cPos] is known to // be equal and does not require evaluation again. // int cPos = AlreadyMatch(this, p); return(PathCompare(p.path, cPos, p.pathLen, pMode, cPos)); }
/// <summary>Set path buffer capacity to the specified size</summary> /// <param name="capacity">the new size</param> /// <param name="len">the amount of bytes to copy</param> private void SetPathCapacity(int capacity, int len) { byte[] o = path; byte[] n = new byte[capacity]; System.Array.Copy(o, 0, n, 0, len); for (NGit.Treewalk.AbstractTreeIterator p = this; p != null && p.path == o; p = p .parent) { p.path = n; } }
public virtual void TestCreateSubtreeIterator() { EmptyTreeIterator etp = new EmptyTreeIterator(); ObjectReader reader = db.NewObjectReader(); AbstractTreeIterator sub = etp.CreateSubtreeIterator(reader); NUnit.Framework.Assert.IsNotNull(sub); NUnit.Framework.Assert.IsTrue(sub.First); NUnit.Framework.Assert.IsTrue(sub.Eof); NUnit.Framework.Assert.IsTrue(sub is EmptyTreeIterator); }
/// <summary>Advance this walker to the next relevant entry.</summary> /// <remarks>Advance this walker to the next relevant entry.</remarks> /// <returns> /// true if there is an entry available; false if all entries have /// been walked and the walk of this set of tree iterators is over. /// </returns> /// <exception cref="NGit.Errors.MissingObjectException"> /// <see cref="Recursive()">Recursive()</see> /// was enabled, a subtree was found, but /// the subtree object does not exist in this repository. The /// repository may be missing objects. /// </exception> /// <exception cref="NGit.Errors.IncorrectObjectTypeException"> /// <see cref="Recursive()">Recursive()</see> /// was enabled, a subtree was found, and /// the subtree id does not denote a tree, but instead names some /// other non-tree type of object. The repository may have data /// corruption. /// </exception> /// <exception cref="NGit.Errors.CorruptObjectException"> /// the contents of a tree did not appear to be a tree. The /// repository may have data corruption. /// </exception> /// <exception cref="System.IO.IOException">a loose object or pack file could not be read. /// </exception> public virtual bool Next() { try { if (advance) { advance = false; postChildren = false; PopEntriesEqual(); } for (; ;) { AbstractTreeIterator t = Min(); if (t.Eof) { if (depth > 0) { ExitSubtree(); if (postOrderTraversal) { advance = true; postChildren = true; return(true); } PopEntriesEqual(); continue; } return(false); } currentHead = t; if (!filter.Include(this)) { SkipEntriesEqual(); continue; } if (recursive && FileMode.TREE.Equals(t.mode)) { EnterSubtree(); continue; } advance = true; return(true); } } catch (StopWalkException) { foreach (AbstractTreeIterator t in trees) { t.StopWalk(); } return(false); } }
/// <summary>Add an already created tree iterator for walking.</summary> /// <remarks> /// Add an already created tree iterator for walking. /// <p> /// The position of this tree is returned to the caller, in case the caller /// has lost track of the order they added the trees into the walker. /// <p> /// The tree which the iterator operates on must have the same root as /// existing trees in the walk. /// </remarks> /// <param name="p"> /// an iterator to walk over. The iterator should be new, with no /// parent, and should still be positioned before the first entry. /// The tree which the iterator operates on must have the same root /// as other trees in the walk. /// </param> /// <returns>position of this tree within the walker.</returns> /// <exception cref="NGit.Errors.CorruptObjectException"> /// the iterator was unable to obtain its first entry, due to /// possible data corruption within the backing data store. /// </exception> public virtual int AddTree(AbstractTreeIterator p) { int n = trees.Length; AbstractTreeIterator[] newTrees = new AbstractTreeIterator[n + 1]; System.Array.Copy(trees, 0, newTrees, 0, n); newTrees[n] = p; p.matches = null; p.matchShift = 0; trees = newTrees; return(n); }
/// <summary>Obtain the ObjectId for the current entry.</summary> /// <remarks> /// Obtain the ObjectId for the current entry. /// <p> /// Every tree supplies an object id, even if the tree does not contain the /// current entry. In the latter case /// <see cref="NGit.ObjectId.ZeroId()">NGit.ObjectId.ZeroId()</see> /// is supplied. /// <p> /// Applications should try to use /// <see cref="IdEqual(int, int)">IdEqual(int, int)</see> /// when possible /// as it avoids conversion overheads. /// </remarks> /// <param name="out">buffer to copy the object id into.</param> /// <param name="nth">tree to obtain the object identifier from.</param> /// <seealso cref="IdEqual(int, int)">IdEqual(int, int)</seealso> public virtual void GetObjectId(MutableObjectId @out, int nth) { AbstractTreeIterator t = trees[nth]; if (t.matches == currentHead) { t.GetEntryObjectId(@out); } else { @out.Clear(); } }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> internal virtual void SkipEntriesEqual() { AbstractTreeIterator ch = currentHead; for (int i = 0; i < trees.Length; i++) { AbstractTreeIterator t = trees[i]; if (t.matches == ch) { t.Skip(); t.matches = null; } } }
/// <summary>Create an iterator for a subtree of an existing iterator.</summary> /// <remarks>Create an iterator for a subtree of an existing iterator.</remarks> /// <param name="p">parent tree iterator.</param> protected internal AbstractTreeIterator(NGit.Treewalk.AbstractTreeIterator p) { parent = p; path = p.path; pathOffset = p.pathLen + 1; try { path[pathOffset - 1] = (byte)('/'); } catch (IndexOutOfRangeException) { GrowPath(p.pathLen); path[pathOffset - 1] = (byte)('/'); } }
/// <summary> /// Test if the supplied path matches (being suffix of) the current entry's /// path. /// </summary> /// <remarks> /// Test if the supplied path matches (being suffix of) the current entry's /// path. /// <p> /// This method tests that the supplied path is exactly equal to the current /// entry, or is relative to one of entry's parent directories. It is faster /// to use this method then to use /// <see cref="PathString()">PathString()</see> /// to first create /// a String object, then test <code>endsWith</code> or some other type of /// string match function. /// </remarks> /// <param name="p">path buffer to test.</param> /// <param name="pLen">number of bytes from <code>buf</code> to test.</param> /// <returns> /// true if p is suffix of the current path; /// false if otherwise /// </returns> public virtual bool IsPathSuffix(byte[] p, int pLen) { AbstractTreeIterator t = currentHead; byte[] c = t.path; int cLen = t.pathLen; int ci; for (ci = 1; ci < cLen && ci < pLen; ci++) { if (c[cLen - ci] != p[pLen - ci]) { return(false); } } return(true); }
public virtual void TestSimpleIterate() { FileTreeIterator top = new FileTreeIterator(trash, db.FileSystem, ((FileBasedConfig )db.GetConfig()).Get(WorkingTreeOptions.KEY)); NUnit.Framework.Assert.IsTrue(top.First); NUnit.Framework.Assert.IsFalse(top.Eof); NUnit.Framework.Assert.AreEqual(FileMode.REGULAR_FILE.GetBits(), top.mode); NUnit.Framework.Assert.AreEqual(paths[0], NameOf(top)); NUnit.Framework.Assert.AreEqual(paths[0].Length, top.GetEntryLength()); NUnit.Framework.Assert.AreEqual(mtime[0], top.GetEntryLastModified()); top.Next(1); NUnit.Framework.Assert.IsFalse(top.First); NUnit.Framework.Assert.IsFalse(top.Eof); NUnit.Framework.Assert.AreEqual(FileMode.REGULAR_FILE.GetBits(), top.mode); NUnit.Framework.Assert.AreEqual(paths[1], NameOf(top)); NUnit.Framework.Assert.AreEqual(paths[1].Length, top.GetEntryLength()); NUnit.Framework.Assert.AreEqual(mtime[1], top.GetEntryLastModified()); top.Next(1); NUnit.Framework.Assert.IsFalse(top.First); NUnit.Framework.Assert.IsFalse(top.Eof); NUnit.Framework.Assert.AreEqual(FileMode.TREE.GetBits(), top.mode); ObjectReader reader = db.NewObjectReader(); AbstractTreeIterator sub = top.CreateSubtreeIterator(reader); NUnit.Framework.Assert.IsTrue(sub is FileTreeIterator); FileTreeIterator subfti = (FileTreeIterator)sub; NUnit.Framework.Assert.IsTrue(sub.First); NUnit.Framework.Assert.IsFalse(sub.Eof); NUnit.Framework.Assert.AreEqual(paths[2], NameOf(sub)); NUnit.Framework.Assert.AreEqual(paths[2].Length, subfti.GetEntryLength()); NUnit.Framework.Assert.AreEqual(mtime[2], subfti.GetEntryLastModified()); sub.Next(1); NUnit.Framework.Assert.IsTrue(sub.Eof); top.Next(1); NUnit.Framework.Assert.IsFalse(top.First); NUnit.Framework.Assert.IsFalse(top.Eof); NUnit.Framework.Assert.AreEqual(FileMode.REGULAR_FILE.GetBits(), top.mode); NUnit.Framework.Assert.AreEqual(paths[3], NameOf(top)); NUnit.Framework.Assert.AreEqual(paths[3].Length, top.GetEntryLength()); NUnit.Framework.Assert.AreEqual(mtime[3], top.GetEntryLastModified()); top.Next(1); NUnit.Framework.Assert.IsTrue(top.Eof); }
private static int AlreadyMatch(NGit.Treewalk.AbstractTreeIterator a, NGit.Treewalk.AbstractTreeIterator b) { for (; ;) { NGit.Treewalk.AbstractTreeIterator ap = a.parent; NGit.Treewalk.AbstractTreeIterator bp = b.parent; if (ap == null || bp == null) { return(0); } if (ap.matches == bp.matches) { return(a.pathOffset); } a = ap; b = bp; } }
/// <summary>Create a new iterator with no parent and a prefix.</summary> /// <remarks> /// Create a new iterator with no parent and a prefix. /// <p> /// The prefix path supplied is inserted in front of all paths generated by /// this iterator. It is intended to be used when an iterator is being /// created for a subsection of an overall repository and needs to be /// combined with other iterators that are created to run over the entire /// repository namespace. /// </remarks> /// <param name="prefix"> /// position of this iterator in the repository tree. The value /// may be null or the empty array to indicate the prefix is the /// root of the repository. A trailing slash ('/') is /// automatically appended if the prefix does not end in '/'. /// </param> protected internal AbstractTreeIterator(byte[] prefix) { parent = null; if (prefix != null && prefix.Length > 0) { pathLen = prefix.Length; path = new byte[Math.Max(DEFAULT_PATH_SIZE, pathLen + 1)]; System.Array.Copy(prefix, 0, path, 0, pathLen); if (path[pathLen - 1] != '/') { path[pathLen++] = (byte)('/'); } pathOffset = pathLen; } else { path = new byte[DEFAULT_PATH_SIZE]; pathOffset = 0; } }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> private bool SkipEntry(AbstractTreeIterator minRef) { // A tree D/F may have been handled earlier. We need to // not report this path if it has already been reported. // foreach (AbstractTreeIterator t in trees) { if (t.matches == minRef || t.First) { continue; } int stepsBack = 0; for (; ;) { stepsBack++; t.Back(1); int cmp = t.PathCompare(minRef, 0); if (cmp == 0) { // We have already seen this "$path" before. Skip it. // t.Next(stepsBack); return(true); } else { if (cmp < 0 || t.First) { // We cannot find "$path" in t; it will never appear. // t.Next(stepsBack); break; } } } } // We have never seen the current path before. // return(false); }
/// <summary>Create a new iterator with no parent and a prefix.</summary> /// <remarks> /// Create a new iterator with no parent and a prefix. /// <p> /// The prefix path supplied is inserted in front of all paths generated by /// this iterator. It is intended to be used when an iterator is being /// created for a subsection of an overall repository and needs to be /// combined with other iterators that are created to run over the entire /// repository namespace. /// </remarks> /// <param name="prefix"> /// position of this iterator in the repository tree. The value /// may be null or the empty string to indicate the prefix is the /// root of the repository. A trailing slash ('/') is /// automatically appended if the prefix does not end in '/'. /// </param> protected internal AbstractTreeIterator(string prefix) { parent = null; if (prefix != null && prefix.Length > 0) { ByteBuffer b; b = Constants.CHARSET.Encode(CharBuffer.Wrap(prefix)); pathLen = b.Limit(); path = new byte[Math.Max(DEFAULT_PATH_SIZE, pathLen + 1)]; b.Get(path, 0, pathLen); if (path[pathLen - 1] != '/') { path[pathLen++] = (byte)('/'); } pathOffset = pathLen; } else { path = new byte[DEFAULT_PATH_SIZE]; pathOffset = 0; } }
private void ExitSubtree() { depth--; for (int i = 0; i < trees.Length; i++) { trees[i] = trees[i].parent; } AbstractTreeIterator minRef = null; foreach (AbstractTreeIterator t in trees) { if (t.matches != t) { continue; } if (minRef == null || t.PathCompare(minRef) < 0) { minRef = t; } } currentHead = minRef; }
/// <summary>Enter into the current subtree.</summary> /// <remarks> /// Enter into the current subtree. /// <p> /// If the current entry is a subtree this method arranges for its children /// to be returned before the next sibling following the subtree is returned. /// </remarks> /// <exception cref="NGit.Errors.MissingObjectException"> /// a subtree was found, but the subtree object does not exist in /// this repository. The repository may be missing objects. /// </exception> /// <exception cref="NGit.Errors.IncorrectObjectTypeException"> /// a subtree was found, and the subtree id does not denote a /// tree, but instead names some other non-tree type of object. /// The repository may have data corruption. /// </exception> /// <exception cref="NGit.Errors.CorruptObjectException"> /// the contents of a tree did not appear to be a tree. The /// repository may have data corruption. /// </exception> /// <exception cref="System.IO.IOException">a loose object or pack file could not be read. /// </exception> public virtual void EnterSubtree() { AbstractTreeIterator ch = currentHead; AbstractTreeIterator[] tmp = new AbstractTreeIterator[trees.Length]; for (int i = 0; i < trees.Length; i++) { AbstractTreeIterator t = trees[i]; AbstractTreeIterator n; if (t.matches == ch && !t.Eof && FileMode.TREE.Equals(t.mode)) { n = t.CreateSubtreeIterator(reader, idBuffer); } else { n = t.CreateEmptyTreeIterator(); } tmp[i] = n; } depth++; advance = false; System.Array.Copy(tmp, 0, trees, 0, trees.Length); }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> internal virtual AbstractTreeIterator Min() { int i = 0; AbstractTreeIterator minRef = trees[i]; while (minRef.Eof && ++i < trees.Length) { minRef = trees[i]; } if (minRef.Eof) { return(minRef); } minRef.matches = minRef; while (++i < trees.Length) { AbstractTreeIterator t = trees[i]; if (t.Eof) { continue; } int cmp = t.PathCompare(minRef); if (cmp < 0) { t.matches = t; minRef = t; } else { if (cmp == 0) { t.matches = minRef; } } } return(minRef); }
/// <summary>Compare two tree's current ObjectId values for equality.</summary> /// <remarks>Compare two tree's current ObjectId values for equality.</remarks> /// <param name="nthA">first tree to compare the object id from.</param> /// <param name="nthB">second tree to compare the object id from.</param> /// <returns> /// result of /// <code>getObjectId(nthA).equals(getObjectId(nthB))</code>. /// </returns> /// <seealso cref="GetObjectId(int)">GetObjectId(int)</seealso> public virtual bool IdEqual(int nthA, int nthB) { AbstractTreeIterator ch = currentHead; AbstractTreeIterator a = trees[nthA]; AbstractTreeIterator b = trees[nthB]; if (a.matches != ch && b.matches != ch) { // If neither tree matches the current path node then neither // tree has this entry. In such case the ObjectId is zero(), // and zero() is always equal to zero(). // return(true); } if (!a.HasId || !b.HasId) { return(false); } if (a.matches == ch && b.matches == ch) { return(a.IdEqual(b)); } return(false); }
/// <summary>Test if the supplied path matches the current entry's path.</summary> /// <remarks> /// Test if the supplied path matches the current entry's path. /// <p> /// This method tests that the supplied path is exactly equal to the current /// entry, or is one of its parent directories. It is faster to use this /// method then to use /// <see cref="PathString()">PathString()</see> /// to first create a String /// object, then test <code>startsWith</code> or some other type of string /// match function. /// </remarks> /// <param name="p"> /// path buffer to test. Callers should ensure the path does not /// end with '/' prior to invocation. /// </param> /// <param name="pLen">number of bytes from <code>buf</code> to test.</param> /// <returns> /// < 0 if p is before the current path; 0 if p matches the current /// path; 1 if the current path is past p and p will never match /// again on this tree walk. /// </returns> public virtual int IsPathPrefix(byte[] p, int pLen) { AbstractTreeIterator t = currentHead; byte[] c = t.path; int cLen = t.pathLen; int ci; for (ci = 0; ci < cLen && ci < pLen; ci++) { int c_value = (c[ci] & unchecked ((int)(0xff))) - (p[ci] & unchecked ((int)(0xff))); if (c_value != 0) { return(c_value); } } if (ci < cLen) { // Ran out of pattern but we still had current data. // If c[ci] == '/' then pattern matches the subtree. // Otherwise we cannot be certain so we return -1. // return(c[ci] == '/' ? 0 : -1); } if (ci < pLen) { // Ran out of current, but we still have pattern data. // If p[ci] == '/' then pattern matches this subtree, // otherwise we cannot be certain so we return -1. // return(p[ci] == '/' ? 0 : -1); } // Both strings are identical. // return(0); }
/// <summary>Create an iterator for a subtree of an existing iterator.</summary> /// <remarks> /// Create an iterator for a subtree of an existing iterator. /// <p> /// The caller is responsible for setting up the path of the child iterator. /// </remarks> /// <param name="p">parent tree iterator.</param> /// <param name="childPath"> /// path array to be used by the child iterator. This path must /// contain the path from the top of the walk to the first child /// and must end with a '/'. /// </param> /// <param name="childPathOffset"> /// position within <code>childPath</code> where the child can /// insert its data. The value at /// <code>childPath[childPathOffset-1]</code> must be '/'. /// </param> protected internal EmptyTreeIterator(AbstractTreeIterator p, byte[] childPath, int childPathOffset) : base(p, childPath, childPathOffset) { pathLen = childPathOffset - 1; }
protected internal EmptyTreeIterator(AbstractTreeIterator p) : base(p) { // Create a root empty tree. pathLen = pathOffset; }
/// <summary> /// Set the tree used by this walk for finding /// <code>.gitmodules</code> /// . /// <p> /// The root tree is not read until the first submodule is encountered by the /// walk. /// <p> /// This method need only be called if constructing a walk manually instead of /// with one of the static factory methods above. /// </summary> /// <param name="id">ID of a tree containing .gitmodules</param> /// <returns>this generator</returns> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public virtual NGit.Submodule.SubmoduleWalk SetRootTree(AnyObjectId id) { CanonicalTreeParser p = new CanonicalTreeParser(); p.Reset(walk.ObjectReader, id); rootTree = p; modulesConfig = null; return this; }
/// <summary> /// Create a generator and advance it to the submodule entry at the given /// path /// </summary> /// <param name="repository"></param> /// <param name="iterator"></param> /// <param name="path"></param> /// <returns>generator at given path, null if no submodule at given path</returns> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public static NGit.Submodule.SubmoduleWalk ForPath(Repository repository, AbstractTreeIterator iterator, string path) { NGit.Submodule.SubmoduleWalk generator = new NGit.Submodule.SubmoduleWalk(repository ); generator.SetTree(iterator); PathFilter filter = PathFilter.Create(path); generator.SetFilter(filter); while (generator.Next()) { if (filter.IsDone(generator.walk)) { return generator; } } return null; }
private static string NameOf(AbstractTreeIterator i) { return RawParseUtils.Decode(Constants.CHARSET, i.path, 0, i.pathLen); }
/// <summary>Create a new iterator with no parent and a prefix.</summary> /// <remarks> /// Create a new iterator with no parent and a prefix. /// <p> /// The prefix path supplied is inserted in front of all paths generated by /// this iterator. It is intended to be used when an iterator is being /// created for a subsection of an overall repository and needs to be /// combined with other iterators that are created to run over the entire /// repository namespace. /// </remarks> /// <param name="prefix"> /// position of this iterator in the repository tree. The value /// may be null or the empty string to indicate the prefix is the /// root of the repository. A trailing slash ('/') is /// automatically appended if the prefix does not end in '/'. /// </param> protected internal AbstractTreeIterator(string prefix) { parent = null; if (prefix != null && prefix.Length > 0) { ByteBuffer b; b = Constants.CHARSET.Encode(CharBuffer.Wrap(prefix)); pathLen = b.Limit(); path = new byte[Math.Max(DEFAULT_PATH_SIZE, pathLen + 1)]; b.Get(path, 0, pathLen); if (path[pathLen - 1] != '/') { path[pathLen++] = (byte)('/'); } pathOffset = pathLen; } else { path = new byte[DEFAULT_PATH_SIZE]; pathOffset = 0; } }
private static bool NameEqual(AbstractTreeIterator a, AbstractTreeIterator b) { return(a.PathCompare(b, TREE_MODE) == 0); }
/// <summary>Create an iterator for a subtree of an existing iterator.</summary> /// <remarks> /// Create an iterator for a subtree of an existing iterator. /// <p> /// The caller is responsible for setting up the path of the child iterator. /// </remarks> /// <param name="p">parent tree iterator.</param> /// <param name="childPath"> /// path array to be used by the child iterator. This path must /// contain the path from the top of the walk to the first child /// and must end with a '/'. /// </param> /// <param name="childPathOffset"> /// position within <code>childPath</code> where the child can /// insert its data. The value at /// <code>childPath[childPathOffset-1]</code> must be '/'. /// </param> protected internal EmptyTreeIterator(AbstractTreeIterator p, byte[] childPath, int childPathOffset) : base(p, childPath, childPathOffset) { pathLen = childPathOffset - 1; }
/// <summary>Create an iterator for a subtree of an existing iterator.</summary> /// <remarks>Create an iterator for a subtree of an existing iterator.</remarks> /// <param name="p">parent tree iterator.</param> protected internal AbstractTreeIterator(NGit.Treewalk.AbstractTreeIterator p) { parent = p; path = p.path; pathOffset = p.pathLen + 1; try { path[pathOffset - 1] = (byte)('/'); } catch (IndexOutOfRangeException) { GrowPath(p.pathLen); path[pathOffset - 1] = (byte)('/'); } }
private static string NameOf(AbstractTreeIterator i) { return(RawParseUtils.Decode(Constants.CHARSET, i.path, 0, i.pathLen)); }
/// <summary> /// Set the tree used by this walk for finding /// <code>.gitmodules</code> /// . /// <p> /// The root tree is not read until the first submodule is encountered by the /// walk. /// <p> /// This method need only be called if constructing a walk manually instead of /// with one of the static factory methods above. /// </summary> /// <param name="tree">tree containing .gitmodules</param> /// <returns>this generator</returns> public virtual NGit.Submodule.SubmoduleWalk SetRootTree(AbstractTreeIterator tree ) { rootTree = tree; modulesConfig = null; return this; }
/// <summary>A conflict is detected - add the three different stages to the index</summary> /// <param name="path">the path of the conflicting entry</param> /// <param name="e">the previous index entry</param> /// <param name="h">the first tree you want to merge (the HEAD)</param> /// <param name="m">the second tree you want to merge</param> private void Conflict(string path, DirCacheEntry e, AbstractTreeIterator h, AbstractTreeIterator m) { conflicts.AddItem(path); DirCacheEntry entry; if (e != null) { entry = new DirCacheEntry(e.PathString, DirCacheEntry.STAGE_1); entry.CopyMetaData(e, true); builder.Add(entry); } if (h != null && !FileMode.TREE.Equals(h.EntryFileMode)) { entry = new DirCacheEntry(h.EntryPathString, DirCacheEntry.STAGE_2); entry.FileMode = h.EntryFileMode; entry.SetObjectId(h.EntryObjectId); builder.Add(entry); } if (m != null && !FileMode.TREE.Equals(m.EntryFileMode)) { entry = new DirCacheEntry(m.EntryPathString, DirCacheEntry.STAGE_3); entry.FileMode = m.EntryFileMode; entry.SetObjectId(m.EntryObjectId); builder.Add(entry); } }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> private AbstractTreeIterator CombineDF(AbstractTreeIterator minRef) { // Look for a possible D/F conflict forward in the tree(s) // as there may be a "$path/" which matches "$path". Make // such entries match this entry. // AbstractTreeIterator treeMatch = null; foreach (AbstractTreeIterator t in trees) { if (t.matches == minRef || t.Eof) { continue; } for (; ; ) { int cmp = t.PathCompare(minRef, TREE_MODE); if (cmp < 0) { // The "$path/" may still appear later. // t.matchShift++; t.Next(1); if (t.Eof) { t.Back(t.matchShift); t.matchShift = 0; break; } } else { if (cmp == 0) { // We have a conflict match here. // t.matches = minRef; treeMatch = t; break; } else { // A conflict match is not possible. // if (t.matchShift != 0) { t.Back(t.matchShift); t.matchShift = 0; } break; } } } } if (treeMatch != null) { // If we do have a conflict use one of the directory // matching iterators instead of the file iterator. // This way isSubtree is true and isRecursive works. // foreach (AbstractTreeIterator t_1 in trees) { if (t_1.matches == minRef) { t_1.matches = treeMatch; } } if (dfConflict == null) { dfConflict = treeMatch; } return treeMatch; } return minRef; }
/// <summary>Set the tree iterator used for finding submodule entries</summary> /// <param name="iterator"></param> /// <returns>this generator</returns> /// <exception cref="NGit.Errors.CorruptObjectException">NGit.Errors.CorruptObjectException /// </exception> public virtual NGit.Submodule.SubmoduleWalk SetTree(AbstractTreeIterator iterator ) { walk.AddTree(iterator); return this; }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> internal override void SkipEntriesEqual() { AbstractTreeIterator ch = currentHead; for (int i = 0; i < trees.Length; i++) { AbstractTreeIterator t = trees[i]; if (t.matches == ch) { if (t.matchShift == 0) { t.Skip(); } else { t.Back(t.matchShift); t.matchShift = 0; } t.matches = null; } } if (ch == dfConflict) { dfConflict = null; } }
private AbstractTreeIterator FastMin() { fastMinHasMatch = true; int i = 0; AbstractTreeIterator minRef = trees[i]; while (minRef.Eof && ++i < trees.Length) { minRef = trees[i]; } if (minRef.Eof) { return(minRef); } bool hasConflict = false; minRef.matches = minRef; while (++i < trees.Length) { AbstractTreeIterator t = trees[i]; if (t.Eof) { continue; } int cmp = t.PathCompare(minRef); if (cmp < 0) { if (fastMinHasMatch && IsTree(minRef) && !IsTree(t) && NameEqual(minRef, t)) { // We used to be at a tree, but now we are at a file // with the same name. Allow the file to match the // tree anyway. // t.matches = minRef; hasConflict = true; } else { fastMinHasMatch = false; t.matches = t; minRef = t; } } else { if (cmp == 0) { // Exact name/mode match is best. // t.matches = minRef; } else { if (fastMinHasMatch && IsTree(t) && !IsTree(minRef) && NameEqual(t, minRef)) { // The minimum is a file (non-tree) but the next entry // of this iterator is a tree whose name matches our file. // This is a classic D/F conflict and commonly occurs like // this, with no gaps in between the file and directory. // // Use the tree as the minimum instead (see combineDF). // for (int k = 0; k < i; k++) { AbstractTreeIterator p = trees[k]; if (p.matches == minRef) { p.matches = t; } } t.matches = t; minRef = t; hasConflict = true; } else { fastMinHasMatch = false; } } } } if (hasConflict && fastMinHasMatch && dfConflict == null) { dfConflict = minRef; } return(minRef); }
/// <summary>Here the main work is done.</summary> /// <remarks> /// Here the main work is done. This method is called for each existing path /// in head, index and merge. This method decides what to do with the /// corresponding index entry: keep it, update it, remove it or mark a /// conflict. /// </remarks> /// <param name="h">the entry for the head</param> /// <param name="m">the entry for the merge</param> /// <param name="i">the entry for the index</param> /// <param name="f">the file in the working tree</param> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> internal virtual void ProcessEntry(AbstractTreeIterator h, AbstractTreeIterator m , DirCacheBuildIterator i, WorkingTreeIterator f) { DirCacheEntry dce; string name = walk.PathString; if (i == null && m == null && h == null) { // File/Directory conflict case #20 if (walk.IsDirectoryFileConflict()) { // TODO: check whether it is always correct to report a conflict here Conflict(name, null, null, null); } // file only exists in working tree -> ignore it return; } ObjectId iId = (i == null ? null : i.EntryObjectId); ObjectId mId = (m == null ? null : m.EntryObjectId); ObjectId hId = (h == null ? null : h.EntryObjectId); // The information whether head,index,merge iterators are currently // pointing to file/folder/non-existing is encoded into this variable. // // To decode write down ffMask in hexadecimal form. The last digit // represents the state for the merge iterator, the second last the // state for the index iterator and the third last represents the state // for the head iterator. The hexadecimal constant "F" stands for // "file", // an "D" stands for "directory" (tree), and a "0" stands for // non-existing // // Examples: // ffMask == 0xFFD -> Head=File, Index=File, Merge=Tree // ffMask == 0xDD0 -> Head=Tree, Index=Tree, Merge=Non-Existing int ffMask = 0; if (h != null) { ffMask = FileMode.TREE.Equals(h.EntryFileMode) ? unchecked((int)(0xD00)) : unchecked( (int)(0xF00)); } if (i != null) { ffMask |= FileMode.TREE.Equals(i.EntryFileMode) ? unchecked((int)(0x0D0)) : unchecked( (int)(0x0F0)); } if (m != null) { ffMask |= FileMode.TREE.Equals(m.EntryFileMode) ? unchecked((int)(0x00D)) : unchecked( (int)(0x00F)); } // Check whether we have a possible file/folder conflict. Therefore we // need a least one file and one folder. if (((ffMask & unchecked((int)(0x222))) != unchecked((int)(0x000))) && (((ffMask & unchecked((int)(0x00F))) == unchecked((int)(0x00D))) || ((ffMask & unchecked(( int)(0x0F0))) == unchecked((int)(0x0D0))) || ((ffMask & unchecked((int)(0xF00))) == unchecked((int)(0xD00))))) { switch (ffMask) { case unchecked((int)(0xDDF)): { // There are 3*3*3=27 possible combinations of file/folder // conflicts. Some of them are not-relevant because // they represent no conflict, e.g. 0xFFF, 0xDDD, ... The following // switch processes all relevant cases. // 1 2 if (IsModified(name)) { Conflict(name, i.GetDirCacheEntry(), h, m); } else { // 1 Update(name, m.EntryObjectId, m.EntryFileMode); } // 2 break; } case unchecked((int)(0xDFD)): { // 3 4 // CAUTION: I put it into removed instead of updated, because // that's what our tests expect // updated.put(name, mId); Remove(name); break; } case unchecked((int)(0xF0D)): { // 18 Remove(name); break; } case unchecked((int)(0xDFF)): case unchecked((int)(0xFDD)): { // 5 6 // 10 11 // TODO: make use of tree extension as soon as available in jgit // we would like to do something like // if (!iId.equals(mId)) // conflict(name, i.getDirCacheEntry(), h, m); // But since we don't know the id of a tree in the index we do // nothing here and wait that conflicts between index and merge // are found later break; } case unchecked((int)(0xD0F)): { // 19 Update(name, mId, m.EntryFileMode); break; } case unchecked((int)(0xDF0)): case unchecked((int)(0x0FD)): { // conflict without a rule // 15 Conflict(name, (i != null) ? i.GetDirCacheEntry() : null, h, m); break; } case unchecked((int)(0xFDF)): { // 7 8 9 if (hId.Equals(mId)) { if (IsModified(name)) { Conflict(name, i.GetDirCacheEntry(), h, m); } else { // 8 Update(name, mId, m.EntryFileMode); } } else { // 7 if (!IsModified(name)) { Update(name, mId, m.EntryFileMode); } else { // 9 // To be confirmed - this case is not in the table. Conflict(name, i.GetDirCacheEntry(), h, m); } } break; } case unchecked((int)(0xFD0)): { // keep without a rule Keep(i.GetDirCacheEntry()); break; } case unchecked((int)(0xFFD)): { // 12 13 14 if (hId.Equals(iId)) { dce = i.GetDirCacheEntry(); if (f == null || f.IsModified(dce, true)) { Conflict(name, i.GetDirCacheEntry(), h, m); } else { Remove(name); } } else { Conflict(name, i.GetDirCacheEntry(), h, m); } break; } case unchecked((int)(0x0DF)): { // 16 17 if (!IsModified(name)) { Update(name, mId, m.EntryFileMode); } else { Conflict(name, i.GetDirCacheEntry(), h, m); } break; } default: { Keep(i.GetDirCacheEntry()); break; } } return; } // if we have no file at all then there is nothing to do if ((ffMask & unchecked((int)(0x222))) == 0) { return; } if ((ffMask == unchecked((int)(0x00F))) && f != null && FileMode.TREE.Equals(f.EntryFileMode )) { // File/Directory conflict case #20 Conflict(name, null, h, m); } if (i == null) { if (h == null) { Update(name, mId, m.EntryFileMode); } else { // 1 if (m == null) { Remove(name); } else { // 2 Update(name, mId, m.EntryFileMode); } } } else { // 3 dce = i.GetDirCacheEntry(); if (h == null) { if (m == null || mId.Equals(iId)) { if (m == null && walk.IsDirectoryFileConflict()) { if (dce != null && (f == null || f.IsModified(dce, true))) { Conflict(name, i.GetDirCacheEntry(), h, m); } else { Remove(name); } } else { Keep(i.GetDirCacheEntry()); } } else { Conflict(name, i.GetDirCacheEntry(), h, m); } } else { if (m == null) { if (hId.Equals(iId)) { if (f == null || f.IsModified(dce, true)) { Conflict(name, i.GetDirCacheEntry(), h, m); } else { Remove(name); } } else { Conflict(name, i.GetDirCacheEntry(), h, m); } } else { if (!hId.Equals(mId) && !hId.Equals(iId) && !mId.Equals(iId)) { Conflict(name, i.GetDirCacheEntry(), h, m); } else { if (hId.Equals(iId) && !mId.Equals(iId)) { if (dce != null && (f == null || f.IsModified(dce, true))) { Conflict(name, i.GetDirCacheEntry(), h, m); } else { Update(name, mId, m.EntryFileMode); } } else { Keep(i.GetDirCacheEntry()); } } } } } }
private static bool IsTree(AbstractTreeIterator p) { return(FileMode.TREE.Equals(p.mode)); }
private AbstractTreeIterator FastMin() { fastMinHasMatch = true; int i = 0; AbstractTreeIterator minRef = trees[i]; while (minRef.Eof && ++i < trees.Length) { minRef = trees[i]; } if (minRef.Eof) { return minRef; } bool hasConflict = false; minRef.matches = minRef; while (++i < trees.Length) { AbstractTreeIterator t = trees[i]; if (t.Eof) { continue; } int cmp = t.PathCompare(minRef); if (cmp < 0) { if (fastMinHasMatch && IsTree(minRef) && !IsTree(t) && NameEqual(minRef, t)) { // We used to be at a tree, but now we are at a file // with the same name. Allow the file to match the // tree anyway. // t.matches = minRef; hasConflict = true; } else { fastMinHasMatch = false; t.matches = t; minRef = t; } } else { if (cmp == 0) { // Exact name/mode match is best. // t.matches = minRef; } else { if (fastMinHasMatch && IsTree(t) && !IsTree(minRef) && NameEqual(t, minRef)) { // The minimum is a file (non-tree) but the next entry // of this iterator is a tree whose name matches our file. // This is a classic D/F conflict and commonly occurs like // this, with no gaps in between the file and directory. // // Use the tree as the minimum instead (see combineDF). // for (int k = 0; k < i; k++) { AbstractTreeIterator p = trees[k]; if (p.matches == minRef) { p.matches = t; } } t.matches = t; minRef = t; hasConflict = true; } else { fastMinHasMatch = false; } } } } if (hasConflict && fastMinHasMatch && dfConflict == null) { dfConflict = minRef; } return minRef; }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> private AbstractTreeIterator CombineDF(AbstractTreeIterator minRef) { // Look for a possible D/F conflict forward in the tree(s) // as there may be a "$path/" which matches "$path". Make // such entries match this entry. // AbstractTreeIterator treeMatch = null; foreach (AbstractTreeIterator t in trees) { if (t.matches == minRef || t.Eof) { continue; } for (; ;) { int cmp = t.PathCompare(minRef, TREE_MODE); if (cmp < 0) { // The "$path/" may still appear later. // t.matchShift++; t.Next(1); if (t.Eof) { t.Back(t.matchShift); t.matchShift = 0; break; } } else { if (cmp == 0) { // We have a conflict match here. // t.matches = minRef; treeMatch = t; break; } else { // A conflict match is not possible. // if (t.matchShift != 0) { t.Back(t.matchShift); t.matchShift = 0; } break; } } } } if (treeMatch != null) { // If we do have a conflict use one of the directory // matching iterators instead of the file iterator. // This way isSubtree is true and isRecursive works. // foreach (AbstractTreeIterator t_1 in trees) { if (t_1.matches == minRef) { t_1.matches = treeMatch; } } if (dfConflict == null) { dfConflict = treeMatch; } return(treeMatch); } return(minRef); }
private static bool NameEqual(AbstractTreeIterator a, AbstractTreeIterator b) { return a.PathCompare(b, TREE_MODE) == 0; }
/// <summary>Create a new iterator with no parent.</summary> /// <remarks>Create a new iterator with no parent.</remarks> public AbstractTreeIterator() { parent = null; path = new byte[DEFAULT_PATH_SIZE]; pathOffset = 0; }
private static bool IsTree(AbstractTreeIterator p) { return FileMode.TREE.Equals(p.mode); }
/// <summary>Create a new iterator with no parent and a prefix.</summary> /// <remarks> /// Create a new iterator with no parent and a prefix. /// <p> /// The prefix path supplied is inserted in front of all paths generated by /// this iterator. It is intended to be used when an iterator is being /// created for a subsection of an overall repository and needs to be /// combined with other iterators that are created to run over the entire /// repository namespace. /// </remarks> /// <param name="prefix"> /// position of this iterator in the repository tree. The value /// may be null or the empty array to indicate the prefix is the /// root of the repository. A trailing slash ('/') is /// automatically appended if the prefix does not end in '/'. /// </param> protected internal AbstractTreeIterator(byte[] prefix) { parent = null; if (prefix != null && prefix.Length > 0) { pathLen = prefix.Length; path = new byte[Math.Max(DEFAULT_PATH_SIZE, pathLen + 1)]; System.Array.Copy(prefix, 0, path, 0, pathLen); if (path[pathLen - 1] != '/') { path[pathLen++] = (byte)('/'); } pathOffset = pathLen; } else { path = new byte[DEFAULT_PATH_SIZE]; pathOffset = 0; } }
/// <exception cref="NGit.Errors.CorruptObjectException"></exception> private bool SkipEntry(AbstractTreeIterator minRef) { // A tree D/F may have been handled earlier. We need to // not report this path if it has already been reported. // foreach (AbstractTreeIterator t in trees) { if (t.matches == minRef || t.First) { continue; } int stepsBack = 0; for (; ; ) { stepsBack++; t.Back(1); int cmp = t.PathCompare(minRef, 0); if (cmp == 0) { // We have already seen this "$path" before. Skip it. // t.Next(stepsBack); return true; } else { if (cmp < 0 || t.First) { // We cannot find "$path" in t; it will never appear. // t.Next(stepsBack); break; } } } } // We have never seen the current path before. // return false; }
/// <summary>Create an iterator for a subtree of an existing iterator.</summary> /// <remarks> /// Create an iterator for a subtree of an existing iterator. /// <p> /// The caller is responsible for setting up the path of the child iterator. /// </remarks> /// <param name="p">parent tree iterator.</param> /// <param name="childPath"> /// path array to be used by the child iterator. This path must /// contain the path from the top of the walk to the first child /// and must end with a '/'. /// </param> /// <param name="childPathOffset"> /// position within <code>childPath</code> where the child can /// insert its data. The value at /// <code>childPath[childPathOffset-1]</code> must be '/'. /// </param> protected internal AbstractTreeIterator(NGit.Treewalk.AbstractTreeIterator p, byte [] childPath, int childPathOffset) { parent = p; path = childPath; pathOffset = childPathOffset; }
/// <summary> /// Create a generator and advance it to the submodule entry at the given /// path /// </summary> /// <param name="repository"></param> /// <param name="iterator"> /// the root of a tree containing both a submodule at the given path /// and .gitmodules at the root. /// </param> /// <param name="path"></param> /// <returns>generator at given path, null if no submodule at given path</returns> /// <exception cref="System.IO.IOException">System.IO.IOException</exception> public static NGit.Submodule.SubmoduleWalk ForPath(Repository repository, AbstractTreeIterator iterator, string path) { NGit.Submodule.SubmoduleWalk generator = new NGit.Submodule.SubmoduleWalk(repository ); try { generator.SetTree(iterator); PathFilter filter = PathFilter.Create(path); generator.SetFilter(filter); generator.SetRootTree(iterator); while (generator.Next()) { if (filter.IsDone(generator.walk)) { return generator; } } } catch (IOException e) { generator.Release(); throw; } generator.Release(); return null; }