View Javadoc
1   /*
2    * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
3    * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
10   */
11  
12  package org.eclipse.jgit.pgm;
13  
14  import static java.lang.Character.valueOf;
15  
16  import java.io.IOException;
17  import java.text.MessageFormat;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.eclipse.jgit.api.Git;
22  import org.eclipse.jgit.api.PushCommand;
23  import org.eclipse.jgit.api.errors.GitAPIException;
24  import org.eclipse.jgit.lib.Constants;
25  import org.eclipse.jgit.lib.ObjectId;
26  import org.eclipse.jgit.lib.ObjectReader;
27  import org.eclipse.jgit.lib.Ref;
28  import org.eclipse.jgit.lib.TextProgressMonitor;
29  import org.eclipse.jgit.pgm.internal.CLIText;
30  import org.eclipse.jgit.transport.PushResult;
31  import org.eclipse.jgit.transport.RefSpec;
32  import org.eclipse.jgit.transport.RemoteRefUpdate;
33  import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
34  import org.eclipse.jgit.transport.Transport;
35  import org.eclipse.jgit.transport.URIish;
36  import org.kohsuke.args4j.Argument;
37  import org.kohsuke.args4j.Option;
38  
39  @Command(common = true, usage = "usage_UpdateRemoteRepositoryFromLocalRefs")
40  class Push extends TextBuiltin {
41  	@Option(name = "--timeout", metaVar = "metaVar_seconds", usage = "usage_abortConnectionIfNoActivity")
42  	int timeout = -1;
43  
44  	@Argument(index = 0, metaVar = "metaVar_uriish")
45  	private String remote = Constants.DEFAULT_REMOTE_NAME;
46  
47  	@Argument(index = 1, metaVar = "metaVar_refspec")
48  	private List<RefSpec> refSpecs = new ArrayList<>();
49  
50  	@Option(name = "--all")
51  	private boolean all;
52  
53  	@Option(name = "--atomic")
54  	private boolean atomic;
55  
56  	@Option(name = "--tags")
57  	private boolean tags;
58  
59  	@Option(name = "--verbose", aliases = { "-v" })
60  	private boolean verbose = false;
61  
62  	@Option(name = "--thin")
63  	private boolean thin = Transport.DEFAULT_PUSH_THIN;
64  
65  	@Option(name = "--no-thin")
66  	void nothin(@SuppressWarnings("unused") final boolean ignored) {
67  		thin = false;
68  	}
69  
70  	@Option(name = "--force", aliases = { "-f" })
71  	private boolean force;
72  
73  	@Option(name = "--receive-pack", metaVar = "metaVar_path")
74  	private String receivePack;
75  
76  	@Option(name = "--dry-run")
77  	private boolean dryRun;
78  
79  	@Option(name = "--push-option", aliases = { "-t" })
80  	private List<String> pushOptions = new ArrayList<>();
81  
82  	private boolean shownURI;
83  
84  	/** {@inheritDoc} */
85  	@Override
86  	protected void run() {
87  		try (Gitit.html#Git">Git git = new Git(db)) {
88  			PushCommand push = git.push();
89  			push.setDryRun(dryRun);
90  			push.setForce(force);
91  			push.setProgressMonitor(new TextProgressMonitor(errw));
92  			push.setReceivePack(receivePack);
93  			push.setRefSpecs(refSpecs);
94  			if (all) {
95  				push.setPushAll();
96  			}
97  			if (tags) {
98  				push.setPushTags();
99  			}
100 			push.setRemote(remote);
101 			push.setThin(thin);
102 			push.setAtomic(atomic);
103 			push.setTimeout(timeout);
104 			if (!pushOptions.isEmpty()) {
105 				push.setPushOptions(pushOptions);
106 			}
107 			Iterable<PushResult> results = push.call();
108 			for (PushResult result : results) {
109 				try (ObjectReader reader = db.newObjectReader()) {
110 					printPushResult(reader, result.getURI(), result);
111 				}
112 			}
113 		} catch (GitAPIException | IOException e) {
114 			throw die(e.getMessage(), e);
115 		}
116 	}
117 
118 	private void printPushResult(final ObjectReader reader, final URIish uri,
119 			final PushResult result) throws IOException {
120 		shownURI = false;
121 		boolean everythingUpToDate = true;
122 
123 		// at first, print up-to-date ones...
124 		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
125 			if (rru.getStatus() == Status.UP_TO_DATE) {
126 				if (verbose)
127 					printRefUpdateResult(reader, uri, result, rru);
128 			} else
129 				everythingUpToDate = false;
130 		}
131 
132 		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
133 			// ...then successful updates...
134 			if (rru.getStatus() == Status.OK)
135 				printRefUpdateResult(reader, uri, result, rru);
136 		}
137 
138 		for (RemoteRefUpdate rru : result.getRemoteUpdates()) {
139 			// ...finally, others (problematic)
140 			if (rru.getStatus() != Status.OK
141 					&& rru.getStatus() != Status.UP_TO_DATE)
142 				printRefUpdateResult(reader, uri, result, rru);
143 		}
144 
145 		AbstractFetchCommand.showRemoteMessages(errw, result.getMessages());
146 		if (everythingUpToDate)
147 			outw.println(CLIText.get().everythingUpToDate);
148 	}
149 
150 	private void printRefUpdateResult(final ObjectReader reader,
151 			final URIish uri, final PushResult result, final RemoteRefUpdate rru)
152 			throws IOException {
153 		if (!shownURI) {
154 			shownURI = true;
155 			outw.println(MessageFormat.format(CLIText.get().pushTo, uri));
156 		}
157 
158 		final String remoteName = rru.getRemoteName();
159 		final String srcRef = rru.isDelete() ? null : rru.getSrcRef();
160 
161 		switch (rru.getStatus()) {
162 		case OK:
163 			if (rru.isDelete())
164 				printUpdateLine('-', "[deleted]", null, remoteName, null); //$NON-NLS-1$
165 			else {
166 				final Ref oldRef = result.getAdvertisedRef(remoteName);
167 				if (oldRef == null) {
168 					final String summary;
169 					if (remoteName.startsWith(Constants.R_TAGS))
170 						summary = "[new tag]"; //$NON-NLS-1$
171 					else
172 						summary = "[new branch]"; //$NON-NLS-1$
173 					printUpdateLine('*', summary, srcRef, remoteName, null);
174 				} else {
175 					boolean fastForward = rru.isFastForward();
176 					final char flag = fastForward ? ' ' : '+';
177 					final String summary = safeAbbreviate(reader, oldRef
178 							.getObjectId())
179 							+ (fastForward ? ".." : "...") //$NON-NLS-1$ //$NON-NLS-2$
180 							+ safeAbbreviate(reader, rru.getNewObjectId());
181 					final String message = fastForward ? null : CLIText.get().forcedUpdate;
182 					printUpdateLine(flag, summary, srcRef, remoteName, message);
183 				}
184 			}
185 			break;
186 
187 		case NON_EXISTING:
188 			printUpdateLine('X', "[no match]", null, remoteName, null); //$NON-NLS-1$
189 			break;
190 
191 		case REJECTED_NODELETE:
192 			printUpdateLine('!', "[rejected]", null, remoteName, //$NON-NLS-1$
193 					CLIText.get().remoteSideDoesNotSupportDeletingRefs);
194 			break;
195 
196 		case REJECTED_NONFASTFORWARD:
197 			printUpdateLine('!', "[rejected]", srcRef, remoteName, //$NON-NLS-1$
198 					CLIText.get().nonFastForward);
199 			break;
200 
201 		case REJECTED_REMOTE_CHANGED:
202 			final String message = MessageFormat.format(
203 					CLIText.get().remoteRefObjectChangedIsNotExpectedOne,
204 					safeAbbreviate(reader, rru.getExpectedOldObjectId()));
205 			printUpdateLine('!', "[rejected]", srcRef, remoteName, message); //$NON-NLS-1$
206 			break;
207 
208 		case REJECTED_OTHER_REASON:
209 			printUpdateLine('!', "[remote rejected]", srcRef, remoteName, rru //$NON-NLS-1$
210 					.getMessage());
211 			break;
212 
213 		case UP_TO_DATE:
214 			if (verbose)
215 				printUpdateLine('=', "[up to date]", srcRef, remoteName, null); //$NON-NLS-1$
216 			break;
217 
218 		case NOT_ATTEMPTED:
219 		case AWAITING_REPORT:
220 			printUpdateLine('?', "[unexpected push-process behavior]", srcRef, //$NON-NLS-1$
221 					remoteName, rru.getMessage());
222 			break;
223 		}
224 	}
225 
226 	private static String safeAbbreviate(ObjectReader reader, ObjectId id) {
227 		try {
228 			return reader.abbreviate(id).name();
229 		} catch (IOException cannotAbbreviate) {
230 			return id.name();
231 		}
232 	}
233 
234 	private void printUpdateLine(final char flag, final String summary,
235 			final String srcRef, final String destRef, final String message)
236 			throws IOException {
237 		outw.format(" %c %-17s", valueOf(flag), summary); //$NON-NLS-1$
238 
239 		if (srcRef != null)
240 			outw.format(" %s ->", abbreviateRef(srcRef, true)); //$NON-NLS-1$
241 		outw.format(" %s", abbreviateRef(destRef, true)); //$NON-NLS-1$
242 
243 		if (message != null)
244 			outw.format(" (%s)", message); //$NON-NLS-1$
245 
246 		outw.println();
247 	}
248 }