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 * Constructor for LsRemoteCommand
87 *
88 * @param repo
89 * local repository or null for operation without local
90 * repository
91 */
92 public LsRemoteCommand(Repository repo) {
93 super(repo);
94 }
95
96 /**
97 * The remote (uri or name) used for the fetch operation. If no remote is
98 * set, the default value of <code>Constants.DEFAULT_REMOTE_NAME</code> will
99 * be used.
100 *
101 * @see Constants#DEFAULT_REMOTE_NAME
102 * @param remote
103 * a {@link java.lang.String} object.
104 * @return {@code this}
105 */
106 public LsRemoteCommand setRemote(String remote) {
107 checkCallable();
108 this.remote = remote;
109 return this;
110 }
111
112 /**
113 * Include refs/heads in references results
114 *
115 * @param heads
116 * whether to include refs/heads
117 * @return {@code this}
118 */
119 public LsRemoteCommand setHeads(boolean heads) {
120 this.heads = heads;
121 return this;
122 }
123
124 /**
125 * Include refs/tags in references results
126 *
127 * @param tags
128 * whether to include tags
129 * @return {@code this}
130 */
131 public LsRemoteCommand setTags(boolean tags) {
132 this.tags = tags;
133 return this;
134 }
135
136 /**
137 * The full path of git-upload-pack on the remote host
138 *
139 * @param uploadPack
140 * the full path of executable providing the git-upload-pack
141 * service on remote host
142 * @return {@code this}
143 */
144 public LsRemoteCommand setUploadPack(String uploadPack) {
145 this.uploadPack = uploadPack;
146 return this;
147 }
148
149 /**
150 * {@inheritDoc}
151 * <p>
152 * Execute the {@code LsRemote} command with all the options and parameters
153 * collected by the setter methods (e.g. {@link #setHeads(boolean)}) of this
154 * class. Each instance of this class should only be used for one invocation
155 * of the command. Don't call this method twice on an instance.
156 */
157 @Override
158 public Collection<Ref> call() throws GitAPIException,
159 InvalidRemoteException,
160 org.eclipse.jgit.api.errors.TransportException {
161 return execute().values();
162 }
163
164 /**
165 * Same as {@link #call()}, but return Map instead of Collection.
166 *
167 * @return a map from names to references in the remote repository
168 * @throws org.eclipse.jgit.api.errors.GitAPIException
169 * or subclass thereof when an error occurs
170 * @throws org.eclipse.jgit.api.errors.InvalidRemoteException
171 * when called with an invalid remote uri
172 * @throws org.eclipse.jgit.api.errors.TransportException
173 * for errors that occurs during transport
174 * @since 3.5
175 */
176 public Map<String, Ref> callAsMap() throws GitAPIException,
177 InvalidRemoteException,
178 org.eclipse.jgit.api.errors.TransportException {
179 return Collections.unmodifiableMap(execute());
180 }
181
182 private Map<String, Ref> execute() throws GitAPIException,
183 InvalidRemoteException,
184 org.eclipse.jgit.api.errors.TransportException {
185 checkCallable();
186
187 try (Transport transport = repo != null
188 ? Transport.open(repo, remote)
189 : Transport.open(new URIish(remote))) {
190 transport.setOptionUploadPack(uploadPack);
191 configure(transport);
192 Collection<RefSpec> refSpecs = new ArrayList<>(1);
193 if (tags)
194 refSpecs.add(new RefSpec(
195 "refs/tags/*:refs/remotes/origin/tags/*")); //$NON-NLS-1$
196 if (heads)
197 refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$
198 Collection<Ref> refs;
199 Map<String, Ref> refmap = new HashMap<>();
200 try (FetchConnection fc = transport.openFetch()) {
201 refs = fc.getRefs();
202 if (refSpecs.isEmpty())
203 for (Ref r : refs)
204 refmap.put(r.getName(), r);
205 else
206 for (Ref r : refs)
207 for (RefSpec rs : refSpecs)
208 if (rs.matchSource(r)) {
209 refmap.put(r.getName(), r);
210 break;
211 }
212 return refmap;
213 }
214 } catch (URISyntaxException e) {
215 throw new InvalidRemoteException(MessageFormat.format(
216 JGitText.get().invalidRemote, remote));
217 } catch (NotSupportedException e) {
218 throw new JGitInternalException(
219 JGitText.get().exceptionCaughtDuringExecutionOfLsRemoteCommand,
220 e);
221 } catch (TransportException e) {
222 throw new org.eclipse.jgit.api.errors.TransportException(
223 e.getMessage(),
224 e);
225 }
226 }
227
228 }