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.

ReceiveCommand.java 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. /*
  2. * Copyright (C) 2008, Google Inc. 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 static org.eclipse.jgit.transport.ReceiveCommand.Result.NOT_ATTEMPTED;
  12. import static org.eclipse.jgit.transport.ReceiveCommand.Result.REJECTED_OTHER_REASON;
  13. import java.io.IOException;
  14. import java.text.MessageFormat;
  15. import java.util.ArrayList;
  16. import java.util.Collection;
  17. import java.util.List;
  18. import org.eclipse.jgit.annotations.NonNull;
  19. import org.eclipse.jgit.annotations.Nullable;
  20. import org.eclipse.jgit.internal.JGitText;
  21. import org.eclipse.jgit.lib.AnyObjectId;
  22. import org.eclipse.jgit.lib.ObjectId;
  23. import org.eclipse.jgit.lib.Ref;
  24. import org.eclipse.jgit.lib.RefUpdate;
  25. import org.eclipse.jgit.revwalk.RevCommit;
  26. import org.eclipse.jgit.revwalk.RevObject;
  27. import org.eclipse.jgit.revwalk.RevWalk;
  28. /**
  29. * A command being processed by
  30. * {@link org.eclipse.jgit.transport.ReceivePack}.
  31. * <p>
  32. * This command instance roughly translates to the server side representation of
  33. * the {@link org.eclipse.jgit.transport.RemoteRefUpdate} created by the client.
  34. */
  35. public class ReceiveCommand {
  36. /** Type of operation requested. */
  37. public enum Type {
  38. /** Create a new ref; the ref must not already exist. */
  39. CREATE,
  40. /**
  41. * Update an existing ref with a fast-forward update.
  42. * <p>
  43. * During a fast-forward update no changes will be lost; only new
  44. * commits are inserted into the ref.
  45. */
  46. UPDATE,
  47. /**
  48. * Update an existing ref by potentially discarding objects.
  49. * <p>
  50. * The current value of the ref is not fully reachable from the new
  51. * value of the ref, so a successful command may result in one or more
  52. * objects becoming unreachable.
  53. */
  54. UPDATE_NONFASTFORWARD,
  55. /** Delete an existing ref; the ref should already exist. */
  56. DELETE;
  57. }
  58. /** Result of the update command. */
  59. public enum Result {
  60. /** The command has not yet been attempted by the server. */
  61. NOT_ATTEMPTED,
  62. /** The server is configured to deny creation of this ref. */
  63. REJECTED_NOCREATE,
  64. /** The server is configured to deny deletion of this ref. */
  65. REJECTED_NODELETE,
  66. /** The update is a non-fast-forward update and isn't permitted. */
  67. REJECTED_NONFASTFORWARD,
  68. /** The update affects <code>HEAD</code> and cannot be permitted. */
  69. REJECTED_CURRENT_BRANCH,
  70. /**
  71. * One or more objects aren't in the repository.
  72. * <p>
  73. * This is severe indication of either repository corruption on the
  74. * server side, or a bug in the client wherein the client did not supply
  75. * all required objects during the pack transfer.
  76. */
  77. REJECTED_MISSING_OBJECT,
  78. /** Other failure; see {@link ReceiveCommand#getMessage()}. */
  79. REJECTED_OTHER_REASON,
  80. /** The ref could not be locked and updated atomically; try again. */
  81. LOCK_FAILURE,
  82. /** The change was completed successfully. */
  83. OK;
  84. }
  85. /**
  86. * Filter a collection of commands according to result.
  87. *
  88. * @param in
  89. * commands to filter.
  90. * @param want
  91. * desired status to filter by.
  92. * @return a copy of the command list containing only those commands with
  93. * the desired status.
  94. * @since 4.2
  95. */
  96. public static List<ReceiveCommand> filter(Iterable<ReceiveCommand> in,
  97. Result want) {
  98. List<ReceiveCommand> r;
  99. if (in instanceof Collection)
  100. r = new ArrayList<>(((Collection<?>) in).size());
  101. else
  102. r = new ArrayList<>();
  103. for (ReceiveCommand cmd : in) {
  104. if (cmd.getResult() == want)
  105. r.add(cmd);
  106. }
  107. return r;
  108. }
  109. /**
  110. * Filter a list of commands according to result.
  111. *
  112. * @param commands
  113. * commands to filter.
  114. * @param want
  115. * desired status to filter by.
  116. * @return a copy of the command list containing only those commands with
  117. * the desired status.
  118. * @since 2.0
  119. */
  120. public static List<ReceiveCommand> filter(List<ReceiveCommand> commands,
  121. Result want) {
  122. return filter((Iterable<ReceiveCommand>) commands, want);
  123. }
  124. /**
  125. * Set unprocessed commands as failed due to transaction aborted.
  126. * <p>
  127. * If a command is still
  128. * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#NOT_ATTEMPTED} it
  129. * will be set to
  130. * {@link org.eclipse.jgit.transport.ReceiveCommand.Result#REJECTED_OTHER_REASON}.
  131. *
  132. * @param commands
  133. * commands to mark as failed.
  134. * @since 4.2
  135. */
  136. public static void abort(Iterable<ReceiveCommand> commands) {
  137. for (ReceiveCommand c : commands) {
  138. if (c.getResult() == NOT_ATTEMPTED) {
  139. c.setResult(REJECTED_OTHER_REASON,
  140. JGitText.get().transactionAborted);
  141. }
  142. }
  143. }
  144. /**
  145. * Check whether a command failed due to transaction aborted.
  146. *
  147. * @param cmd
  148. * command.
  149. * @return whether the command failed due to transaction aborted, as in
  150. * {@link #abort(Iterable)}.
  151. * @since 4.9
  152. */
  153. public static boolean isTransactionAborted(ReceiveCommand cmd) {
  154. return cmd.getResult() == REJECTED_OTHER_REASON
  155. && cmd.getMessage().equals(JGitText.get().transactionAborted);
  156. }
  157. /**
  158. * Create a command to switch a reference from object to symbolic.
  159. *
  160. * @param oldId
  161. * expected oldId. May be {@code zeroId} to create.
  162. * @param newTarget
  163. * new target; must begin with {@code "refs/"}.
  164. * @param name
  165. * name of the reference to make symbolic.
  166. * @return command instance.
  167. * @since 4.10
  168. */
  169. public static ReceiveCommand link(@NonNull ObjectId oldId,
  170. @NonNull String newTarget, @NonNull String name) {
  171. return new ReceiveCommand(oldId, newTarget, name);
  172. }
  173. /**
  174. * Create a command to switch a symbolic reference's target.
  175. *
  176. * @param oldTarget
  177. * expected old target. May be null to create.
  178. * @param newTarget
  179. * new target; must begin with {@code "refs/"}.
  180. * @param name
  181. * name of the reference to make symbolic.
  182. * @return command instance.
  183. * @since 4.10
  184. */
  185. public static ReceiveCommand link(@Nullable String oldTarget,
  186. @NonNull String newTarget, @NonNull String name) {
  187. return new ReceiveCommand(oldTarget, newTarget, name);
  188. }
  189. /**
  190. * Create a command to switch a reference from symbolic to object.
  191. *
  192. * @param oldTarget
  193. * expected old target.
  194. * @param newId
  195. * new object identifier. May be {@code zeroId()} to delete.
  196. * @param name
  197. * name of the reference to convert from symbolic.
  198. * @return command instance.
  199. * @since 4.10
  200. */
  201. public static ReceiveCommand unlink(@NonNull String oldTarget,
  202. @NonNull ObjectId newId, @NonNull String name) {
  203. return new ReceiveCommand(oldTarget, newId, name);
  204. }
  205. private final ObjectId oldId;
  206. private final String oldSymref;
  207. private final ObjectId newId;
  208. private final String newSymref;
  209. private final String name;
  210. private Type type;
  211. private boolean typeIsCorrect;
  212. private Ref ref;
  213. private Result status = Result.NOT_ATTEMPTED;
  214. private String message;
  215. private boolean customRefLog;
  216. private String refLogMessage;
  217. private boolean refLogIncludeResult;
  218. private Boolean forceRefLog;
  219. /**
  220. * Create a new command for
  221. * {@link org.eclipse.jgit.transport.ReceivePack}.
  222. *
  223. * @param oldId
  224. * the expected old object id; must not be null. Use
  225. * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
  226. * ref creation.
  227. * @param newId
  228. * the new object id; must not be null. Use
  229. * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
  230. * ref deletion.
  231. * @param name
  232. * name of the ref being affected.
  233. */
  234. public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
  235. final String name) {
  236. if (oldId == null) {
  237. throw new IllegalArgumentException(
  238. JGitText.get().oldIdMustNotBeNull);
  239. }
  240. if (newId == null) {
  241. throw new IllegalArgumentException(
  242. JGitText.get().newIdMustNotBeNull);
  243. }
  244. if (name == null || name.isEmpty()) {
  245. throw new IllegalArgumentException(
  246. JGitText.get().nameMustNotBeNullOrEmpty);
  247. }
  248. this.oldId = oldId;
  249. this.oldSymref = null;
  250. this.newId = newId;
  251. this.newSymref = null;
  252. this.name = name;
  253. type = Type.UPDATE;
  254. if (ObjectId.zeroId().equals(oldId)) {
  255. type = Type.CREATE;
  256. }
  257. if (ObjectId.zeroId().equals(newId)) {
  258. type = Type.DELETE;
  259. }
  260. }
  261. /**
  262. * Create a new command for
  263. * {@link org.eclipse.jgit.transport.ReceivePack}.
  264. *
  265. * @param oldId
  266. * the old object id; must not be null. Use
  267. * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
  268. * ref creation.
  269. * @param newId
  270. * the new object id; must not be null. Use
  271. * {@link org.eclipse.jgit.lib.ObjectId#zeroId()} to indicate a
  272. * ref deletion.
  273. * @param name
  274. * name of the ref being affected.
  275. * @param type
  276. * type of the command. Must be
  277. * {@link org.eclipse.jgit.transport.ReceiveCommand.Type#CREATE}
  278. * if {@code
  279. * oldId} is zero, or
  280. * {@link org.eclipse.jgit.transport.ReceiveCommand.Type#DELETE}
  281. * if {@code newId} is zero.
  282. * @since 2.0
  283. */
  284. public ReceiveCommand(final ObjectId oldId, final ObjectId newId,
  285. final String name, final Type type) {
  286. if (oldId == null) {
  287. throw new IllegalArgumentException(
  288. JGitText.get().oldIdMustNotBeNull);
  289. }
  290. if (newId == null) {
  291. throw new IllegalArgumentException(
  292. JGitText.get().newIdMustNotBeNull);
  293. }
  294. if (name == null || name.isEmpty()) {
  295. throw new IllegalArgumentException(
  296. JGitText.get().nameMustNotBeNullOrEmpty);
  297. }
  298. this.oldId = oldId;
  299. this.oldSymref = null;
  300. this.newId = newId;
  301. this.newSymref = null;
  302. this.name = name;
  303. switch (type) {
  304. case CREATE:
  305. if (!ObjectId.zeroId().equals(oldId)) {
  306. throw new IllegalArgumentException(
  307. JGitText.get().createRequiresZeroOldId);
  308. }
  309. break;
  310. case DELETE:
  311. if (!ObjectId.zeroId().equals(newId)) {
  312. throw new IllegalArgumentException(
  313. JGitText.get().deleteRequiresZeroNewId);
  314. }
  315. break;
  316. case UPDATE:
  317. case UPDATE_NONFASTFORWARD:
  318. if (ObjectId.zeroId().equals(newId)
  319. || ObjectId.zeroId().equals(oldId)) {
  320. throw new IllegalArgumentException(
  321. JGitText.get().updateRequiresOldIdAndNewId);
  322. }
  323. break;
  324. default:
  325. throw new IllegalStateException(
  326. JGitText.get().enumValueNotSupported0);
  327. }
  328. this.type = type;
  329. }
  330. /**
  331. * Create a command to switch a reference from object to symbolic.
  332. *
  333. * @param oldId
  334. * the old object id; must not be null. Use
  335. * {@link ObjectId#zeroId()} to indicate a ref creation.
  336. * @param newSymref
  337. * new target, must begin with {@code "refs/"}. Use {@code null}
  338. * to indicate a ref deletion.
  339. * @param name
  340. * name of the reference to make symbolic.
  341. * @since 4.10
  342. */
  343. private ReceiveCommand(ObjectId oldId, String newSymref, String name) {
  344. if (oldId == null) {
  345. throw new IllegalArgumentException(
  346. JGitText.get().oldIdMustNotBeNull);
  347. }
  348. if (name == null || name.isEmpty()) {
  349. throw new IllegalArgumentException(
  350. JGitText.get().nameMustNotBeNullOrEmpty);
  351. }
  352. this.oldId = oldId;
  353. this.oldSymref = null;
  354. this.newId = ObjectId.zeroId();
  355. this.newSymref = newSymref;
  356. this.name = name;
  357. if (AnyObjectId.isEqual(ObjectId.zeroId(), oldId)) {
  358. type = Type.CREATE;
  359. } else if (newSymref != null) {
  360. type = Type.UPDATE;
  361. } else {
  362. type = Type.DELETE;
  363. }
  364. typeIsCorrect = true;
  365. }
  366. /**
  367. * Create a command to switch a reference from symbolic to object.
  368. *
  369. * @param oldSymref
  370. * expected old target. Use {@code null} to indicate a ref
  371. * creation.
  372. * @param newId
  373. * the new object id; must not be null. Use
  374. * {@link ObjectId#zeroId()} to indicate a ref deletion.
  375. * @param name
  376. * name of the reference to convert from symbolic.
  377. * @since 4.10
  378. */
  379. private ReceiveCommand(String oldSymref, ObjectId newId, String name) {
  380. if (newId == null) {
  381. throw new IllegalArgumentException(
  382. JGitText.get().newIdMustNotBeNull);
  383. }
  384. if (name == null || name.isEmpty()) {
  385. throw new IllegalArgumentException(
  386. JGitText.get().nameMustNotBeNullOrEmpty);
  387. }
  388. this.oldId = ObjectId.zeroId();
  389. this.oldSymref = oldSymref;
  390. this.newId = newId;
  391. this.newSymref = null;
  392. this.name = name;
  393. if (oldSymref == null) {
  394. type = Type.CREATE;
  395. } else if (!AnyObjectId.isEqual(ObjectId.zeroId(), newId)) {
  396. type = Type.UPDATE;
  397. } else {
  398. type = Type.DELETE;
  399. }
  400. typeIsCorrect = true;
  401. }
  402. /**
  403. * Create a command to switch a symbolic reference's target.
  404. *
  405. * @param oldTarget
  406. * expected old target. Use {@code null} to indicate a ref
  407. * creation.
  408. * @param newTarget
  409. * new target. Use {@code null} to indicate a ref deletion.
  410. * @param name
  411. * name of the reference to make symbolic.
  412. * @since 4.10
  413. */
  414. private ReceiveCommand(@Nullable String oldTarget, String newTarget, String name) {
  415. if (name == null || name.isEmpty()) {
  416. throw new IllegalArgumentException(
  417. JGitText.get().nameMustNotBeNullOrEmpty);
  418. }
  419. this.oldId = ObjectId.zeroId();
  420. this.oldSymref = oldTarget;
  421. this.newId = ObjectId.zeroId();
  422. this.newSymref = newTarget;
  423. this.name = name;
  424. if (oldTarget == null) {
  425. if (newTarget == null) {
  426. throw new IllegalArgumentException(
  427. JGitText.get().bothRefTargetsMustNotBeNull);
  428. }
  429. type = Type.CREATE;
  430. } else if (newTarget != null) {
  431. type = Type.UPDATE;
  432. } else {
  433. type = Type.DELETE;
  434. }
  435. typeIsCorrect = true;
  436. }
  437. /**
  438. * Get the old value the client thinks the ref has.
  439. *
  440. * @return the old value the client thinks the ref has.
  441. */
  442. public ObjectId getOldId() {
  443. return oldId;
  444. }
  445. /**
  446. * Get expected old target for a symbolic reference.
  447. *
  448. * @return expected old target for a symbolic reference.
  449. * @since 4.10
  450. */
  451. @Nullable
  452. public String getOldSymref() {
  453. return oldSymref;
  454. }
  455. /**
  456. * Get the requested new value for this ref.
  457. *
  458. * @return the requested new value for this ref.
  459. */
  460. public ObjectId getNewId() {
  461. return newId;
  462. }
  463. /**
  464. * Get requested new target for a symbolic reference.
  465. *
  466. * @return requested new target for a symbolic reference.
  467. * @since 4.10
  468. */
  469. @Nullable
  470. public String getNewSymref() {
  471. return newSymref;
  472. }
  473. /**
  474. * Get the name of the ref being updated.
  475. *
  476. * @return the name of the ref being updated.
  477. */
  478. public String getRefName() {
  479. return name;
  480. }
  481. /**
  482. * Get the type of this command; see {@link Type}.
  483. *
  484. * @return the type of this command; see {@link Type}.
  485. */
  486. public Type getType() {
  487. return type;
  488. }
  489. /**
  490. * Get the ref, if this was advertised by the connection.
  491. *
  492. * @return the ref, if this was advertised by the connection.
  493. */
  494. public Ref getRef() {
  495. return ref;
  496. }
  497. /**
  498. * Get the current status code of this command.
  499. *
  500. * @return the current status code of this command.
  501. */
  502. public Result getResult() {
  503. return status;
  504. }
  505. /**
  506. * Get the message associated with a failure status.
  507. *
  508. * @return the message associated with a failure status.
  509. */
  510. public String getMessage() {
  511. return message;
  512. }
  513. /**
  514. * Set the message to include in the reflog.
  515. * <p>
  516. * Overrides the default set by {@code setRefLogMessage} on any containing
  517. * {@link org.eclipse.jgit.lib.BatchRefUpdate}.
  518. *
  519. * @param msg
  520. * the message to describe this change. If null and appendStatus is
  521. * false, the reflog will not be updated.
  522. * @param appendStatus
  523. * true if the status of the ref change (fast-forward or
  524. * forced-update) should be appended to the user supplied message.
  525. * @since 4.9
  526. */
  527. public void setRefLogMessage(String msg, boolean appendStatus) {
  528. customRefLog = true;
  529. if (msg == null && !appendStatus) {
  530. disableRefLog();
  531. } else if (msg == null && appendStatus) {
  532. refLogMessage = ""; //$NON-NLS-1$
  533. refLogIncludeResult = true;
  534. } else {
  535. refLogMessage = msg;
  536. refLogIncludeResult = appendStatus;
  537. }
  538. }
  539. /**
  540. * Don't record this update in the ref's associated reflog.
  541. * <p>
  542. * Equivalent to {@code setRefLogMessage(null, false)}.
  543. *
  544. * @since 4.9
  545. */
  546. public void disableRefLog() {
  547. customRefLog = true;
  548. refLogMessage = null;
  549. refLogIncludeResult = false;
  550. }
  551. /**
  552. * Force writing a reflog for the updated ref.
  553. *
  554. * @param force whether to force.
  555. * @since 4.9
  556. */
  557. public void setForceRefLog(boolean force) {
  558. forceRefLog = Boolean.valueOf(force);
  559. }
  560. /**
  561. * Check whether this command has a custom reflog message setting that should
  562. * override defaults in any containing
  563. * {@link org.eclipse.jgit.lib.BatchRefUpdate}.
  564. * <p>
  565. * Does not take into account whether {@code #setForceRefLog(boolean)} has
  566. * been called.
  567. *
  568. * @return whether a custom reflog is set.
  569. * @since 4.9
  570. */
  571. public boolean hasCustomRefLog() {
  572. return customRefLog;
  573. }
  574. /**
  575. * Check whether log has been disabled by {@link #disableRefLog()}.
  576. *
  577. * @return true if disabled.
  578. * @since 4.9
  579. */
  580. public boolean isRefLogDisabled() {
  581. return refLogMessage == null;
  582. }
  583. /**
  584. * Get the message to include in the reflog.
  585. *
  586. * @return message the caller wants to include in the reflog; null if the
  587. * update should not be logged.
  588. * @since 4.9
  589. */
  590. @Nullable
  591. public String getRefLogMessage() {
  592. return refLogMessage;
  593. }
  594. /**
  595. * Check whether the reflog message should include the result of the update,
  596. * such as fast-forward or force-update.
  597. *
  598. * @return true if the message should include the result.
  599. * @since 4.9
  600. */
  601. public boolean isRefLogIncludingResult() {
  602. return refLogIncludeResult;
  603. }
  604. /**
  605. * Check whether the reflog should be written regardless of repo defaults.
  606. *
  607. * @return whether force writing is enabled; {@code null} if
  608. * {@code #setForceRefLog(boolean)} was never called.
  609. * @since 4.9
  610. */
  611. @Nullable
  612. public Boolean isForceRefLog() {
  613. return forceRefLog;
  614. }
  615. /**
  616. * Set the status of this command.
  617. *
  618. * @param s
  619. * the new status code for this command.
  620. */
  621. public void setResult(Result s) {
  622. setResult(s, null);
  623. }
  624. /**
  625. * Set the status of this command.
  626. *
  627. * @param s
  628. * new status code for this command.
  629. * @param m
  630. * optional message explaining the new status.
  631. */
  632. public void setResult(Result s, String m) {
  633. status = s;
  634. message = m;
  635. }
  636. /**
  637. * Update the type of this command by checking for fast-forward.
  638. * <p>
  639. * If the command's current type is UPDATE, a merge test will be performed
  640. * using the supplied RevWalk to determine if {@link #getOldId()} is fully
  641. * merged into {@link #getNewId()}. If some commits are not merged the
  642. * update type is changed to
  643. * {@link org.eclipse.jgit.transport.ReceiveCommand.Type#UPDATE_NONFASTFORWARD}.
  644. *
  645. * @param walk
  646. * an instance to perform the merge test with. The caller must
  647. * allocate and release this object.
  648. * @throws java.io.IOException
  649. * either oldId or newId is not accessible in the repository
  650. * used by the RevWalk. This usually indicates data corruption,
  651. * and the command cannot be processed.
  652. */
  653. public void updateType(RevWalk walk) throws IOException {
  654. if (typeIsCorrect)
  655. return;
  656. if (type == Type.UPDATE && !AnyObjectId.isEqual(oldId, newId)) {
  657. RevObject o = walk.parseAny(oldId);
  658. RevObject n = walk.parseAny(newId);
  659. if (!(o instanceof RevCommit)
  660. || !(n instanceof RevCommit)
  661. || !walk.isMergedInto((RevCommit) o, (RevCommit) n))
  662. setType(Type.UPDATE_NONFASTFORWARD);
  663. }
  664. typeIsCorrect = true;
  665. }
  666. /**
  667. * Execute this command during a receive-pack session.
  668. * <p>
  669. * Sets the status of the command as a side effect.
  670. *
  671. * @param rp
  672. * receive-pack session.
  673. * @since 5.6
  674. */
  675. public void execute(ReceivePack rp) {
  676. try {
  677. String expTarget = getOldSymref();
  678. boolean detach = getNewSymref() != null
  679. || (type == Type.DELETE && expTarget != null);
  680. RefUpdate ru = rp.getRepository().updateRef(getRefName(), detach);
  681. if (expTarget != null) {
  682. if (!ru.getRef().isSymbolic() || !ru.getRef().getTarget()
  683. .getName().equals(expTarget)) {
  684. setResult(Result.LOCK_FAILURE);
  685. return;
  686. }
  687. }
  688. ru.setRefLogIdent(rp.getRefLogIdent());
  689. ru.setRefLogMessage(refLogMessage, refLogIncludeResult);
  690. switch (getType()) {
  691. case DELETE:
  692. if (!ObjectId.zeroId().equals(getOldId())) {
  693. // We can only do a CAS style delete if the client
  694. // didn't bork its delete request by sending the
  695. // wrong zero id rather than the advertised one.
  696. //
  697. ru.setExpectedOldObjectId(getOldId());
  698. }
  699. ru.setForceUpdate(true);
  700. setResult(ru.delete(rp.getRevWalk()));
  701. break;
  702. case CREATE:
  703. case UPDATE:
  704. case UPDATE_NONFASTFORWARD:
  705. ru.setForceUpdate(rp.isAllowNonFastForwards());
  706. ru.setExpectedOldObjectId(getOldId());
  707. ru.setRefLogMessage("push", true); //$NON-NLS-1$
  708. if (getNewSymref() != null) {
  709. setResult(ru.link(getNewSymref()));
  710. } else {
  711. ru.setNewObjectId(getNewId());
  712. setResult(ru.update(rp.getRevWalk()));
  713. }
  714. break;
  715. }
  716. } catch (IOException err) {
  717. reject(err);
  718. }
  719. }
  720. void setRef(Ref r) {
  721. ref = r;
  722. }
  723. void setType(Type t) {
  724. type = t;
  725. }
  726. void setTypeFastForwardUpdate() {
  727. type = Type.UPDATE;
  728. typeIsCorrect = true;
  729. }
  730. /**
  731. * Set the result of this command.
  732. *
  733. * @param r
  734. * the new result code for this command.
  735. */
  736. public void setResult(RefUpdate.Result r) {
  737. switch (r) {
  738. case NOT_ATTEMPTED:
  739. setResult(Result.NOT_ATTEMPTED);
  740. break;
  741. case LOCK_FAILURE:
  742. case IO_FAILURE:
  743. setResult(Result.LOCK_FAILURE);
  744. break;
  745. case NO_CHANGE:
  746. case NEW:
  747. case FORCED:
  748. case FAST_FORWARD:
  749. setResult(Result.OK);
  750. break;
  751. case REJECTED:
  752. setResult(Result.REJECTED_NONFASTFORWARD);
  753. break;
  754. case REJECTED_CURRENT_BRANCH:
  755. setResult(Result.REJECTED_CURRENT_BRANCH);
  756. break;
  757. case REJECTED_MISSING_OBJECT:
  758. setResult(Result.REJECTED_MISSING_OBJECT);
  759. break;
  760. case REJECTED_OTHER_REASON:
  761. setResult(Result.REJECTED_OTHER_REASON);
  762. break;
  763. default:
  764. setResult(Result.REJECTED_OTHER_REASON, r.name());
  765. break;
  766. }
  767. }
  768. void reject(IOException err) {
  769. setResult(Result.REJECTED_OTHER_REASON, MessageFormat.format(
  770. JGitText.get().lockError, err.getMessage()));
  771. }
  772. /** {@inheritDoc} */
  773. @SuppressWarnings("nls")
  774. @Override
  775. public String toString() {
  776. return getType().name() + ": " + getOldId().name() + " "
  777. + getNewId().name() + " " + getRefName();
  778. }
  779. }