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

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit.Api/PullCommand.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.IO;
 
45
using NGit;
 
46
using NGit.Api;
 
47
using NGit.Api.Errors;
 
48
using NGit.Transport;
 
49
using Sharpen;
 
50
 
 
51
namespace NGit.Api
 
52
{
 
53
        /// <summary>The Pull command</summary>
 
54
        /// <seealso><a href="http://www.kernel.org/pub/software/scm/git/docs/git-pull.html"
 
55
        /// *      >Git documentation about Pull</a></seealso>
 
56
        public class PullCommand : GitCommand<PullResult>
 
57
        {
 
58
                private int timeout = 0;
 
59
 
 
60
                private static readonly string DOT = ".";
 
61
 
 
62
                private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
 
63
 
 
64
                private CredentialsProvider credentialsProvider;
 
65
 
 
66
                /// <param name="repo"></param>
 
67
                protected internal PullCommand(Repository repo) : base(repo)
 
68
                {
 
69
                }
 
70
 
 
71
                /// <param name="timeout">in seconds</param>
 
72
                /// <returns>this instance</returns>
 
73
                public virtual NGit.Api.PullCommand SetTimeout(int timeout)
 
74
                {
 
75
                        this.timeout = timeout;
 
76
                        return this;
 
77
                }
 
78
 
 
79
                /// <param name="monitor">a progress monitor</param>
 
80
                /// <returns>this instance</returns>
 
81
                public virtual NGit.Api.PullCommand SetProgressMonitor(ProgressMonitor monitor)
 
82
                {
 
83
                        this.monitor = monitor;
 
84
                        return this;
 
85
                }
 
86
 
 
87
                /// <param name="credentialsProvider">
 
88
                /// the
 
89
                /// <see cref="NGit.Transport.CredentialsProvider">NGit.Transport.CredentialsProvider
 
90
                ///     </see>
 
91
                /// to use
 
92
                /// </param>
 
93
                /// <returns>this instance</returns>
 
94
                public virtual NGit.Api.PullCommand SetCredentialsProvider(CredentialsProvider credentialsProvider
 
95
                        )
 
96
                {
 
97
                        CheckCallable();
 
98
                        this.credentialsProvider = credentialsProvider;
 
99
                        return this;
 
100
                }
 
101
 
 
102
                /// <summary>
 
103
                /// Executes the
 
104
                /// <code>Pull</code>
 
105
                /// command with all the options and parameters
 
106
                /// collected by the setter methods (e.g.
 
107
                /// <see cref="SetProgressMonitor(NGit.ProgressMonitor)">SetProgressMonitor(NGit.ProgressMonitor)
 
108
                ///     </see>
 
109
                /// ) of this class. Each
 
110
                /// instance of this class should only be used for one invocation of the
 
111
                /// command. Don't call this method twice on an instance.
 
112
                /// </summary>
 
113
                /// <returns>the result of the pull</returns>
 
114
                /// <exception cref="NGit.Api.Errors.WrongRepositoryStateException"></exception>
 
115
                /// <exception cref="NGit.Api.Errors.InvalidConfigurationException"></exception>
 
116
                /// <exception cref="NGit.Api.Errors.DetachedHeadException"></exception>
 
117
                /// <exception cref="NGit.Api.Errors.InvalidRemoteException"></exception>
 
118
                /// <exception cref="NGit.Api.Errors.CanceledException"></exception>
 
119
                /// <exception cref="NGit.Api.Errors.RefNotFoundException"></exception>
 
120
                public override PullResult Call()
 
121
                {
 
122
                        CheckCallable();
 
123
                        monitor.BeginTask(JGitText.Get().pullTaskName, 2);
 
124
                        string branchName;
 
125
                        try
 
126
                        {
 
127
                                string fullBranch = repo.GetFullBranch();
 
128
                                if (!fullBranch.StartsWith(Constants.R_HEADS))
 
129
                                {
 
130
                                        // we can not pull if HEAD is detached and branch is not
 
131
                                        // specified explicitly
 
132
                                        throw new DetachedHeadException();
 
133
                                }
 
134
                                branchName = Sharpen.Runtime.Substring(fullBranch, Constants.R_HEADS.Length);
 
135
                        }
 
136
                        catch (IOException e)
 
137
                        {
 
138
                                throw new JGitInternalException(JGitText.Get().exceptionCaughtDuringExecutionOfPullCommand
 
139
                                        , e);
 
140
                        }
 
141
                        if (!repo.GetRepositoryState().Equals(RepositoryState.SAFE))
 
142
                        {
 
143
                                throw new WrongRepositoryStateException(MessageFormat.Format(JGitText.Get().cannotPullOnARepoWithState
 
144
                                        , repo.GetRepositoryState().Name()));
 
145
                        }
 
146
                        // get the configured remote for the currently checked out branch
 
147
                        // stored in configuration key branch.<branch name>.remote
 
148
                        Config repoConfig = repo.GetConfig();
 
149
                        string remote = repoConfig.GetString(ConfigConstants.CONFIG_BRANCH_SECTION, branchName
 
150
                                , ConfigConstants.CONFIG_KEY_REMOTE);
 
151
                        if (remote == null)
 
152
                        {
 
153
                                // fall back to default remote
 
154
                                remote = Constants.DEFAULT_REMOTE_NAME;
 
155
                        }
 
156
                        // get the name of the branch in the remote repository
 
157
                        // stored in configuration key branch.<branch name>.merge
 
158
                        string remoteBranchName = repoConfig.GetString(ConfigConstants.CONFIG_BRANCH_SECTION
 
159
                                , branchName, ConfigConstants.CONFIG_KEY_MERGE);
 
160
                        // check if the branch is configured for pull-rebase
 
161
                        bool doRebase = repoConfig.GetBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, branchName
 
162
                                , ConfigConstants.CONFIG_KEY_REBASE, false);
 
163
                        if (remoteBranchName == null)
 
164
                        {
 
165
                                string missingKey = ConfigConstants.CONFIG_BRANCH_SECTION + DOT + branchName + DOT
 
166
                                         + ConfigConstants.CONFIG_KEY_MERGE;
 
167
                                throw new InvalidConfigurationException(MessageFormat.Format(JGitText.Get().missingConfigurationForKey
 
168
                                        , missingKey));
 
169
                        }
 
170
                        bool isRemote = !remote.Equals(".");
 
171
                        string remoteUri;
 
172
                        FetchResult fetchRes;
 
173
                        if (isRemote)
 
174
                        {
 
175
                                remoteUri = repoConfig.GetString("remote", remote, ConfigConstants.CONFIG_KEY_URL
 
176
                                        );
 
177
                                if (remoteUri == null)
 
178
                                {
 
179
                                        string missingKey = ConfigConstants.CONFIG_REMOTE_SECTION + DOT + remote + DOT + 
 
180
                                                ConfigConstants.CONFIG_KEY_URL;
 
181
                                        throw new InvalidConfigurationException(MessageFormat.Format(JGitText.Get().missingConfigurationForKey
 
182
                                                , missingKey));
 
183
                                }
 
184
                                if (monitor.IsCancelled())
 
185
                                {
 
186
                                        throw new CanceledException(MessageFormat.Format(JGitText.Get().operationCanceled
 
187
                                                , JGitText.Get().pullTaskName));
 
188
                                }
 
189
                                FetchCommand fetch = new FetchCommand(repo);
 
190
                                fetch.SetRemote(remote);
 
191
                                fetch.SetProgressMonitor(monitor);
 
192
                                fetch.SetTimeout(this.timeout);
 
193
                                fetch.SetCredentialsProvider(credentialsProvider);
 
194
                                fetchRes = fetch.Call();
 
195
                        }
 
196
                        else
 
197
                        {
 
198
                                // we can skip the fetch altogether
 
199
                                remoteUri = "local repository";
 
200
                                fetchRes = null;
 
201
                        }
 
202
                        monitor.Update(1);
 
203
                        if (monitor.IsCancelled())
 
204
                        {
 
205
                                throw new CanceledException(MessageFormat.Format(JGitText.Get().operationCanceled
 
206
                                        , JGitText.Get().pullTaskName));
 
207
                        }
 
208
                        // we check the updates to see which of the updated branches
 
209
                        // corresponds
 
210
                        // to the remote branch name
 
211
                        AnyObjectId commitToMerge;
 
212
                        if (isRemote)
 
213
                        {
 
214
                                Ref r = null;
 
215
                                if (fetchRes != null)
 
216
                                {
 
217
                                        r = fetchRes.GetAdvertisedRef(remoteBranchName);
 
218
                                        if (r == null)
 
219
                                        {
 
220
                                                r = fetchRes.GetAdvertisedRef(Constants.R_HEADS + remoteBranchName);
 
221
                                        }
 
222
                                }
 
223
                                if (r == null)
 
224
                                {
 
225
                                        throw new JGitInternalException(MessageFormat.Format(JGitText.Get().couldNotGetAdvertisedRef
 
226
                                                , remoteBranchName));
 
227
                                }
 
228
                                else
 
229
                                {
 
230
                                        commitToMerge = r.GetObjectId();
 
231
                                }
 
232
                        }
 
233
                        else
 
234
                        {
 
235
                                try
 
236
                                {
 
237
                                        commitToMerge = repo.Resolve(remoteBranchName);
 
238
                                        if (commitToMerge == null)
 
239
                                        {
 
240
                                                throw new RefNotFoundException(MessageFormat.Format(JGitText.Get().refNotResolved
 
241
                                                        , remoteBranchName));
 
242
                                        }
 
243
                                }
 
244
                                catch (IOException e)
 
245
                                {
 
246
                                        throw new JGitInternalException(JGitText.Get().exceptionCaughtDuringExecutionOfPullCommand
 
247
                                                , e);
 
248
                                }
 
249
                        }
 
250
                        PullResult result;
 
251
                        if (doRebase)
 
252
                        {
 
253
                                RebaseCommand rebase = new RebaseCommand(repo);
 
254
                                try
 
255
                                {
 
256
                                        RebaseResult rebaseRes = rebase.SetUpstream(commitToMerge).SetProgressMonitor(monitor
 
257
                                                ).SetOperation(RebaseCommand.Operation.BEGIN).Call();
 
258
                                        result = new PullResult(fetchRes, remote, rebaseRes);
 
259
                                }
 
260
                                catch (NoHeadException e)
 
261
                                {
 
262
                                        throw new JGitInternalException(e.Message, e);
 
263
                                }
 
264
                                catch (RefNotFoundException e)
 
265
                                {
 
266
                                        throw new JGitInternalException(e.Message, e);
 
267
                                }
 
268
                                catch (JGitInternalException e)
 
269
                                {
 
270
                                        throw new JGitInternalException(e.Message, e);
 
271
                                }
 
272
                                catch (GitAPIException e)
 
273
                                {
 
274
                                        throw new JGitInternalException(e.Message, e);
 
275
                                }
 
276
                        }
 
277
                        else
 
278
                        {
 
279
                                MergeCommand merge = new MergeCommand(repo);
 
280
                                string name = "branch \'" + Repository.ShortenRefName(remoteBranchName) + "\' of "
 
281
                                         + remoteUri;
 
282
                                merge.Include(name, commitToMerge);
 
283
                                MergeCommandResult mergeRes;
 
284
                                try
 
285
                                {
 
286
                                        mergeRes = merge.Call();
 
287
                                        monitor.Update(1);
 
288
                                        result = new PullResult(fetchRes, remote, mergeRes);
 
289
                                }
 
290
                                catch (NoHeadException e)
 
291
                                {
 
292
                                        throw new JGitInternalException(e.Message, e);
 
293
                                }
 
294
                                catch (ConcurrentRefUpdateException e)
 
295
                                {
 
296
                                        throw new JGitInternalException(e.Message, e);
 
297
                                }
 
298
                                catch (NGit.Api.Errors.CheckoutConflictException e)
 
299
                                {
 
300
                                        throw new JGitInternalException(e.Message, e);
 
301
                                }
 
302
                                catch (InvalidMergeHeadsException e)
 
303
                                {
 
304
                                        throw new JGitInternalException(e.Message, e);
 
305
                                }
 
306
                                catch (WrongRepositoryStateException e)
 
307
                                {
 
308
                                        throw new JGitInternalException(e.Message, e);
 
309
                                }
 
310
                                catch (NoMessageException e)
 
311
                                {
 
312
                                        throw new JGitInternalException(e.Message, e);
 
313
                                }
 
314
                        }
 
315
                        monitor.EndTask();
 
316
                        return result;
 
317
                }
 
318
        }
 
319
}