View Javadoc
1   /*
2    * Copyright (C) 2011, Christoph Brill <egore911@egore911.de>
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.Collection;
49  import java.util.Collections;
50  import java.util.HashMap;
51  import java.util.Map;
52  
53  import org.eclipse.jgit.api.errors.GitAPIException;
54  import org.eclipse.jgit.api.errors.InvalidRemoteException;
55  import org.eclipse.jgit.api.errors.JGitInternalException;
56  import org.eclipse.jgit.errors.NotSupportedException;
57  import org.eclipse.jgit.errors.TransportException;
58  import org.eclipse.jgit.internal.JGitText;
59  import org.eclipse.jgit.lib.Constants;
60  import org.eclipse.jgit.lib.Ref;
61  import org.eclipse.jgit.lib.Repository;
62  import org.eclipse.jgit.transport.FetchConnection;
63  import org.eclipse.jgit.transport.RefSpec;
64  import org.eclipse.jgit.transport.Transport;
65  import org.eclipse.jgit.transport.URIish;
66  
67  /**
68   * The ls-remote command
69   *
70   * @see <a
71   *      href="http://www.kernel.org/pub/software/scm/git/docs/git-ls-remote.html"
72   *      >Git documentation about ls-remote</a>
73   */
74  public class LsRemoteCommand extends
75  		TransportCommand<LsRemoteCommand, Collection<Ref>> {
76  
77  	private String remote = Constants.DEFAULT_REMOTE_NAME;
78  
79  	private boolean heads;
80  
81  	private boolean tags;
82  
83  	private String uploadPack;
84  
85  	/**
86  	 * @param repo
87  	 *            local repository or null for operation without local
88  	 *            repository
89  	 */
90  	public LsRemoteCommand(Repository repo) {
91  		super(repo);
92  	}
93  
94  	/**
95  	 * The remote (uri or name) used for the fetch operation. If no remote is
96  	 * set, the default value of <code>Constants.DEFAULT_REMOTE_NAME</code> will
97  	 * be used.
98  	 *
99  	 * @see Constants#DEFAULT_REMOTE_NAME
100 	 * @param remote
101 	 * @return {@code this}
102 	 */
103 	public LsRemoteCommand setRemote(String remote) {
104 		checkCallable();
105 		this.remote = remote;
106 		return this;
107 	}
108 
109 	/**
110 	 * Include refs/heads in references results
111 	 *
112 	 * @param heads
113 	 * @return {@code this}
114 	 */
115 	public LsRemoteCommand setHeads(boolean heads) {
116 		this.heads = heads;
117 		return this;
118 	}
119 
120 	/**
121 	 * Include refs/tags in references results
122 	 *
123 	 * @param tags
124 	 * @return {@code this}
125 	 */
126 	public LsRemoteCommand setTags(boolean tags) {
127 		this.tags = tags;
128 		return this;
129 	}
130 
131 	/**
132 	 * The full path of git-upload-pack on the remote host
133 	 *
134 	 * @param uploadPack
135 	 * @return {@code this}
136 	 */
137 	public LsRemoteCommand setUploadPack(String uploadPack) {
138 		this.uploadPack = uploadPack;
139 		return this;
140 	}
141 
142 	/**
143 	 * Executes the {@code LsRemote} command with all the options and parameters
144 	 * collected by the setter methods (e.g. {@link #setHeads(boolean)}) of this
145 	 * class. Each instance of this class should only be used for one invocation
146 	 * of the command. Don't call this method twice on an instance.
147 	 *
148 	 * @return a collection of references in the remote repository
149 	 * @throws GitAPIException
150 	 *             or subclass thereof when an error occurs
151 	 * @throws InvalidRemoteException
152 	 *             when called with an invalid remote uri
153 	 * @throws org.eclipse.jgit.api.errors.TransportException
154 	 *             for errors that occurs during transport
155 	 */
156 	public Collection<Ref> call() throws GitAPIException,
157 			InvalidRemoteException,
158 			org.eclipse.jgit.api.errors.TransportException {
159 		return execute().values();
160 	}
161 
162 	/**
163 	 * Same as {@link #call()}, but return Map instead of Collection.
164 	 *
165 	 * @return a map from names to references in the remote repository
166 	 * @throws GitAPIException
167 	 *             or subclass thereof when an error occurs
168 	 * @throws InvalidRemoteException
169 	 *             when called with an invalid remote uri
170 	 * @throws org.eclipse.jgit.api.errors.TransportException
171 	 *             for errors that occurs during transport
172 	 * @since 3.5
173 	 */
174 	public Map<String, Ref> callAsMap() throws GitAPIException,
175 			InvalidRemoteException,
176 			org.eclipse.jgit.api.errors.TransportException {
177 		return Collections.unmodifiableMap(execute());
178 	}
179 
180 	private Map<String, Ref> execute() throws GitAPIException,
181 			InvalidRemoteException,
182 			org.eclipse.jgit.api.errors.TransportException {
183 		checkCallable();
184 
185 		Transport transport = null;
186 		FetchConnection fc = null;
187 		try {
188 			if (repo != null)
189 				transport = Transport.open(repo, remote);
190 			else
191 				transport = Transport.open(new URIish(remote));
192 			transport.setOptionUploadPack(uploadPack);
193 			configure(transport);
194 			Collection<RefSpec> refSpecs = new ArrayList<RefSpec>(1);
195 			if (tags)
196 				refSpecs.add(new RefSpec(
197 						"refs/tags/*:refs/remotes/origin/tags/*")); //$NON-NLS-1$
198 			if (heads)
199 				refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$
200 			Collection<Ref> refs;
201 			Map<String, Ref> refmap = new HashMap<String, Ref>();
202 			fc = transport.openFetch();
203 			refs = fc.getRefs();
204 			if (refSpecs.isEmpty())
205 				for (Ref r : refs)
206 					refmap.put(r.getName(), r);
207 			else
208 				for (Ref r : refs)
209 					for (RefSpec rs : refSpecs)
210 						if (rs.matchSource(r)) {
211 							refmap.put(r.getName(), r);
212 							break;
213 						}
214 			return refmap;
215 		} catch (URISyntaxException e) {
216 			throw new InvalidRemoteException(MessageFormat.format(
217 					JGitText.get().invalidRemote, remote));
218 		} catch (NotSupportedException e) {
219 			throw new JGitInternalException(
220 					JGitText.get().exceptionCaughtDuringExecutionOfLsRemoteCommand,
221 					e);
222 		} catch (TransportException e) {
223 			throw new org.eclipse.jgit.api.errors.TransportException(
224 					e.getMessage(),
225 					e);
226 		} finally {
227 			if (fc != null)
228 				fc.close();
229 			if (transport != null)
230 				transport.close();
231 		}
232 	}
233 
234 }