View Javadoc
1   /*
2    * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
3    * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
4    * and other copyright owners as documented in the project's IP log.
5    *
6    * This program and the accompanying materials are made available
7    * under the terms of the Eclipse Distribution License v1.0 which
8    * accompanies this distribution, is reproduced below, and is
9    * available at http://www.eclipse.org/org/documents/edl-v10.php
10   *
11   * All rights reserved.
12   *
13   * Redistribution and use in source and binary forms, with or
14   * without modification, are permitted provided that the following
15   * conditions are met:
16   *
17   * - Redistributions of source code must retain the above copyright
18   *   notice, this list of conditions and the following disclaimer.
19   *
20   * - Redistributions in binary form must reproduce the above
21   *   copyright notice, this list of conditions and the following
22   *   disclaimer in the documentation and/or other materials provided
23   *   with the distribution.
24   *
25   * - Neither the name of the Eclipse Foundation, Inc. nor the
26   *   names of its contributors may be used to endorse or promote
27   *   products derived from this software without specific prior
28   *   written permission.
29   *
30   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43   */
44  
45  package org.eclipse.jgit.pgm;
46  
47  import static java.lang.Character.valueOf;
48  
49  import java.io.IOException;
50  import java.text.MessageFormat;
51  import java.util.ArrayList;
52  import java.util.List;
53  
54  import org.eclipse.jgit.api.Git;
55  import org.eclipse.jgit.api.PushCommand;
56  import org.eclipse.jgit.api.errors.GitAPIException;
57  import org.eclipse.jgit.lib.Constants;
58  import org.eclipse.jgit.lib.ObjectId;
59  import org.eclipse.jgit.lib.ObjectReader;
60  import org.eclipse.jgit.lib.Ref;
61  import org.eclipse.jgit.lib.TextProgressMonitor;
62  import org.eclipse.jgit.pgm.internal.CLIText;
63  import org.eclipse.jgit.transport.PushResult;
64  import org.eclipse.jgit.transport.RefSpec;
65  import org.eclipse.jgit.transport.RemoteRefUpdate;
66  import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
67  import org.eclipse.jgit.transport.Transport;
68  import org.eclipse.jgit.transport.URIish;
69  import org.kohsuke.args4j.Argument;
70  import org.kohsuke.args4j.Option;
71  
72  @Command(common = true, usage = "usage_UpdateRemoteRepositoryFromLocalRefs")
73  class Push extends TextBuiltin {
74  	@Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity")
75  	int timeout = -1;
76  
77  	@Argument(index = 0, metaVar = "metaVar_uriish")
78  	private String remote = Constants.DEFAULT_REMOTE_NAME;
79  
80  	@Argument(index = 1, metaVar = "metaVar_refspec")
81  	private List<RefSpec> refSpecs = new ArrayList<>();
82  
83  	@Option(name = "--all")
84  	private boolean all;
85  
86  	@Option(name = "--atomic")
87  	private boolean atomic;
88  
89  	@Option(name = "--tags")
90  	private boolean tags;
91  
92  	@Option(name = "--verbose", aliases = { "-v" })
93  	private boolean verbose = false;
94  
95  	@Option(name = "--thin")
96  	private boolean thin = Transport.DEFAULT_PUSH_THIN;
97  
98  	@Option(name = "--no-thin")
99  	void nothin(@SuppressWarnings("unused") final boolean ignored) {
100 		thin = false;
101 	}
102 
103 	@Option(name = "--force", aliases = { "-f" })
104 	private boolean force;
105 
106 	@Option(name = "--receive-pack", metaVar = "metaVar_path")
107 	private String receivePack;
108 
109 	@Option(name = "--dry-run")
110 	private boolean dryRun;
111 
112 	@Option(name = "--push-option", aliases = { "-t" })
113 	private List<String> pushOptions = new ArrayList<>();
114 
115 	private boolean shownURI;
116 
117 	/** {@inheritDoc} */
118 	@Override
119 	protected void run() {
120 		try (Gitit.html#Git">Git git = new Git(db)) {
121 			PushCommand push = git.push();
122 			push.setDryRun(dryRun);
123 			push.setForce(force);
124 			push.setProgressMonitor(new TextProgressMonitor(errw));
125 			push.setReceivePack(receivePack);
126 			push.setRefSpecs(refSpecs);
127 			if (all) {
128 				push.setPushAll();
129 			}
130 			if (tags) {
131 				push.setPushTags();
132 			}
133 			push.setRemote(remote);
134 			push.setThin(thin);
135 			push.setAtomic(atomic);
136 			push.setTimeout(timeout);
137 			if (!pushOptions.isEmpty()) {
138 				push.setPushOptions(pushOptions);
139 			}
140 			Iterable<PushResult> results = push.call();
141 			for (PushResult result : results) {
142 				try (ObjectReader reader = db.newObjectReader()) {
143 					printPushResult(reader, result.getURI(), result);
144 				}
145 			}
146 		} catch (GitAPIException | IOException e) {
147 			throw die(e.getMessage(), e);
148 		}
149 	}
150 
151 	private void printPushResult(final ObjectReader reader, final URIish uri,
152 			final PushResult result) throws IOException {
153 		shownURI = false;
154 		boolean everythingUpToDate = true;
155 
156 		// at first, print up-to-date ones...
157 		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
158 			if (rru.getStatus() == Status.UP_TO_DATE) {
159 				if (verbose)
160 					printRefUpdateResult(reader, uri, result, rru);
161 			} else
162 				everythingUpToDate = false;
163 		}
164 
165 		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
166 			// ...then successful updates...
167 			if (rru.getStatus() == Status.OK)
168 				printRefUpdateResult(reader, uri, result, rru);
169 		}
170 
171 		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
172 			// ...finally, others (problematic)
173 			if (rru.getStatus() != Status.OK
174 					&& rru.getStatus() != Status.UP_TO_DATE)
175 				printRefUpdateResult(reader, uri, result, rru);
176 		}
177 
178 		AbstractFetchCommand.showRemoteMessages(errw, result.getMessages());
179 		if (everythingUpToDate)
180 			outw.println(CLIText.get().everythingUpToDate);
181 	}
182 
183 	private void printRefUpdateResult(final ObjectReader reader,
184 			final URIish uri, final PushResult result, final RemoteRefUpdate rru)
185 			throws IOException {
186 		if (!shownURI) {
187 			shownURI = true;
188 			outw.println(MessageFormat.format(CLIText.get().pushTo, uri));
189 		}
190 
191 		final String remoteName = rru.getRemoteName();
192 		final String srcRef = rru.isDelete() ? null : rru.getSrcRef();
193 
194 		switch (rru.getStatus()) {
195 		case OK:
196 			if (rru.isDelete())
197 				printUpdateLine('-', "[deleted]", null, remoteName, null); //$NON-NLS-1$
198 			else {
199 				final Ref oldRef = result.getAdvertisedRef(remoteName);
200 				if (oldRef == null) {
201 					final String summary;
202 					if (remoteName.startsWith(Constants.R_TAGS))
203 						summary = "[new tag]"; //$NON-NLS-1$
204 					else
205 						summary = "[new branch]"; //$NON-NLS-1$
206 					printUpdateLine('*', summary, srcRef, remoteName, null);
207 				} else {
208 					boolean fastForward = rru.isFastForward();
209 					final char flag = fastForward ? ' ' : '+';
210 					final String summary = safeAbbreviate(reader, oldRef
211 							.getObjectId())
212 							+ (fastForward ? ".." : "...") //$NON-NLS-1$ //$NON-NLS-2$
213 							+ safeAbbreviate(reader, rru.getNewObjectId());
214 					final String message = fastForward ? null : CLIText.get().forcedUpdate;
215 					printUpdateLine(flag, summary, srcRef, remoteName, message);
216 				}
217 			}
218 			break;
219 
220 		case NON_EXISTING:
221 			printUpdateLine('X', "[no match]", null, remoteName, null); //$NON-NLS-1$
222 			break;
223 
224 		case REJECTED_NODELETE:
225 			printUpdateLine('!', "[rejected]", null, remoteName, //$NON-NLS-1$
226 					CLIText.get().remoteSideDoesNotSupportDeletingRefs);
227 			break;
228 
229 		case REJECTED_NONFASTFORWARD:
230 			printUpdateLine('!', "[rejected]", srcRef, remoteName, //$NON-NLS-1$
231 					CLIText.get().nonFastForward);
232 			break;
233 
234 		case REJECTED_REMOTE_CHANGED:
235 			final String message = MessageFormat.format(
236 					CLIText.get().remoteRefObjectChangedIsNotExpectedOne,
237 					safeAbbreviate(reader, rru.getExpectedOldObjectId()));
238 			printUpdateLine('!', "[rejected]", srcRef, remoteName, message); //$NON-NLS-1$
239 			break;
240 
241 		case REJECTED_OTHER_REASON:
242 			printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru //$NON-NLS-1$
243 					.getMessage());
244 			break;
245 
246 		case UP_TO_DATE:
247 			if (verbose)
248 				printUpdateLine('=', "[up to date]", srcRef, remoteName, null); //$NON-NLS-1$
249 			break;
250 
251 		case NOT_ATTEMPTED:
252 		case AWAITING_REPORT:
253 			printUpdateLine('?', "[unexpected push-process behavior]", srcRef, //$NON-NLS-1$
254 					remoteName, rru.getMessage());
255 			break;
256 		}
257 	}
258 
259 	private static String safeAbbreviate(ObjectReader reader, ObjectId id) {
260 		try {
261 			return reader.abbreviate(id).name();
262 		} catch (IOException cannotAbbreviate) {
263 			return id.name();
264 		}
265 	}
266 
267 	private void printUpdateLine(final char flag, final String summary,
268 			final String srcRef, final String destRef, final String message)
269 			throws IOException {
270 		outw.format(" %c %-17s", valueOf(flag), summary); //$NON-NLS-1$
271 
272 		if (srcRef != null)
273 			outw.format(" %s ->", abbreviateRef(srcRef, true)); //$NON-NLS-1$
274 		outw.format(" %s", abbreviateRef(destRef, true)); //$NON-NLS-1$
275 
276 		if (message != null)
277 			outw.format(" (%s)", message); //$NON-NLS-1$
278 
279 		outw.println();
280 	}
281 }