View Javadoc
1   /*
2    * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
3    * and other copyright owners as documented in the project'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  package org.eclipse.jgit.api;
44  
45  import java.net.URISyntaxException;
46  import java.text.MessageFormat;
47  import java.util.ArrayList;
48  import java.util.List;
49  
50  import org.eclipse.jgit.api.errors.GitAPIException;
51  import org.eclipse.jgit.api.errors.InvalidRemoteException;
52  import org.eclipse.jgit.api.errors.JGitInternalException;
53  import org.eclipse.jgit.errors.NoRemoteRepositoryException;
54  import org.eclipse.jgit.errors.NotSupportedException;
55  import org.eclipse.jgit.errors.TransportException;
56  import org.eclipse.jgit.internal.JGitText;
57  import org.eclipse.jgit.lib.ConfigConstants;
58  import org.eclipse.jgit.lib.Constants;
59  import org.eclipse.jgit.lib.NullProgressMonitor;
60  import org.eclipse.jgit.lib.ProgressMonitor;
61  import org.eclipse.jgit.lib.Repository;
62  import org.eclipse.jgit.lib.StoredConfig;
63  import org.eclipse.jgit.transport.FetchResult;
64  import org.eclipse.jgit.transport.RefSpec;
65  import org.eclipse.jgit.transport.TagOpt;
66  import org.eclipse.jgit.transport.Transport;
67  
68  /**
69   * A class used to execute a {@code Fetch} command. It has setters for all
70   * supported options and arguments of this command and a {@link #call()} method
71   * to finally execute the command.
72   *
73   * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-fetch.html"
74   *      >Git documentation about Fetch</a>
75   */
76  public class FetchCommand extends TransportCommand<FetchCommand, FetchResult> {
77  
78  	private String remote = Constants.DEFAULT_REMOTE_NAME;
79  
80  	private List<RefSpec> refSpecs;
81  
82  	private ProgressMonitor monitor = NullProgressMonitor.INSTANCE;
83  
84  	private boolean checkFetchedObjects;
85  
86  	private Boolean removeDeletedRefs;
87  
88  	private boolean dryRun;
89  
90  	private boolean thin = Transport.DEFAULT_FETCH_THIN;
91  
92  	private TagOpt tagOption;
93  
94  	/**
95  	 * @param repo
96  	 */
97  	protected FetchCommand(Repository repo) {
98  		super(repo);
99  		refSpecs = new ArrayList<RefSpec>(3);
100 	}
101 
102 	/**
103 	 * Executes the {@code fetch} command with all the options and parameters
104 	 * collected by the setter methods of this class. Each instance of this
105 	 * class should only be used for one invocation of the command (means: one
106 	 * call to {@link #call()})
107 	 *
108 	 * @return a {@link FetchResult} object representing the successful fetch
109 	 *         result
110 	 * @throws InvalidRemoteException
111 	 *             when called with an invalid remote uri
112 	 * @throws org.eclipse.jgit.api.errors.TransportException
113 	 *             when an error occurs during transport
114 	 */
115 	public FetchResult call() throws GitAPIException, InvalidRemoteException,
116 			org.eclipse.jgit.api.errors.TransportException {
117 		checkCallable();
118 
119 		try {
120 			Transport transport = Transport.open(repo, remote);
121 			try {
122 				transport.setCheckFetchedObjects(checkFetchedObjects);
123 				transport.setRemoveDeletedRefs(isRemoveDeletedRefs());
124 				transport.setDryRun(dryRun);
125 				if (tagOption != null)
126 					transport.setTagOpt(tagOption);
127 				transport.setFetchThin(thin);
128 				configure(transport);
129 
130 				FetchResult result = transport.fetch(monitor, refSpecs);
131 				return result;
132 			} finally {
133 				transport.close();
134 			}
135 		} catch (NoRemoteRepositoryException e) {
136 			throw new InvalidRemoteException(MessageFormat.format(
137 					JGitText.get().invalidRemote, remote), e);
138 		} catch (TransportException e) {
139 			throw new org.eclipse.jgit.api.errors.TransportException(
140 					e.getMessage(), e);
141 		} catch (URISyntaxException e) {
142 			throw new InvalidRemoteException(MessageFormat.format(
143 					JGitText.get().invalidRemote, remote));
144 		} catch (NotSupportedException e) {
145 			throw new JGitInternalException(
146 					JGitText.get().exceptionCaughtDuringExecutionOfFetchCommand,
147 					e);
148 		}
149 
150 	}
151 
152 	/**
153 	 * The remote (uri or name) used for the fetch operation. If no remote is
154 	 * set, the default value of <code>Constants.DEFAULT_REMOTE_NAME</code> will
155 	 * be used.
156 	 *
157 	 * @see Constants#DEFAULT_REMOTE_NAME
158 	 * @param remote
159 	 * @return {@code this}
160 	 */
161 	public FetchCommand setRemote(String remote) {
162 		checkCallable();
163 		this.remote = remote;
164 		return this;
165 	}
166 
167 	/**
168 	 * @return the remote used for the remote operation
169 	 */
170 	public String getRemote() {
171 		return remote;
172 	}
173 
174 	/**
175 	 * @return the timeout used for the fetch operation
176 	 */
177 	public int getTimeout() {
178 		return timeout;
179 	}
180 
181 	/**
182 	 * @return whether to check received objects checked for validity
183 	 */
184 	public boolean isCheckFetchedObjects() {
185 		return checkFetchedObjects;
186 	}
187 
188 	/**
189 	 * If set to true, objects received will be checked for validity
190 	 *
191 	 * @param checkFetchedObjects
192 	 * @return {@code this}
193 	 */
194 	public FetchCommand setCheckFetchedObjects(boolean checkFetchedObjects) {
195 		checkCallable();
196 		this.checkFetchedObjects = checkFetchedObjects;
197 		return this;
198 	}
199 
200 	/**
201 	 * @return whether or not to remove refs which no longer exist in the source
202 	 */
203 	public boolean isRemoveDeletedRefs() {
204 		if (removeDeletedRefs != null)
205 			return removeDeletedRefs.booleanValue();
206 		else { // fall back to configuration
207 			boolean result = false;
208 			StoredConfig config = repo.getConfig();
209 			result = config.getBoolean(ConfigConstants.CONFIG_FETCH_SECTION,
210 					null, ConfigConstants.CONFIG_KEY_PRUNE, result);
211 			result = config.getBoolean(ConfigConstants.CONFIG_REMOTE_SECTION,
212 					remote, ConfigConstants.CONFIG_KEY_PRUNE, result);
213 			return result;
214 		}
215 	}
216 
217 	/**
218 	 * If set to true, refs are removed which no longer exist in the source
219 	 *
220 	 * @param removeDeletedRefs
221 	 * @return {@code this}
222 	 */
223 	public FetchCommand setRemoveDeletedRefs(boolean removeDeletedRefs) {
224 		checkCallable();
225 		this.removeDeletedRefs = Boolean.valueOf(removeDeletedRefs);
226 		return this;
227 	}
228 
229 	/**
230 	 * @return the progress monitor for the fetch operation
231 	 */
232 	public ProgressMonitor getProgressMonitor() {
233 		return monitor;
234 	}
235 
236 	/**
237 	 * The progress monitor associated with the fetch operation. By default,
238 	 * this is set to <code>NullProgressMonitor</code>
239 	 *
240 	 * @see NullProgressMonitor
241 	 *
242 	 * @param monitor
243 	 * @return {@code this}
244 	 */
245 	public FetchCommand setProgressMonitor(ProgressMonitor monitor) {
246 		checkCallable();
247 		if (monitor == null) {
248 			monitor = NullProgressMonitor.INSTANCE;
249 		}
250 		this.monitor = monitor;
251 		return this;
252 	}
253 
254 	/**
255 	 * @return the ref specs
256 	 */
257 	public List<RefSpec> getRefSpecs() {
258 		return refSpecs;
259 	}
260 
261 	/**
262 	 * The ref specs to be used in the fetch operation
263 	 *
264 	 * @param specs
265 	 * @return {@code this}
266 	 */
267 	public FetchCommand setRefSpecs(RefSpec... specs) {
268 		checkCallable();
269 		this.refSpecs.clear();
270 		for (RefSpec spec : specs)
271 			refSpecs.add(spec);
272 		return this;
273 	}
274 
275 	/**
276 	 * The ref specs to be used in the fetch operation
277 	 *
278 	 * @param specs
279 	 * @return {@code this}
280 	 */
281 	public FetchCommand setRefSpecs(List<RefSpec> specs) {
282 		checkCallable();
283 		this.refSpecs.clear();
284 		this.refSpecs.addAll(specs);
285 		return this;
286 	}
287 
288 	/**
289 	 * @return the dry run preference for the fetch operation
290 	 */
291 	public boolean isDryRun() {
292 		return dryRun;
293 	}
294 
295 	/**
296 	 * Sets whether the fetch operation should be a dry run
297 	 *
298 	 * @param dryRun
299 	 * @return {@code this}
300 	 */
301 	public FetchCommand setDryRun(boolean dryRun) {
302 		checkCallable();
303 		this.dryRun = dryRun;
304 		return this;
305 	}
306 
307 	/**
308 	 * @return the thin-pack preference for fetch operation
309 	 */
310 	public boolean isThin() {
311 		return thin;
312 	}
313 
314 	/**
315 	 * Sets the thin-pack preference for fetch operation.
316 	 *
317 	 * Default setting is Transport.DEFAULT_FETCH_THIN
318 	 *
319 	 * @param thin
320 	 * @return {@code this}
321 	 */
322 	public FetchCommand setThin(boolean thin) {
323 		checkCallable();
324 		this.thin = thin;
325 		return this;
326 	}
327 
328 	/**
329 	 * Sets the specification of annotated tag behavior during fetch
330 	 *
331 	 * @param tagOpt
332 	 * @return {@code this}
333 	 */
334 	public FetchCommand setTagOpt(TagOpt tagOpt) {
335 		checkCallable();
336 		this.tagOption = tagOpt;
337 		return this;
338 	}
339 }