refactor: simplify collection.toArray()
[egit/eclipse.git] / org.eclipse.egit.core / src / org / eclipse / egit / core / op / PushOperation.java
blob134fbde85f4db565e0177812b2928d055083e8eb
1 /*******************************************************************************
2 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
3 * Copyright (C) 2011, Mathias Kinzler <mathias.kinzler@sap.com>
4 * Copyright (C) 2012, Robin Stocker <robin@nibor.org>
5 * Copyright (C) 2015, Stephan Hackstedt <stephan.hackstedt@googlemail.com>
6 * Copyright (C) 2016, Thomas Wolf <thomas.wolf@paranor.ch>
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License 2.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-2.0/
13 * SPDX-License-Identifier: EPL-2.0
14 *******************************************************************************/
15 package org.eclipse.egit.core.op;
17 import java.io.OutputStream;
18 import java.lang.reflect.InvocationTargetException;
19 import java.net.URISyntaxException;
20 import java.util.Collection;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.SubMonitor;
24 import org.eclipse.egit.core.Activator;
25 import org.eclipse.egit.core.EclipseGitProgressTransformer;
26 import org.eclipse.egit.core.internal.CoreText;
27 import org.eclipse.jgit.api.Git;
28 import org.eclipse.jgit.api.errors.JGitInternalException;
29 import org.eclipse.jgit.lib.Repository;
30 import org.eclipse.jgit.transport.CredentialsProvider;
31 import org.eclipse.jgit.transport.PushResult;
32 import org.eclipse.jgit.transport.RemoteConfig;
33 import org.eclipse.jgit.transport.RemoteRefUpdate;
34 import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
35 import org.eclipse.jgit.transport.Transport;
36 import org.eclipse.jgit.transport.URIish;
37 import org.eclipse.osgi.util.NLS;
39 /**
40 * Push operation: pushing from local repository to one or many remote ones.
42 public class PushOperation {
44 private final Repository localDb;
46 private final PushOperationSpecification specification;
48 private final boolean dryRun;
50 private final String remoteName;
52 private final int timeout;
54 private OutputStream out;
56 private PushOperationResult operationResult;
58 private CredentialsProvider credentialsProvider;
60 /**
61 * Create push operation for provided specification.
63 * @param localDb
64 * local repository.
65 * @param specification
66 * specification of ref updates for remote repositories.
67 * @param dryRun
68 * true if push operation should just check for possible result
69 * and not really update remote refs, false otherwise - when push
70 * should act normally.
71 * @param timeout
72 * the timeout in seconds (0 for no timeout)
74 public PushOperation(final Repository localDb,
75 final PushOperationSpecification specification,
76 final boolean dryRun, int timeout) {
77 this(localDb, null, specification, dryRun, timeout);
80 /**
81 * Creates a push operation for a remote configuration.
83 * @param localDb
84 * @param remoteName
85 * @param dryRun
86 * @param timeout
88 public PushOperation(final Repository localDb, final String remoteName,
89 final boolean dryRun, int timeout) {
90 this(localDb, remoteName, null, dryRun, timeout);
93 private PushOperation(final Repository localDb, final String remoteName,
94 PushOperationSpecification specification, final boolean dryRun,
95 int timeout) {
96 this.localDb = localDb;
97 this.specification = specification;
98 this.dryRun = dryRun;
99 this.remoteName = remoteName;
100 this.timeout = timeout;
104 * @param credentialsProvider
106 public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
107 this.credentialsProvider = credentialsProvider;
111 * @return the operation's credentials provider
113 public CredentialsProvider getCredentialsProvider() {
114 return credentialsProvider;
118 * @return push operation result
120 public PushOperationResult getOperationResult() {
121 if (operationResult == null)
122 throw new IllegalStateException(CoreText.OperationNotYetExecuted);
123 return operationResult;
127 * @return operation specification, as provided in constructor (may be
128 * <code>null</code>)
130 public PushOperationSpecification getSpecification() {
131 return specification;
135 * @param actMonitor
136 * may be <code>null</code> if progress monitoring is not desired
137 * @throws InvocationTargetException
138 * not really used: failure is communicated via the result (see
139 * {@link #getOperationResult()})
141 public void run(IProgressMonitor actMonitor)
142 throws InvocationTargetException {
144 if (operationResult != null)
145 throw new IllegalStateException(CoreText.OperationAlreadyExecuted);
147 if (this.specification != null)
148 for (URIish uri : this.specification.getURIs()) {
149 for (RemoteRefUpdate update : this.specification
150 .getRefUpdates(uri))
151 if (update.getStatus() != Status.NOT_ATTEMPTED)
152 throw new IllegalStateException(
153 CoreText.RemoteRefUpdateCantBeReused);
156 final int totalWork;
157 if (specification != null) {
158 totalWork = specification.getURIsNumber();
159 } else {
160 totalWork = 1;
163 String taskName = dryRun ? CoreText.PushOperation_taskNameDryRun
164 : CoreText.PushOperation_taskNameNormalRun;
165 SubMonitor progress = SubMonitor.convert(actMonitor, totalWork);
166 progress.setTaskName(taskName);
168 operationResult = new PushOperationResult();
169 try (Git git = new Git(localDb)) {
170 if (specification != null)
171 for (final URIish uri : specification.getURIs()) {
172 if (progress.isCanceled()) {
173 operationResult.addOperationResult(uri,
174 CoreText.PushOperation_resultCancelled);
175 progress.worked(1);
176 continue;
179 Collection<RemoteRefUpdate> refUpdates = specification
180 .getRefUpdates(uri);
181 final EclipseGitProgressTransformer gitSubMonitor = new EclipseGitProgressTransformer(
182 progress.newChild(1));
184 try (Transport transport = Transport.open(localDb, uri)) {
185 transport.setDryRun(dryRun);
186 transport.setTimeout(timeout);
187 if (credentialsProvider != null) {
188 transport.setCredentialsProvider(
189 credentialsProvider);
191 PushResult result = transport.push(gitSubMonitor,
192 refUpdates, out);
194 operationResult.addOperationResult(result.getURI(),
195 result);
196 specification.addURIRefUpdates(result.getURI(),
197 result.getRemoteUpdates());
198 } catch (JGitInternalException e) {
199 String errorMessage = e.getCause() != null
200 ? e.getCause().getMessage() : e.getMessage();
201 String userMessage = NLS.bind(
202 CoreText.PushOperation_InternalExceptionOccurredMessage,
203 errorMessage);
204 handleException(uri, e, userMessage);
205 } catch (Exception e) {
206 handleException(uri, e, e.getMessage());
209 else {
210 final EclipseGitProgressTransformer gitMonitor = new EclipseGitProgressTransformer(
211 progress.newChild(totalWork));
212 try {
213 Iterable<PushResult> results = git.push()
214 .setRemote(remoteName).setDryRun(dryRun)
215 .setTimeout(timeout).setProgressMonitor(gitMonitor)
216 .setCredentialsProvider(credentialsProvider)
217 .setOutputStream(out).call();
218 for (PushResult result : results) {
219 operationResult.addOperationResult(result.getURI(),
220 result);
222 } catch (JGitInternalException e) {
223 String errorMessage = e.getCause() != null
224 ? e.getCause().getMessage() : e.getMessage();
225 String userMessage = NLS.bind(
226 CoreText.PushOperation_InternalExceptionOccurredMessage,
227 errorMessage);
228 URIish uri = getPushURIForErrorHandling();
229 handleException(uri, e, userMessage);
230 } catch (Exception e) {
231 URIish uri = getPushURIForErrorHandling();
232 handleException(uri, e, e.getMessage());
238 private void handleException(final URIish uri, Exception e,
239 String userMessage) {
240 String uriString;
241 if (uri != null) {
242 operationResult.addOperationResult(uri, userMessage);
243 uriString = uri.toString();
244 } else
245 uriString = "retrieving URI failed"; //$NON-NLS-1$
247 String userMessageForUri = NLS.bind(
248 CoreText.PushOperation_ExceptionOccurredDuringPushOnUriMessage,
249 uriString, userMessage);
250 Activator.logError(userMessageForUri, e);
253 private URIish getPushURIForErrorHandling() {
254 RemoteConfig rc = null;
255 try {
256 rc = new RemoteConfig(localDb.getConfig(), remoteName);
257 return rc.getPushURIs().isEmpty() ? rc.getURIs().get(0) : rc
258 .getPushURIs().get(0);
259 } catch (URISyntaxException e) {
260 // should not happen
261 Activator.logError("Reading RemoteConfig failed", e); //$NON-NLS-1$
262 return null;
267 * Sets the output stream this operation will write sideband messages to.
269 * @param out
270 * the outputstream to write to
271 * @since 3.0
273 public void setOutputStream(OutputStream out) {
274 this.out = out;