2
This code is derived from jgit (http://eclipse.org/jgit).
3
Copyright owners are documented in jgit's IP log.
5
This program and the accompanying materials are made available
6
under the terms of the Eclipse Distribution License v1.0 which
7
accompanies this distribution, is reproduced below, and is
8
available at http://www.eclipse.org/org/documents/edl-v10.php
12
Redistribution and use in source and binary forms, with or
13
without modification, are permitted provided that the following
16
- Redistributions of source code must retain the above copyright
17
notice, this list of conditions and the following disclaimer.
19
- Redistributions in binary form must reproduce the above
20
copyright notice, this list of conditions and the following
21
disclaimer in the documentation and/or other materials provided
22
with the distribution.
24
- Neither the name of the Eclipse Foundation, Inc. nor the
25
names of its contributors may be used to endorse or promote
26
products derived from this software without specific prior
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45
using System.Collections.Generic;
50
namespace NGit.Dircache
54
/// <see cref="DirCache">DirCache</see>
55
/// by supplying discrete edit commands.
57
/// An editor updates a DirCache by taking a list of
58
/// <see cref="PathEdit">PathEdit</see>
60
/// and executing them against the entries of the destination cache to produce a
61
/// new cache. This edit style allows applications to insert a few commands and
62
/// then have the editor compute the proper entry indexes necessary to perform an
63
/// efficient in-order update of the index records. This can be easier to use
65
/// <see cref="DirCacheBuilder">DirCacheBuilder</see>
69
/// <seealso cref="DirCacheBuilder">DirCacheBuilder</seealso>
70
public class DirCacheEditor : BaseDirCacheEditor
72
private sealed class _IComparer_71 : IComparer<DirCacheEditor.PathEdit>
74
public _IComparer_71()
78
public int Compare(DirCacheEditor.PathEdit o1, DirCacheEditor.PathEdit o2)
82
return DirCache.Cmp(a, a.Length, b, b.Length);
86
private static readonly IComparer<DirCacheEditor.PathEdit> EDIT_CMP = new _IComparer_71
89
private readonly IList<DirCacheEditor.PathEdit> edits;
91
/// <summary>Construct a new editor.</summary>
92
/// <remarks>Construct a new editor.</remarks>
93
/// <param name="dc">the cache this editor will eventually update.</param>
94
/// <param name="ecnt">
95
/// estimated number of entries the editor will have upon
96
/// completion. This sizes the initial entry table.
98
protected internal DirCacheEditor(DirCache dc, int ecnt) : base(dc, ecnt)
100
edits = new AList<DirCacheEditor.PathEdit>();
103
/// <summary>Append one edit command to the list of commands to be applied.</summary>
105
/// Append one edit command to the list of commands to be applied.
107
/// Edit commands may be added in any order chosen by the application. They
108
/// are automatically rearranged by the builder to provide the most efficient
111
/// <param name="edit">another edit command.</param>
112
public virtual void Add(DirCacheEditor.PathEdit edit)
117
/// <exception cref="System.IO.IOException"></exception>
118
public override bool Commit()
122
// No changes? Don't rewrite the index.
127
return base.Commit();
130
public override void Finish()
132
if (!edits.IsEmpty())
139
private void ApplyEdits()
141
edits.Sort(EDIT_CMP);
142
int maxIdx = cache.GetEntryCount();
144
foreach (DirCacheEditor.PathEdit e in edits)
146
int eIdx = cache.FindEntry(e.path, e.path.Length);
147
bool missing = eIdx < 0;
152
int cnt = Math.Min(eIdx, maxIdx) - lastIdx;
155
FastKeep(lastIdx, cnt);
157
lastIdx = missing ? eIdx : cache.NextEntry(eIdx);
158
if (e is DirCacheEditor.DeletePath)
162
if (e is DirCacheEditor.DeleteTree)
164
lastIdx = cache.NextEntry(e.path, e.path.Length, eIdx);
170
ent = new DirCacheEntry(e.path);
172
if (ent.RawMode == 0)
174
throw new ArgumentException(MessageFormat.Format(JGitText.Get().fileModeNotSetForPath
180
ent = cache.GetEntry(eIdx);
185
int cnt_1 = maxIdx - lastIdx;
188
FastKeep(lastIdx, cnt_1);
192
/// <summary>Any index record update.</summary>
194
/// Any index record update.
196
/// Applications should subclass and provide their own implementation for the
197
/// <see cref="Apply(DirCacheEntry)">Apply(DirCacheEntry)</see>
198
/// method. The editor will invoke apply once
199
/// for each record in the index which matches the path name. If there are
200
/// multiple records (for example in stages 1, 2 and 3), the edit instance
201
/// will be called multiple times, once for each stage.
203
public abstract class PathEdit
205
internal readonly byte[] path;
207
/// <summary>Create a new update command by path name.</summary>
208
/// <remarks>Create a new update command by path name.</remarks>
209
/// <param name="entryPath">path of the file within the repository.</param>
210
public PathEdit(string entryPath)
212
path = Constants.Encode(entryPath);
215
/// <summary>Create a new update command for an existing entry instance.</summary>
216
/// <remarks>Create a new update command for an existing entry instance.</remarks>
217
/// <param name="ent">
218
/// entry instance to match path of. Only the path of this
219
/// entry is actually considered during command evaluation.
221
public PathEdit(DirCacheEntry ent)
226
/// <summary>Apply the update to a single cache entry matching the path.</summary>
228
/// Apply the update to a single cache entry matching the path.
230
/// After apply is invoked the entry is added to the output table, and
231
/// will be included in the new index.
233
/// <param name="ent">
234
/// the entry being processed. All fields are zeroed out if
235
/// the path is a new path in the index.
237
public abstract void Apply(DirCacheEntry ent);
240
/// <summary>Deletes a single file entry from the index.</summary>
242
/// Deletes a single file entry from the index.
244
/// This deletion command removes only a single file at the given location,
245
/// but removes multiple stages (if present) for that path. To remove a
246
/// complete subtree use
247
/// <see cref="DeleteTree">DeleteTree</see>
250
/// <seealso cref="DeleteTree">DeleteTree</seealso>
251
public sealed class DeletePath : DirCacheEditor.PathEdit
253
/// <summary>Create a new deletion command by path name.</summary>
254
/// <remarks>Create a new deletion command by path name.</remarks>
255
/// <param name="entryPath">path of the file within the repository.</param>
256
public DeletePath(string entryPath) : base(entryPath)
260
/// <summary>Create a new deletion command for an existing entry instance.</summary>
261
/// <remarks>Create a new deletion command for an existing entry instance.</remarks>
262
/// <param name="ent">
263
/// entry instance to remove. Only the path of this entry is
264
/// actually considered during command evaluation.
266
public DeletePath(DirCacheEntry ent) : base(ent)
270
public override void Apply(DirCacheEntry ent)
272
throw new NotSupportedException(JGitText.Get().noApplyInDelete);
276
/// <summary>Recursively deletes all paths under a subtree.</summary>
278
/// Recursively deletes all paths under a subtree.
280
/// This deletion command is more generic than
281
/// <see cref="DeletePath">DeletePath</see>
283
/// remove all records which appear recursively under the same subtree.
284
/// Multiple stages are removed (if present) for any deleted entry.
286
/// This command will not remove a single file entry. To remove a single file
288
/// <see cref="DeletePath">DeletePath</see>
291
/// <seealso cref="DeletePath">DeletePath</seealso>
292
public sealed class DeleteTree : DirCacheEditor.PathEdit
294
/// <summary>Create a new tree deletion command by path name.</summary>
295
/// <remarks>Create a new tree deletion command by path name.</remarks>
296
/// <param name="entryPath">
297
/// path of the subtree within the repository. If the path
298
/// does not end with "/" a "/" is implicitly added to ensure
299
/// only the subtree's contents are matched by the command.
301
public DeleteTree(string entryPath) : base(entryPath.EndsWith("/") ? entryPath :
306
public override void Apply(DirCacheEntry ent)
308
throw new NotSupportedException(JGitText.Get().noApplyInDelete);