~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit.Dircache/DirCacheEditor.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit's IP log.
 
4
 
 
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
 
9
 
 
10
All rights reserved.
 
11
 
 
12
Redistribution and use in source and binary forms, with or
 
13
without modification, are permitted provided that the following
 
14
conditions are met:
 
15
 
 
16
- Redistributions of source code must retain the above copyright
 
17
  notice, this list of conditions and the following disclaimer.
 
18
 
 
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.
 
23
 
 
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
 
27
  written permission.
 
28
 
 
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.
 
42
*/
 
43
 
 
44
using System;
 
45
using System.Collections.Generic;
 
46
using NGit;
 
47
using NGit.Dircache;
 
48
using Sharpen;
 
49
 
 
50
namespace NGit.Dircache
 
51
{
 
52
        /// <summary>
 
53
        /// Updates a
 
54
        /// <see cref="DirCache">DirCache</see>
 
55
        /// by supplying discrete edit commands.
 
56
        /// <p>
 
57
        /// An editor updates a DirCache by taking a list of
 
58
        /// <see cref="PathEdit">PathEdit</see>
 
59
        /// commands
 
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
 
64
        /// than
 
65
        /// <see cref="DirCacheBuilder">DirCacheBuilder</see>
 
66
        /// .
 
67
        /// <p>
 
68
        /// </summary>
 
69
        /// <seealso cref="DirCacheBuilder">DirCacheBuilder</seealso>
 
70
        public class DirCacheEditor : BaseDirCacheEditor
 
71
        {
 
72
                private sealed class _IComparer_71 : IComparer<DirCacheEditor.PathEdit>
 
73
                {
 
74
                        public _IComparer_71()
 
75
                        {
 
76
                        }
 
77
 
 
78
                        public int Compare(DirCacheEditor.PathEdit o1, DirCacheEditor.PathEdit o2)
 
79
                        {
 
80
                                byte[] a = o1.path;
 
81
                                byte[] b = o2.path;
 
82
                                return DirCache.Cmp(a, a.Length, b, b.Length);
 
83
                        }
 
84
                }
 
85
 
 
86
                private static readonly IComparer<DirCacheEditor.PathEdit> EDIT_CMP = new _IComparer_71
 
87
                        ();
 
88
 
 
89
                private readonly IList<DirCacheEditor.PathEdit> edits;
 
90
 
 
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.
 
97
                /// </param>
 
98
                protected internal DirCacheEditor(DirCache dc, int ecnt) : base(dc, ecnt)
 
99
                {
 
100
                        edits = new AList<DirCacheEditor.PathEdit>();
 
101
                }
 
102
 
 
103
                /// <summary>Append one edit command to the list of commands to be applied.</summary>
 
104
                /// <remarks>
 
105
                /// Append one edit command to the list of commands to be applied.
 
106
                /// <p>
 
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
 
109
                /// update possible.
 
110
                /// </remarks>
 
111
                /// <param name="edit">another edit command.</param>
 
112
                public virtual void Add(DirCacheEditor.PathEdit edit)
 
113
                {
 
114
                        edits.AddItem(edit);
 
115
                }
 
116
 
 
117
                /// <exception cref="System.IO.IOException"></exception>
 
118
                public override bool Commit()
 
119
                {
 
120
                        if (edits.IsEmpty())
 
121
                        {
 
122
                                // No changes? Don't rewrite the index.
 
123
                                //
 
124
                                cache.Unlock();
 
125
                                return true;
 
126
                        }
 
127
                        return base.Commit();
 
128
                }
 
129
 
 
130
                public override void Finish()
 
131
                {
 
132
                        if (!edits.IsEmpty())
 
133
                        {
 
134
                                ApplyEdits();
 
135
                                Replace();
 
136
                        }
 
137
                }
 
138
 
 
139
                private void ApplyEdits()
 
140
                {
 
141
                        edits.Sort(EDIT_CMP);
 
142
                        int maxIdx = cache.GetEntryCount();
 
143
                        int lastIdx = 0;
 
144
                        foreach (DirCacheEditor.PathEdit e in edits)
 
145
                        {
 
146
                                int eIdx = cache.FindEntry(e.path, e.path.Length);
 
147
                                bool missing = eIdx < 0;
 
148
                                if (eIdx < 0)
 
149
                                {
 
150
                                        eIdx = -(eIdx + 1);
 
151
                                }
 
152
                                int cnt = Math.Min(eIdx, maxIdx) - lastIdx;
 
153
                                if (cnt > 0)
 
154
                                {
 
155
                                        FastKeep(lastIdx, cnt);
 
156
                                }
 
157
                                lastIdx = missing ? eIdx : cache.NextEntry(eIdx);
 
158
                                if (e is DirCacheEditor.DeletePath)
 
159
                                {
 
160
                                        continue;
 
161
                                }
 
162
                                if (e is DirCacheEditor.DeleteTree)
 
163
                                {
 
164
                                        lastIdx = cache.NextEntry(e.path, e.path.Length, eIdx);
 
165
                                        continue;
 
166
                                }
 
167
                                DirCacheEntry ent;
 
168
                                if (missing)
 
169
                                {
 
170
                                        ent = new DirCacheEntry(e.path);
 
171
                                        e.Apply(ent);
 
172
                                        if (ent.RawMode == 0)
 
173
                                        {
 
174
                                                throw new ArgumentException(MessageFormat.Format(JGitText.Get().fileModeNotSetForPath
 
175
                                                        , ent.PathString));
 
176
                                        }
 
177
                                }
 
178
                                else
 
179
                                {
 
180
                                        ent = cache.GetEntry(eIdx);
 
181
                                        e.Apply(ent);
 
182
                                }
 
183
                                FastAdd(ent);
 
184
                        }
 
185
                        int cnt_1 = maxIdx - lastIdx;
 
186
                        if (cnt_1 > 0)
 
187
                        {
 
188
                                FastKeep(lastIdx, cnt_1);
 
189
                        }
 
190
                }
 
191
 
 
192
                /// <summary>Any index record update.</summary>
 
193
                /// <remarks>
 
194
                /// Any index record update.
 
195
                /// <p>
 
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.
 
202
                /// </remarks>
 
203
                public abstract class PathEdit
 
204
                {
 
205
                        internal readonly byte[] path;
 
206
 
 
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)
 
211
                        {
 
212
                                path = Constants.Encode(entryPath);
 
213
                        }
 
214
 
 
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.
 
220
                        /// </param>
 
221
                        public PathEdit(DirCacheEntry ent)
 
222
                        {
 
223
                                path = ent.path;
 
224
                        }
 
225
 
 
226
                        /// <summary>Apply the update to a single cache entry matching the path.</summary>
 
227
                        /// <remarks>
 
228
                        /// Apply the update to a single cache entry matching the path.
 
229
                        /// <p>
 
230
                        /// After apply is invoked the entry is added to the output table, and
 
231
                        /// will be included in the new index.
 
232
                        /// </remarks>
 
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.
 
236
                        /// </param>
 
237
                        public abstract void Apply(DirCacheEntry ent);
 
238
                }
 
239
 
 
240
                /// <summary>Deletes a single file entry from the index.</summary>
 
241
                /// <remarks>
 
242
                /// Deletes a single file entry from the index.
 
243
                /// <p>
 
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>
 
248
                /// instead.
 
249
                /// </remarks>
 
250
                /// <seealso cref="DeleteTree">DeleteTree</seealso>
 
251
                public sealed class DeletePath : DirCacheEditor.PathEdit
 
252
                {
 
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)
 
257
                        {
 
258
                        }
 
259
 
 
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.
 
265
                        /// </param>
 
266
                        public DeletePath(DirCacheEntry ent) : base(ent)
 
267
                        {
 
268
                        }
 
269
 
 
270
                        public override void Apply(DirCacheEntry ent)
 
271
                        {
 
272
                                throw new NotSupportedException(JGitText.Get().noApplyInDelete);
 
273
                        }
 
274
                }
 
