~ubuntu-branches/ubuntu/quantal/monodevelop/quantal

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit/RefUpdate.cs

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Mitchell
  • Date: 2011-06-29 06:56:25 UTC
  • mfrom: (1.8.1 upstream) (1.3.11 experimental)
  • Revision ID: james.westby@ubuntu.com-20110629065625-7xx19c4vb95j65pl
Tags: 2.5.92+dfsg-1ubuntu1
* Merge from Debian experimental:
 - Dropped patches & changes to debian/control for Moonlight
   + debian/patches/remove_support_for_moonlight.patch,
   + debian/patches/dont_add_moonlight_to_core_addins.patch,
 - Remaining patches:
   + debian/patches/no_appmenu:

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.IO;
 
46
using NGit;
 
47
using NGit.Errors;
 
48
using NGit.Revwalk;
 
49
using Sharpen;
 
50
 
 
51
namespace NGit
 
52
{
 
53
        /// <summary>Creates, updates or deletes any reference.</summary>
 
54
        /// <remarks>Creates, updates or deletes any reference.</remarks>
 
55
        public abstract class RefUpdate
 
56
        {
 
57
                /// <summary>Status of an update request.</summary>
 
58
                /// <remarks>Status of an update request.</remarks>
 
59
                public enum Result
 
60
                {
 
61
                        NOT_ATTEMPTED,
 
62
                        LOCK_FAILURE,
 
63
                        NO_CHANGE,
 
64
                        NEW,
 
65
                        FORCED,
 
66
                        FAST_FORWARD,
 
67
                        REJECTED,
 
68
                        REJECTED_CURRENT_BRANCH,
 
69
                        IO_FAILURE,
 
70
                        RENAMED
 
71
                }
 
72
 
 
73
                /// <summary>New value the caller wants this ref to have.</summary>
 
74
                /// <remarks>New value the caller wants this ref to have.</remarks>
 
75
                private ObjectId newValue;
 
76
 
 
77
                /// <summary>Does this specification ask for forced updated (rewind/reset)?</summary>
 
78
                private bool force;
 
79
 
 
80
                /// <summary>Identity to record action as within the reflog.</summary>
 
81
                /// <remarks>Identity to record action as within the reflog.</remarks>
 
82
                private PersonIdent refLogIdent;
 
83
 
 
84
                /// <summary>Message the caller wants included in the reflog.</summary>
 
85
                /// <remarks>Message the caller wants included in the reflog.</remarks>
 
86
                private string refLogMessage;
 
87
 
 
88
                /// <summary>
 
89
                /// Should the Result value be appended to
 
90
                /// <see cref="refLogMessage">refLogMessage</see>
 
91
                /// .
 
92
                /// </summary>
 
93
                private bool refLogIncludeResult;
 
94
 
 
95
                /// <summary>Old value of the ref, obtained after we lock it.</summary>
 
96
                /// <remarks>Old value of the ref, obtained after we lock it.</remarks>
 
97
                private ObjectId oldValue;
 
98
 
 
99
                /// <summary>
 
100
                /// If non-null, the value
 
101
                /// <see cref="oldValue">oldValue</see>
 
102
                /// must have to continue.
 
103
                /// </summary>
 
104
                private ObjectId expValue;
 
105
 
 
106
                /// <summary>Result of the update operation.</summary>
 
107
                /// <remarks>Result of the update operation.</remarks>
 
108
                private RefUpdate.Result result = RefUpdate.Result.NOT_ATTEMPTED;
 
109
 
 
110
                private readonly Ref @ref;
 
111
 
 
112
                /// <summary>
 
113
                /// Is this RefUpdate detaching a symbolic ref?
 
114
                /// We need this info since this.ref will normally be peeled of in case of
 
115
                /// detaching a symbolic ref (HEAD for example).
 
116
                /// </summary>
 
117
                /// <remarks>
 
118
                /// Is this RefUpdate detaching a symbolic ref?
 
119
                /// We need this info since this.ref will normally be peeled of in case of
 
120
                /// detaching a symbolic ref (HEAD for example).
 
121
                /// Without this flag we cannot decide whether the ref has to be updated or
 
122
                /// not in case when it was a symbolic ref and the newValue == oldValue.
 
123
                /// </remarks>
 
124
                private bool detachingSymbolicRef;
 
125
 
 
126
                /// <summary>Construct a new update operation for the reference.</summary>
 
127
                /// <remarks>
 
128
                /// Construct a new update operation for the reference.
 
129
                /// <p>
 
130
                /// <code>ref.getObjectId()</code>
 
131
                /// will be used to seed
 
132
                /// <see cref="GetOldObjectId()">GetOldObjectId()</see>
 
133
                /// ,
 
134
                /// which callers can use as part of their own update logic.
 
135
                /// </remarks>
 
136
                /// <param name="ref">the reference that will be updated by this operation.</param>
 
137
                protected internal RefUpdate(Ref @ref)
 
138
                {
 
139
                        this.@ref = @ref;
 
140
                        oldValue = @ref.GetObjectId();
 
141
                        refLogMessage = string.Empty;
 
142
                }
 
143
 
 
144
                /// <returns>the reference database this update modifies.</returns>
 
145
                protected internal abstract RefDatabase GetRefDatabase();
 
146
 
 
147
                /// <returns>the repository storing the database's objects.</returns>
 
148
                protected internal abstract Repository GetRepository();
 
149
 
 
150
                /// <summary>Try to acquire the lock on the reference.</summary>
 
151
                /// <remarks>
 
152
                /// Try to acquire the lock on the reference.
 
153
                /// <p>
 
154
                /// If the locking was successful the implementor must set the current
 
155
                /// identity value by calling
 
156
                /// <see cref="SetOldObjectId(ObjectId)">SetOldObjectId(ObjectId)</see>
 
157
                /// .
 
158
                /// </remarks>
 
159
                /// <param name="deref">
 
160
                /// true if the lock should be taken against the leaf level
 
161
                /// reference; false if it should be taken exactly against the
 
162
                /// current reference.
 
163
                /// </param>
 
164
                /// <returns>
 
165
                /// true if the lock was acquired and the reference is likely
 
166
                /// protected from concurrent modification; false if it failed.
 
167
                /// </returns>
 
168
                /// <exception cref="System.IO.IOException">
 
169
                /// the lock couldn't be taken due to an unexpected storage
 
170
                /// failure, and not because of a concurrent update.
 
171
                /// </exception>
 
172
                protected internal abstract bool TryLock(bool deref);
 
173
 
 
174
                /// <summary>
 
175
                /// Releases the lock taken by
 
176
                /// <see cref="TryLock(bool)">TryLock(bool)</see>
 
177
                /// if it succeeded.
 
178
                /// </summary>
 
179
                protected internal abstract void Unlock();
 
180
 
 
181
                /// <param name="desiredResult"></param>
 
182
                /// <returns>
 
183
                /// 
 
184
                /// <code>result</code>
 
185
                /// </returns>
 
186
                /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
 
187
                protected internal abstract RefUpdate.Result DoUpdate(RefUpdate.Result desiredResult
 
188
                        );
 
189
 
 
190
                /// <param name="desiredResult"></param>
 
191
                /// <returns>
 
192
                /// 
 
193
                /// <code>result</code>
 
194
                /// </returns>
 
195
                /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
 
196
                protected internal abstract RefUpdate.Result DoDelete(RefUpdate.Result desiredResult
 
197
                        );
 
198
 
 
199
                /// <param name="target"></param>
 
200
                /// <returns>
 
201
                /// 
 
202
                /// <see cref="Result.NEW">Result.NEW</see>
 
203
                /// on success.
 
204
                /// </returns>
 
205
                /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
 
206
                protected internal abstract RefUpdate.Result DoLink(string target);
 
207
 
 
208
                /// <summary>Get the name of the ref this update will operate on.</summary>
 
209
                /// <remarks>Get the name of the ref this update will operate on.</remarks>
 
210
                /// <returns>name of underlying ref.</returns>
 
211
                public virtual string GetName()
 
212
                {
 
213
                        return GetRef().GetName();
 
214
                }
 
215
 
 
216
                /// <returns>the reference this update will create or modify.</returns>
 
217
                public virtual Ref GetRef()
 
218
                {
 
219
                        return @ref;
 
220
                }
 
221
 
 
222
                /// <summary>Get the new value the ref will be (or was) updated to.</summary>
 
223
                /// <remarks>Get the new value the ref will be (or was) updated to.</remarks>
 
224
                /// <returns>new value. Null if the caller has not configured it.</returns>
 
225
                public virtual ObjectId GetNewObjectId()
 
226
                {
 
227
                        return newValue;
 
228
                }
 
229
 
 
230
                /// <summary>Tells this RefUpdate that it is actually detaching a symbolic ref.</summary>
 
231
                /// <remarks>Tells this RefUpdate that it is actually detaching a symbolic ref.</remarks>
 
232
                public virtual void SetDetachingSymbolicRef()
 
233
                {
 
234
                        detachingSymbolicRef = true;
 
235
                }
 
236
 
 
237
                /// <summary>Set the new value the ref will update to.</summary>
 
238
                /// <remarks>Set the new value the ref will update to.</remarks>
 
239
                /// <param name="id">the new value.</param>
 
240
                public virtual void SetNewObjectId(AnyObjectId id)
 
241
                {
 
242
                        newValue = id.Copy();
 
243
                }
 
244
 
 
245
                /// <returns>
 
246
                /// the expected value of the ref after the lock is taken, but before
 
247
                /// update occurs. Null to avoid the compare and swap test. Use
 
248
                /// <see cref="ObjectId.ZeroId()">ObjectId.ZeroId()</see>
 
249
                /// to indicate expectation of a
 
250
                /// non-existant ref.
 
251
                /// </returns>
 
252
                public virtual ObjectId GetExpectedOldObjectId()
 
253
                {
 
254
                        return expValue;
 
255
                }
 
256
 
 
257
                /// <param name="id">
 
258
                /// the expected value of the ref after the lock is taken, but
 
259
                /// before update occurs. Null to avoid the compare and swap test.
 
260
                /// Use
 
261
                /// <see cref="ObjectId.ZeroId()">ObjectId.ZeroId()</see>
 
262
                /// to indicate expectation of a
 
263
                /// non-existant ref.
 
264
                /// </param>
 
265
                public virtual void SetExpectedOldObjectId(AnyObjectId id)
 
266
                {
 
267
                        expValue = id != null ? id.ToObjectId() : null;
 
268
                }
 
269
 
 
270
                /// <summary>Check if this update wants to forcefully change the ref.</summary>
 
271
                /// <remarks>Check if this update wants to forcefully change the ref.</remarks>
 
272
                /// <returns>true if this update should ignore merge tests.</returns>
 
273
                public virtual bool IsForceUpdate()
 
274
                {
 
275
                        return force;
 
276
                }
 
277
 
 
278
                /// <summary>Set if this update wants to forcefully change the ref.</summary>
 
279
                /// <remarks>Set if this update wants to forcefully change the ref.</remarks>
 
280
                /// <param name="b">true if this update should ignore merge tests.</param>
 
281
                public virtual void SetForceUpdate(bool b)
 
282
                {
 
283
                        force = b;
 
284
                }
 
285
 
 
286
                /// <returns>identity of the user making the change in the reflog.</returns>
 
287
                public virtual PersonIdent GetRefLogIdent()
 
288
                {
 
289
                        return refLogIdent;
 
290
                }
 
291
 
 
292
                /// <summary>Set the identity of the user appearing in the reflog.</summary>
 
293
                /// <remarks>
 
294
                /// Set the identity of the user appearing in the reflog.
 
295
                /// <p>
 
296
                /// The timestamp portion of the identity is ignored. A new identity with the
 
297
                /// current timestamp will be created automatically when the update occurs
 
298
                /// and the log record is written.
 
299
                /// </remarks>
 
300
                /// <param name="pi">
 
301
                /// identity of the user. If null the identity will be
 
302
                /// automatically determined based on the repository
 
303
                /// configuration.
 
304
                /// </param>
 
305
                public virtual void SetRefLogIdent(PersonIdent pi)
 
306
                {
 
307
                        refLogIdent = pi;
 
308
                }
 
309
 
 
310
                /// <summary>Get the message to include in the reflog.</summary>
 
311
                /// <remarks>Get the message to include in the reflog.</remarks>
 
312
                /// <returns>
 
313
                /// message the caller wants to include in the reflog; null if the
 
314
                /// update should not be logged.
 
315
                /// </returns>
 
316
                public virtual string GetRefLogMessage()
 
317
                {
 
318
                        return refLogMessage;
 
319
                }
 
320
 
 
321
                /// <returns>
 
322
                /// 
 
323
                /// <code>true</code>
 
324
                /// if the ref log message should show the result.
 
325
                /// </returns>
 
326
                protected internal virtual bool IsRefLogIncludingResult()
 
327
                {
 
328
                        return refLogIncludeResult;
 
329
                }
 
330
 
 
331
                /// <summary>Set the message to include in the reflog.</summary>
 
332
                /// <remarks>Set the message to include in the reflog.</remarks>
 
333
                /// <param name="msg">
 
334
                /// the message to describe this change. It may be null if
 
335
                /// appendStatus is null in order not to append to the reflog
 
336
                /// </param>
 
337
                /// <param name="appendStatus">
 
338
                /// true if the status of the ref change (fast-forward or
 
339
                /// forced-update) should be appended to the user supplied
 
340
                /// message.
 
341
                /// </param>
 
342
                public virtual void SetRefLogMessage(string msg, bool appendStatus)
 
343
                {
 
344
                        if (msg == null && !appendStatus)
 
345
                        {
 
346
                                DisableRefLog();
 
347
                        }
 
348
                        else
 
349
                        {
 
350
                                if (msg == null && appendStatus)
 
351
                                {
 
352
                                        refLogMessage = string.Empty;
 
353
                                        refLogIncludeResult = true;
 
354
                                }
 
355
                                else
 
356
                                {
 
357
                                        refLogMessage = msg;
 
358
                                        refLogIncludeResult = appendStatus;
 
359
                                }
 
360
                        }
 
361
                }
 
362
 
 
363
                /// <summary>Don't record this update in the ref's associated reflog.</summary>
 
364
                /// <remarks>Don't record this update in the ref's associated reflog.</remarks>
 
365
                public virtual void DisableRefLog()
 
366
                {
 
367
                        refLogMessage = null;
 
368
                        refLogIncludeResult = false;
 
369
                }
 
370
 
 
371
                /// <summary>The old value of the ref, prior to the update being attempted.</summary>
 
372
                /// <remarks>
 
373
                /// The old value of the ref, prior to the update being attempted.
 
374
                /// <p>
 
375
                /// This value may differ before and after the update method. Initially it is
 
376
                /// populated with the value of the ref before the lock is taken, but the old
 
377
                /// value may change if someone else modified the ref between the time we
 
378
                /// last read it and when the ref was locked for update.
 
379
                /// </remarks>
 
380
                /// <returns>
 
381
                /// the value of the ref prior to the update being attempted; null if
 
382
                /// the updated has not been attempted yet.
 
383
                /// </returns>
 
384
                public virtual ObjectId GetOldObjectId()
 
385
                {
 
386
                        return oldValue;
 
387
                }
 
388
 
 
389
                /// <summary>Set the old value of the ref.</summary>
 
390
                /// <remarks>Set the old value of the ref.</remarks>
 
391
                /// <param name="old">the old value.</param>
 
392
                protected internal virtual void SetOldObjectId(ObjectId old)
 
393
                {
 
394
                        oldValue = old;
 
395
                }
 
396
 
 
397
                /// <summary>Get the status of this update.</summary>
 
398
                /// <remarks>
 
399
                /// Get the status of this update.
 
400
                /// <p>
 
401
                /// The same value that was previously returned from an update method.
 
402
                /// </remarks>
 
403
                /// <returns>the status of the update.</returns>
 
404
                public virtual RefUpdate.Result GetResult()
 
405
                {
 
406
                        return result;
 
407
                }
 
408
 
 
409
                private void RequireCanDoUpdate()
 
410
                {
 
411
                        if (newValue == null)
 
412
                        {
 
413
                                throw new InvalidOperationException(JGitText.Get().aNewObjectIdIsRequired);
 
414
                        }
 
415
                }
 
416
 
 
417
                /// <summary>Force the ref to take the new value.</summary>
 
418
                /// <remarks>
 
419
                /// Force the ref to take the new value.
 
420
                /// <p>
 
421
                /// This is just a convenient helper for setting the force flag, and as such
 
422
                /// the merge test is performed.
 
423
                /// </remarks>
 
424
                /// <returns>the result status of the update.</returns>
 
425
                /// <exception cref="System.IO.IOException">an unexpected IO error occurred while writing changes.
 
426
                ///     </exception>
 
427
                public virtual RefUpdate.Result ForceUpdate()
 
428
                {
 
429
                        force = true;
 
430
                        return Update();
 
431
                }
 
432
 
 
433
                /// <summary>Gracefully update the ref to the new value.</summary>
 
434
                /// <remarks>
 
435
                /// Gracefully update the ref to the new value.
 
436
                /// <p>
 
437
                /// Merge test will be performed according to
 
438
                /// <see cref="IsForceUpdate()">IsForceUpdate()</see>
 
439
                /// .
 
440
                /// <p>
 
441
                /// This is the same as:
 
442
                /// <pre>
 
443
                /// return update(new RevWalk(getRepository()));
 
444
                /// </pre>
 
445
                /// </remarks>
 
446
                /// <returns>the result status of the update.</returns>
 
447
                /// <exception cref="System.IO.IOException">an unexpected IO error occurred while writing changes.
 
448
                ///     </exception>
 
449
                public virtual RefUpdate.Result Update()
 
450
                {
 
451
                        RevWalk rw = new RevWalk(GetRepository());
 
452
                        try
 
453
                        {
 
454
                                return Update(rw);
 
455
                        }
 
456
                        finally
 
457
                        {
 
458
                                rw.Release();
 
459
                        }
 
460
                }
 
461
 
 
462
                /// <summary>Gracefully update the ref to the new value.</summary>
 
463
                /// <remarks>
 
464
                /// Gracefully update the ref to the new value.
 
465
                /// <p>
 
466
                /// Merge test will be performed according to
 
467
                /// <see cref="IsForceUpdate()">IsForceUpdate()</see>
 
468
                /// .
 
469
                /// </remarks>
 
470
                /// <param name="walk">
 
471
                /// a RevWalk instance this update command can borrow to perform
 
472
                /// the merge test. The walk will be reset to perform the test.
 
473
                /// </param>
 
474
                /// <returns>the result status of the update.</returns>
 
475
                /// <exception cref="System.IO.IOException">an unexpected IO error occurred while writing changes.
 
476
                ///     </exception>
 
477
                public virtual RefUpdate.Result Update(RevWalk walk)
 
478
                {
 
479
                        RequireCanDoUpdate();
 
480
                        try
 
481
                        {
 
482
                                return result = UpdateImpl(walk, new _Store_484(this));
 
483
                        }
 
484
                        catch (IOException x)
 
485
                        {
 
486
                                result = RefUpdate.Result.IO_FAILURE;
 
487
                                throw;
 
488
                        }
 
489
                }
 
490
 
 
491
                private sealed class _Store_484 : RefUpdate.Store
 
492
                {
 
493
                        public _Store_484(RefUpdate _enclosing) : base(_enclosing)
 
494
                        {
 
495
                                this._enclosing = _enclosing;
 
496
                        }
 
497
 
 
498
                        /// <exception cref="System.IO.IOException"></exception>
 
499
                        internal override RefUpdate.Result Execute(RefUpdate.Result status)
 
500
                        {
 
501
                                if (status == RefUpdate.Result.NO_CHANGE)
 
502
                                {
 
503
                                        return status;
 
504
                                }
 
505
                                return this._enclosing.DoUpdate(status);
 
506
                        }
 
507
 
 
508
                        private readonly RefUpdate _enclosing;
 
509
                }
 
510
 
 
511
                /// <summary>Delete the ref.</summary>
 
512
                /// <remarks>
 
513
                /// Delete the ref.
 
514
                /// <p>
 
515
                /// This is the same as:
 
516
                /// <pre>
 
517
                /// return delete(new RevWalk(getRepository()));
 
518
                /// </pre>
 
519
                /// </remarks>
 
520
                /// <returns>the result status of the delete.</returns>
 
521
                /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
 
522
                public virtual RefUpdate.Result Delete()
 
523
                {
 
524
                        RevWalk rw = new RevWalk(GetRepository());
 
525
                        try
 
526
                        {
 
527
                                return Delete(rw);
 
528
                        }
 
529
                        finally
 
530
                        {
 
531
                                rw.Release();
 
532
                        }
 
533
                }
 
534
 
 
535
                /// <summary>Delete the ref.</summary>
 
536
                /// <remarks>Delete the ref.</remarks>
 
537
                /// <param name="walk">
 
538
                /// a RevWalk instance this delete command can borrow to perform
 
539
                /// the merge test. The walk will be reset to perform the test.
 
540
                /// </param>
 
541
                /// <returns>the result status of the delete.</returns>
 
542
                /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
 
543
                public virtual RefUpdate.Result Delete(RevWalk walk)
 
544
                {
 
545
                        string myName = GetRef().GetLeaf().GetName();
 
546
                        if (myName.StartsWith(Constants.R_HEADS))
 
547
                        {
 
548
                                Ref head = GetRefDatabase().GetRef(Constants.HEAD);
 
549
                                while (head.IsSymbolic())
 
550
                                {
 
551
                                        head = head.GetTarget();
 
552
                                        if (myName.Equals(head.GetName()))
 
553
                                        {
 
554
                                                return result = RefUpdate.Result.REJECTED_CURRENT_BRANCH;
 
555
                                        }
 
556
                                }
 
557
                        }
 
558
                        try
 
559
                        {
 
560
                                return result = UpdateImpl(walk, new _Store_540(this));
 
561
                        }
 
562
                        catch (IOException x)
 
563
                        {
 
564
                                result = RefUpdate.Result.IO_FAILURE;
 
565
                                throw;
 
566
                        }
 
567
                }
 
568
 
 
569
                private sealed class _Store_540 : RefUpdate.Store
 
570
                {
 
571
                        public _Store_540(RefUpdate _enclosing) : base(_enclosing)
 
572
                        {
 
573
                                this._enclosing = _enclosing;
 
574
                        }
 
575
 
 
576
                        /// <exception cref="System.IO.IOException"></exception>
 
577
                        internal override RefUpdate.Result Execute(RefUpdate.Result status)
 
578
                        {
 
579
                                return this._enclosing.DoDelete(status);
 
580
                        }
 
581
 
 
582
                        private readonly RefUpdate _enclosing;
 
583
                }
 
584
 
 
585
                /// <summary>Replace this reference with a symbolic reference to another reference.</summary>
 
586
                /// <remarks>
 
587
                /// Replace this reference with a symbolic reference to another reference.
 
588
                /// <p>
 
589
                /// This exact reference (not its traversed leaf) is replaced with a symbolic
 
590
                /// reference to the requested name.
 
591
                /// </remarks>
 
592
                /// <param name="target">
 
593
                /// name of the new target for this reference. The new target name
 
594
                /// must be absolute, so it must begin with
 
595
                /// <code>refs/</code>
 
596
                /// .
 
597
                /// </param>
 
598
                /// <returns>
 
599
                /// 
 
600
                /// <see cref="Result.NEW">Result.NEW</see>
 
601
                /// or
 
602
                /// <see cref="Result.FORCED">Result.FORCED</see>
 
603
                /// on success.
 
604
                /// </returns>
 
605
                /// <exception cref="System.IO.IOException">System.IO.IOException</exception>
 
606
                public virtual RefUpdate.Result Link(string target)
 
607
                {
 
608
                        if (!target.StartsWith(Constants.R_REFS))
 
609
                        {
 
610
                                throw new ArgumentException(MessageFormat.Format(JGitText.Get().illegalArgumentNotA
 
611
                                        , Constants.R_REFS));
 
612
                        }
 
613
                        if (GetRefDatabase().IsNameConflicting(GetName()))
 
614
                        {
 
615
                                return RefUpdate.Result.LOCK_FAILURE;
 
616
                        }
 
617
                        try
 
618
                        {
 
619
                                if (!TryLock(false))
 
620
                                {
 
621
                                        return RefUpdate.Result.LOCK_FAILURE;
 
622
                                }
 
623
                                Ref old = GetRefDatabase().GetRef(GetName());
 
624
                                if (old != null && old.IsSymbolic())
 
625
                                {
 
626
                                        Ref dst = old.GetTarget();
 
627
                                        if (target.Equals(dst.GetName()))
 
628
                                        {
 
629
                                                return result = RefUpdate.Result.NO_CHANGE;
 
630
                                        }
 
631
                                }
 
632
                                if (old != null && old.GetObjectId() != null)
 
633
                                {
 
634
                                        SetOldObjectId(old.GetObjectId());
 
635
                                }
 
636
                                Ref dst_1 = GetRefDatabase().GetRef(target);
 
637
                                if (dst_1 != null && dst_1.GetObjectId() != null)
 
638
                                {
 
639
                                        SetNewObjectId(dst_1.GetObjectId());
 
640
                                }
 
641
                                return result = DoLink(target);
 
642
                        }
 
643
                        catch (IOException x)
 
644
                        {
 
645
                                result = RefUpdate.Result.IO_FAILURE;
 
646
                                throw;
 
647
                        }
 
648
                        finally
 
649
                        {
 
650
                                Unlock();
 
651
                        }
 
652
                }
 
653
 
 
654
                /// <exception cref="System.IO.IOException"></exception>
 
655
                private RefUpdate.Result UpdateImpl(RevWalk walk, RefUpdate.Store store)
 
656
                {
 
657
                        RevObject newObj;
 
658
                        RevObject oldObj;
 
659
                        if (GetRefDatabase().IsNameConflicting(GetName()))
 
660
                        {
 
661
                                return RefUpdate.Result.LOCK_FAILURE;
 
662
                        }
 
663
                        try
 
664
                        {
 
665
                                if (!TryLock(true))
 
666
                                {
 
667
                                        return RefUpdate.Result.LOCK_FAILURE;
 
668
                                }
 
669
                                if (expValue != null)
 
670
                                {
 
671
                                        ObjectId o;
 
672
                                        o = oldValue != null ? oldValue : ObjectId.ZeroId;
 
673
                                        if (!AnyObjectId.Equals(expValue, o))
 
674
                                        {
 
675
                                                return RefUpdate.Result.LOCK_FAILURE;
 
676
                                        }
 
677
                                }
 
678
                                if (oldValue == null)
 
679
                                {
 
680
                                        return store.Execute(RefUpdate.Result.NEW);
 
681
                                }
 
682
                                newObj = SafeParse(walk, newValue);
 
683
                                oldObj = SafeParse(walk, oldValue);
 
684
                                if (newObj == oldObj && !detachingSymbolicRef)
 
685
                                {
 
686
                                        return store.Execute(RefUpdate.Result.NO_CHANGE);
 
687
                                }
 
688
                                if (newObj is RevCommit && oldObj is RevCommit)
 
689
                                {
 
690
                                        if (walk.IsMergedInto((RevCommit)oldObj, (RevCommit)newObj))
 
691
                                        {
 
692
                                                return store.Execute(RefUpdate.Result.FAST_FORWARD);
 
693
                                        }
 
694
                                }
 
695
                                if (IsForceUpdate())
 
696
                                {
 
697
                                        return store.Execute(RefUpdate.Result.FORCED);
 
698
                                }
 
699
                                return RefUpdate.Result.REJECTED;
 
700
                        }
 
701
                        finally
 
702
                        {
 
703
                                Unlock();
 
704
                        }
 
705
                }
 
706
 
 
707
                /// <exception cref="System.IO.IOException"></exception>
 
708
                private static RevObject SafeParse(RevWalk rw, AnyObjectId id)
 
709
                {
 
710
                        try
 
711
                        {
 
712
                                return id != null ? rw.ParseAny(id) : null;
 
713
                        }
 
714
                        catch (MissingObjectException)
 
715
                        {
 
716
                                // We can expect some objects to be missing, like if we are
 
717
                                // trying to force a deletion of a branch and the object it
 
718
                                // points to has been pruned from the database due to freak
 
719
                                // corruption accidents (it happens with 'git new-work-dir').
 
720
                                //
 
721
                                return null;
 
722
                        }
 
723
                }
 
724
 
 
725
                /// <summary>Handle the abstraction of storing a ref update.</summary>
 
726
                /// <remarks>
 
727
                /// Handle the abstraction of storing a ref update. This is because both
 
728
                /// updating and deleting of a ref have merge testing in common.
 
729
                /// </remarks>
 
730
                private abstract class Store
 
731
                {
 
732
                        /// <exception cref="System.IO.IOException"></exception>
 
733
                        internal abstract RefUpdate.Result Execute(RefUpdate.Result status);
 
734
 
 
735
                        internal Store(RefUpdate _enclosing)
 
736
                        {
 
737
                                this._enclosing = _enclosing;
 
738
                        }
 
739
 
 
740
                        private readonly RefUpdate _enclosing;
 
741
                }
 
742
        }
 
743
}