View Javadoc
1   /*
2    * Copyright (C) 2011, 2022 Christoph Brill <egore911@egore911.de> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.api;
11  
12  import java.io.IOException;
13  import java.net.URISyntaxException;
14  import java.text.MessageFormat;
15  import java.util.ArrayList;
16  import java.util.Collection;
17  import java.util.Collections;
18  import java.util.HashMap;
19  import java.util.Map;
20  
21  import org.eclipse.jgit.api.errors.GitAPIException;
22  import org.eclipse.jgit.api.errors.InvalidRemoteException;
23  import org.eclipse.jgit.api.errors.JGitInternalException;
24  import org.eclipse.jgit.errors.ConfigInvalidException;
25  import org.eclipse.jgit.errors.NotSupportedException;
26  import org.eclipse.jgit.internal.JGitText;
27  import org.eclipse.jgit.lib.Constants;
28  import org.eclipse.jgit.lib.Ref;
29  import org.eclipse.jgit.lib.Repository;
30  import org.eclipse.jgit.transport.FetchConnection;
31  import org.eclipse.jgit.transport.RefSpec;
32  import org.eclipse.jgit.transport.Transport;
33  import org.eclipse.jgit.transport.URIish;
34  import org.eclipse.jgit.transport.UrlConfig;
35  import org.eclipse.jgit.util.SystemReader;
36  
37  /**
38   * The ls-remote command
39   *
40   * @see <a
41   *      href="http://www.kernel.org/pub/software/scm/git/docs/git-ls-remote.html"
42   *      >Git documentation about ls-remote</a>
43   */
44  public class LsRemoteCommand extends
45  		TransportCommand<LsRemoteCommand, Collection<Ref>> {
46  
47  	private String remote = Constants.DEFAULT_REMOTE_NAME;
48  
49  	private boolean heads;
50  
51  	private boolean tags;
52  
53  	private String uploadPack;
54  
55  	/**
56  	 * Constructor for LsRemoteCommand
57  	 *
58  	 * @param repo
59  	 *            local repository or null for operation without local
60  	 *            repository
61  	 */
62  	public LsRemoteCommand(Repository repo) {
63  		super(repo);
64  	}
65  
66  	/**
67  	 * The remote (uri or name) used for the fetch operation. If no remote is
68  	 * set, the default value of <code>Constants.DEFAULT_REMOTE_NAME</code> will
69  	 * be used.
70  	 *
71  	 * @see Constants#DEFAULT_REMOTE_NAME
72  	 * @param remote
73  	 *            a {@link java.lang.String} object.
74  	 * @return {@code this}
75  	 */
76  	public LsRemoteCommand setRemote(String remote) {
77  		checkCallable();
78  		this.remote = remote;
79  		return this;
80  	}
81  
82  	/**
83  	 * Include refs/heads in references results
84  	 *
85  	 * @param heads
86  	 *            whether to include refs/heads
87  	 * @return {@code this}
88  	 */
89  	public LsRemoteCommand setHeads(boolean heads) {
90  		this.heads = heads;
91  		return this;
92  	}
93  
94  	/**
95  	 * Include refs/tags in references results
96  	 *
97  	 * @param tags
98  	 *            whether to include tags
99  	 * @return {@code this}
100 	 */
101 	public LsRemoteCommand setTags(boolean tags) {
102 		this.tags = tags;
103 		return this;
104 	}
105 
106 	/**
107 	 * The full path of git-upload-pack on the remote host
108 	 *
109 	 * @param uploadPack
110 	 *            the full path of executable providing the git-upload-pack
111 	 *            service on remote host
112 	 * @return {@code this}
113 	 */
114 	public LsRemoteCommand setUploadPack(String uploadPack) {
115 		this.uploadPack = uploadPack;
116 		return this;
117 	}
118 
119 	/**
120 	 * {@inheritDoc}
121 	 * <p>
122 	 * Execute the {@code LsRemote} command with all the options and parameters
123 	 * collected by the setter methods (e.g. {@link #setHeads(boolean)}) of this
124 	 * class. Each instance of this class should only be used for one invocation
125 	 * of the command. Don't call this method twice on an instance.
126 	 */
127 	@Override
128 	public Collection<Ref> call() throws GitAPIException,
129 			InvalidRemoteException,
130 			org.eclipse.jgit.api.errors.TransportException {
131 		return execute().values();
132 	}
133 
134 	/**
135 	 * Same as {@link #call()}, but return Map instead of Collection.
136 	 *
137 	 * @return a map from names to references in the remote repository
138 	 * @throws org.eclipse.jgit.api.errors.GitAPIException
139 	 *             or subclass thereof when an error occurs
140 	 * @throws org.eclipse.jgit.api.errors.InvalidRemoteException
141 	 *             when called with an invalid remote uri
142 	 * @throws org.eclipse.jgit.api.errors.TransportException
143 	 *             for errors that occurs during transport
144 	 * @since 3.5
145 	 */
146 	public Map<String, Ref> callAsMap() throws GitAPIException,
147 			InvalidRemoteException,
148 			org.eclipse.jgit.api.errors.TransportException {
149 		return Collections.unmodifiableMap(execute());
150 	}
151 
152 	private Map<String, Ref> execute() throws GitAPIException,
153 			InvalidRemoteException,
154 			org.eclipse.jgit.api.errors.TransportException {
155 		checkCallable();
156 
157 		try (Transport transport = repo != null
158 				? Transport.open(repo, remote)
159 				: Transport.open(new URIish(translate(remote)))) {
160 			transport.setOptionUploadPack(uploadPack);
161 			configure(transport);
162 			Collection<RefSpec> refSpecs = new ArrayList<>(1);
163 			if (tags)
164 				refSpecs.add(new RefSpec(
165 						"refs/tags/*:refs/remotes/origin/tags/*")); //$NON-NLS-1$
166 			if (heads)
167 				refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$
168 			Collection<Ref> refs;
169 			Map<String, Ref> refmap = new HashMap<>();
170 			try (FetchConnection fc = transport.openFetch(refSpecs)) {
171 				refs = fc.getRefs();
172 				if (refSpecs.isEmpty())
173 					for (Ref r : refs)
174 						refmap.put(r.getName(), r);
175 				else
176 					for (Ref r : refs)
177 						for (RefSpec rs : refSpecs)
178 							if (rs.matchSource(r)) {
179 								refmap.put(r.getName(), r);
180 								break;
181 							}
182 				return refmap;
183 			}
184 		} catch (URISyntaxException e) {
185 			throw new InvalidRemoteException(MessageFormat.format(
186 					JGitText.get().invalidRemote, remote), e);
187 		} catch (NotSupportedException e) {
188 			throw new JGitInternalException(
189 					JGitText.get().exceptionCaughtDuringExecutionOfLsRemoteCommand,
190 					e);
191 		} catch (IOException | ConfigInvalidException e) {
192 			throw new org.eclipse.jgit.api.errors.TransportException(
193 					e.getMessage(), e);
194 		}
195 	}
196 
197 	private String translate(String uri)
198 			throws IOException, ConfigInvalidException {
199 		UrlConfig urls = new UrlConfig(
200 				SystemReader.getInstance().getUserConfig());
201 		return urls.replace(uri);
202 	}
203 }