275
 
 
276
                /// <summary>Recursively deletes all paths under a subtree.</summary>
 
277
                /// <remarks>
 
278
                /// Recursively deletes all paths under a subtree.
 
279
                /// <p>
 
280
                /// This deletion command is more generic than
 
281
                /// <see cref="DeletePath">DeletePath</see>
 
282
                /// as it can
 
283
                /// remove all records which appear recursively under the same subtree.
 
284
                /// Multiple stages are removed (if present) for any deleted entry.
 
285
                /// <p>
 
286
                /// This command will not remove a single file entry. To remove a single file
 
287
                /// use
 
288
                /// <see cref="DeletePath">DeletePath</see>
 
289
                /// .
 
290
                /// </remarks>
 
291
                /// <seealso cref="DeletePath">DeletePath</seealso>
 
292
                public sealed class DeleteTree : DirCacheEditor.PathEdit
 
293
                {
 
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.
 
300
                        /// </param>
 
301
                        public DeleteTree(string entryPath) : base(entryPath.EndsWith("/") ? entryPath : 
 
302
                                entryPath + "/")
 
303
                        {
 
304
                        }
 
305
 
 
306
                        public override void Apply(DirCacheEntry ent)
 
307
                        {
 
308
                                throw new NotSupportedException(JGitText.Get().noApplyInDelete);
 
309
                        }
 
310
                }
 
311
        }
 
312
}