You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RemoteRefUpdate.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> 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.transport;
  11. import java.io.IOException;
  12. import java.text.MessageFormat;
  13. import org.eclipse.jgit.internal.JGitText;
  14. import org.eclipse.jgit.lib.ObjectId;
  15. import org.eclipse.jgit.lib.Ref;
  16. import org.eclipse.jgit.lib.RefUpdate;
  17. import org.eclipse.jgit.lib.Repository;
  18. import org.eclipse.jgit.revwalk.RevWalk;
  19. /**
  20. * Represent request and status of a remote ref update. Specification is
  21. * provided by client, while status is handled by
  22. * {@link org.eclipse.jgit.transport.PushProcess} class, being read-only for
  23. * client.
  24. * <p>
  25. * Client can create instances of this class directly, basing on user
  26. * specification and advertised refs
  27. * ({@link org.eclipse.jgit.transport.Connection} or through
  28. * {@link org.eclipse.jgit.transport.Transport} helper methods. Apply this
  29. * specification on remote repository using
  30. * {@link org.eclipse.jgit.transport.Transport#push(org.eclipse.jgit.lib.ProgressMonitor, java.util.Collection)}
  31. * method.
  32. * </p>
  33. */
  34. public class RemoteRefUpdate {
  35. /**
  36. * Represent current status of a remote ref update.
  37. */
  38. public enum Status {
  39. /**
  40. * Push process hasn't yet attempted to update this ref. This is the
  41. * default status, prior to push process execution.
  42. */
  43. NOT_ATTEMPTED,
  44. /**
  45. * Remote ref was up to date, there was no need to update anything.
  46. */
  47. UP_TO_DATE,
  48. /**
  49. * Remote ref update was rejected, as it would cause non fast-forward
  50. * update.
  51. */
  52. REJECTED_NONFASTFORWARD,
  53. /**
  54. * Remote ref update was rejected, because remote side doesn't
  55. * support/allow deleting refs.
  56. */
  57. REJECTED_NODELETE,
  58. /**
  59. * Remote ref update was rejected, because old object id on remote
  60. * repository wasn't the same as defined expected old object.
  61. */
  62. REJECTED_REMOTE_CHANGED,
  63. /**
  64. * Remote ref update was rejected for other reason, possibly described
  65. * in {@link RemoteRefUpdate#getMessage()}.
  66. */
  67. REJECTED_OTHER_REASON,
  68. /**
  69. * Remote ref didn't exist. Can occur on delete request of a non
  70. * existing ref.
  71. */
  72. NON_EXISTING,
  73. /**
  74. * Push process is awaiting update report from remote repository. This
  75. * is a temporary state or state after critical error in push process.
  76. */
  77. AWAITING_REPORT,
  78. /**
  79. * Remote ref was successfully updated.
  80. */
  81. OK;
  82. }
  83. private ObjectId expectedOldObjectId;
  84. private final ObjectId newObjectId;
  85. private final String remoteName;
  86. private final TrackingRefUpdate trackingRefUpdate;
  87. private final String srcRef;
  88. private final boolean forceUpdate;
  89. private Status status;
  90. private boolean fastForward;
  91. private String message;
  92. private final Repository localDb;
  93. private RefUpdate localUpdate;
  94. /**
  95. * Construct remote ref update request by providing an update specification.
  96. * Object is created with default
  97. * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
  98. * status and no message.
  99. *
  100. * @param localDb
  101. * local repository to push from.
  102. * @param srcRef
  103. * source revision - any string resolvable by
  104. * {@link org.eclipse.jgit.lib.Repository#resolve(String)}. This
  105. * resolves to the new object that the caller want remote ref to
  106. * be after update. Use null or
  107. * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} string for
  108. * delete request.
  109. * @param remoteName
  110. * full name of a remote ref to update, e.g. "refs/heads/master"
  111. * (no wildcard, no short name).
  112. * @param forceUpdate
  113. * true when caller want remote ref to be updated regardless
  114. * whether it is fast-forward update (old object is ancestor of
  115. * new object).
  116. * @param localName
  117. * optional full name of a local stored tracking branch, to
  118. * update after push, e.g. "refs/remotes/zawir/dirty" (no
  119. * wildcard, no short name); null if no local tracking branch
  120. * should be updated.
  121. * @param expectedOldObjectId
  122. * optional object id that caller is expecting, requiring to be
  123. * advertised by remote side before update; update will take
  124. * place ONLY if remote side advertise exactly this expected id;
  125. * null if caller doesn't care what object id remote side
  126. * advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
  127. * when expecting no remote ref with this name.
  128. * @throws java.io.IOException
  129. * when I/O error occurred during creating
  130. * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
  131. * local tracking branch or srcRef can't be resolved to any
  132. * object.
  133. * @throws java.lang.IllegalArgumentException
  134. * if some required parameter was null
  135. */
  136. public RemoteRefUpdate(final Repository localDb, final String srcRef,
  137. final String remoteName, final boolean forceUpdate,
  138. final String localName, final ObjectId expectedOldObjectId)
  139. throws IOException {
  140. this(localDb, srcRef, srcRef != null ? localDb.resolve(srcRef)
  141. : ObjectId.zeroId(), remoteName, forceUpdate, localName,
  142. expectedOldObjectId);
  143. }
  144. /**
  145. * Construct remote ref update request by providing an update specification.
  146. * Object is created with default
  147. * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
  148. * status and no message.
  149. *
  150. * @param localDb
  151. * local repository to push from.
  152. * @param srcRef
  153. * source revision. Use null to delete.
  154. * @param remoteName
  155. * full name of a remote ref to update, e.g. "refs/heads/master"
  156. * (no wildcard, no short name).
  157. * @param forceUpdate
  158. * true when caller want remote ref to be updated regardless
  159. * whether it is fast-forward update (old object is ancestor of
  160. * new object).
  161. * @param localName
  162. * optional full name of a local stored tracking branch, to
  163. * update after push, e.g. "refs/remotes/zawir/dirty" (no
  164. * wildcard, no short name); null if no local tracking branch
  165. * should be updated.
  166. * @param expectedOldObjectId
  167. * optional object id that caller is expecting, requiring to be
  168. * advertised by remote side before update; update will take
  169. * place ONLY if remote side advertise exactly this expected id;
  170. * null if caller doesn't care what object id remote side
  171. * advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
  172. * when expecting no remote ref with this name.
  173. * @throws java.io.IOException
  174. * when I/O error occurred during creating
  175. * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
  176. * local tracking branch or srcRef can't be resolved to any
  177. * object.
  178. * @throws java.lang.IllegalArgumentException
  179. * if some required parameter was null
  180. */
  181. public RemoteRefUpdate(final Repository localDb, final Ref srcRef,
  182. final String remoteName, final boolean forceUpdate,
  183. final String localName, final ObjectId expectedOldObjectId)
  184. throws IOException {
  185. this(localDb, srcRef != null ? srcRef.getName() : null,
  186. srcRef != null ? srcRef.getObjectId() : null, remoteName,
  187. forceUpdate, localName, expectedOldObjectId);
  188. }
  189. /**
  190. * Construct remote ref update request by providing an update specification.
  191. * Object is created with default
  192. * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#NOT_ATTEMPTED}
  193. * status and no message.
  194. *
  195. * @param localDb
  196. * local repository to push from.
  197. * @param srcRef
  198. * source revision to label srcId with. If null srcId.name() will
  199. * be used instead.
  200. * @param srcId
  201. * The new object that the caller wants remote ref to be after
  202. * update. Use null or
  203. * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} for delete
  204. * request.
  205. * @param remoteName
  206. * full name of a remote ref to update, e.g. "refs/heads/master"
  207. * (no wildcard, no short name).
  208. * @param forceUpdate
  209. * true when caller want remote ref to be updated regardless
  210. * whether it is fast-forward update (old object is ancestor of
  211. * new object).
  212. * @param localName
  213. * optional full name of a local stored tracking branch, to
  214. * update after push, e.g. "refs/remotes/zawir/dirty" (no
  215. * wildcard, no short name); null if no local tracking branch
  216. * should be updated.
  217. * @param expectedOldObjectId
  218. * optional object id that caller is expecting, requiring to be
  219. * advertised by remote side before update; update will take
  220. * place ONLY if remote side advertise exactly this expected id;
  221. * null if caller doesn't care what object id remote side
  222. * advertise. Use {@link org.eclipse.jgit.lib.ObjectId#zeroId()}
  223. * when expecting no remote ref with this name.
  224. * @throws java.io.IOException
  225. * when I/O error occurred during creating
  226. * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
  227. * local tracking branch or srcRef can't be resolved to any
  228. * object.
  229. * @throws java.lang.IllegalArgumentException
  230. * if some required parameter was null
  231. */
  232. public RemoteRefUpdate(final Repository localDb, final String srcRef,
  233. final ObjectId srcId, final String remoteName,
  234. final boolean forceUpdate, final String localName,
  235. final ObjectId expectedOldObjectId) throws IOException {
  236. if (remoteName == null)
  237. throw new IllegalArgumentException(JGitText.get().remoteNameCannotBeNull);
  238. if (srcId == null && srcRef != null)
  239. throw new IOException(MessageFormat.format(
  240. JGitText.get().sourceRefDoesntResolveToAnyObject, srcRef));
  241. if (srcRef != null)
  242. this.srcRef = srcRef;
  243. else if (srcId != null && !srcId.equals(ObjectId.zeroId()))
  244. this.srcRef = srcId.name();
  245. else
  246. this.srcRef = null;
  247. if (srcId != null)
  248. this.newObjectId = srcId;
  249. else
  250. this.newObjectId = ObjectId.zeroId();
  251. this.remoteName = remoteName;
  252. this.forceUpdate = forceUpdate;
  253. if (localName != null && localDb != null) {
  254. localUpdate = localDb.updateRef(localName);
  255. localUpdate.setForceUpdate(true);
  256. localUpdate.setRefLogMessage("push", true); //$NON-NLS-1$
  257. localUpdate.setNewObjectId(newObjectId);
  258. trackingRefUpdate = new TrackingRefUpdate(
  259. true,
  260. remoteName,
  261. localName,
  262. localUpdate.getOldObjectId() != null
  263. ? localUpdate.getOldObjectId()
  264. : ObjectId.zeroId(),
  265. newObjectId);
  266. } else
  267. trackingRefUpdate = null;
  268. this.localDb = localDb;
  269. this.expectedOldObjectId = expectedOldObjectId;
  270. this.status = Status.NOT_ATTEMPTED;
  271. }
  272. /**
  273. * Create a new instance of this object basing on existing instance for
  274. * configuration. State (like {@link #getMessage()}, {@link #getStatus()})
  275. * of base object is not shared. Expected old object id is set up from
  276. * scratch, as this constructor may be used for 2-stage push: first one
  277. * being dry run, second one being actual push.
  278. *
  279. * @param base
  280. * configuration base.
  281. * @param newExpectedOldObjectId
  282. * new expected object id value.
  283. * @throws java.io.IOException
  284. * when I/O error occurred during creating
  285. * {@link org.eclipse.jgit.transport.TrackingRefUpdate} for
  286. * local tracking branch or srcRef of base object no longer can
  287. * be resolved to any object.
  288. */
  289. public RemoteRefUpdate(final RemoteRefUpdate base,
  290. final ObjectId newExpectedOldObjectId) throws IOException {
  291. this(base.localDb, base.srcRef, base.remoteName, base.forceUpdate,
  292. (base.trackingRefUpdate == null ? null : base.trackingRefUpdate
  293. .getLocalName()), newExpectedOldObjectId);
  294. }
  295. /**
  296. * Get expected old object id
  297. *
  298. * @return expectedOldObjectId required to be advertised by remote side, as
  299. * set in constructor; may be null.
  300. */
  301. public ObjectId getExpectedOldObjectId() {
  302. return expectedOldObjectId;
  303. }
  304. /**
  305. * Whether some object is required to be advertised by remote side, as set
  306. * in constructor
  307. *
  308. * @return true if some object is required to be advertised by remote side,
  309. * as set in constructor; false otherwise.
  310. */
  311. public boolean isExpectingOldObjectId() {
  312. return expectedOldObjectId != null;
  313. }
  314. /**
  315. * Get new object id
  316. *
  317. * @return newObjectId for remote ref, as set in constructor.
  318. */
  319. public ObjectId getNewObjectId() {
  320. return newObjectId;
  321. }
  322. /**
  323. * Whether this update is a deleting update
  324. *
  325. * @return true if this update is deleting update; false otherwise.
  326. */
  327. public boolean isDelete() {
  328. return ObjectId.zeroId().equals(newObjectId);
  329. }
  330. /**
  331. * Get name of remote ref to update
  332. *
  333. * @return name of remote ref to update, as set in constructor.
  334. */
  335. public String getRemoteName() {
  336. return remoteName;
  337. }
  338. /**
  339. * Get tracking branch update if localName was set in constructor.
  340. *
  341. * @return local tracking branch update if localName was set in constructor.
  342. */
  343. public TrackingRefUpdate getTrackingRefUpdate() {
  344. return trackingRefUpdate;
  345. }
  346. /**
  347. * Get source revision as specified by user (in constructor)
  348. *
  349. * @return source revision as specified by user (in constructor), could be
  350. * any string parseable by
  351. * {@link org.eclipse.jgit.lib.Repository#resolve(String)}; can be
  352. * null if specified that way in constructor - this stands for
  353. * delete request.
  354. */
  355. public String getSrcRef() {
  356. return srcRef;
  357. }
  358. /**
  359. * Whether user specified a local tracking branch for remote update
  360. *
  361. * @return true if user specified a local tracking branch for remote update;
  362. * false otherwise.
  363. */
  364. public boolean hasTrackingRefUpdate() {
  365. return trackingRefUpdate != null;
  366. }
  367. /**
  368. * Whether this update is forced regardless of old remote ref object
  369. *
  370. * @return true if this update is forced regardless of old remote ref
  371. * object; false otherwise.
  372. */
  373. public boolean isForceUpdate() {
  374. return forceUpdate;
  375. }
  376. /**
  377. * Get status of remote ref update operation.
  378. *
  379. * @return status of remote ref update operation.
  380. */
  381. public Status getStatus() {
  382. return status;
  383. }
  384. /**
  385. * Check whether update was fast-forward. Note that this result is
  386. * meaningful only after successful update (when status is
  387. * {@link org.eclipse.jgit.transport.RemoteRefUpdate.Status#OK}).
  388. *
  389. * @return true if update was fast-forward; false otherwise.
  390. */
  391. public boolean isFastForward() {
  392. return fastForward;
  393. }
  394. /**
  395. * Get message describing reasons of status when needed/possible; may be
  396. * null.
  397. *
  398. * @return message describing reasons of status when needed/possible; may be
  399. * null.
  400. */
  401. public String getMessage() {
  402. return message;
  403. }
  404. void setExpectedOldObjectId(ObjectId id) {
  405. expectedOldObjectId = id;
  406. }
  407. void setStatus(Status status) {
  408. this.status = status;
  409. }
  410. void setFastForward(boolean fastForward) {
  411. this.fastForward = fastForward;
  412. }
  413. void setMessage(String message) {
  414. this.message = message;
  415. }
  416. /**
  417. * Update locally stored tracking branch with the new object.
  418. *
  419. * @param walk
  420. * walker used for checking update properties.
  421. * @throws java.io.IOException
  422. * when I/O error occurred during update
  423. */
  424. protected void updateTrackingRef(RevWalk walk) throws IOException {
  425. if (isDelete())
  426. trackingRefUpdate.setResult(localUpdate.delete(walk));
  427. else
  428. trackingRefUpdate.setResult(localUpdate.update(walk));
  429. }
  430. /** {@inheritDoc} */
  431. @SuppressWarnings("nls")
  432. @Override
  433. public String toString() {
  434. return "RemoteRefUpdate[remoteName="
  435. + remoteName
  436. + ", "
  437. + status
  438. + ", "
  439. + (expectedOldObjectId != null ? expectedOldObjectId.name()
  440. : "(null)") + "..."
  441. + (newObjectId != null ? newObjectId.name() : "(null)")
  442. + (fastForward ? ", fastForward" : "")
  443. + ", srcRef=" + srcRef
  444. + (forceUpdate ? ", forceUpdate" : "") + ", message="
  445. + (message != null ? "\"" + message + "\"" : "null") + "]";
  446. }
  447. }