diff options
Diffstat (limited to 'org.eclipse.jgit/src/org')
9 files changed, 243 insertions, 6 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java index 0a49f78069..bd4521b517 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java @@ -96,6 +96,8 @@ public class PushCommand extends private OutputStream out; + private List<String> pushOptions; + /** * @param repo */ @@ -149,6 +151,7 @@ public class PushCommand extends if (receivePack != null) transport.setOptionReceivePack(receivePack); transport.setDryRun(dryRun); + transport.setPushOptions(pushOptions); configure(transport); final Collection<RemoteRefUpdate> toPush = transport @@ -189,7 +192,6 @@ public class PushCommand extends } return pushResults; - } /** @@ -453,4 +455,24 @@ public class PushCommand extends this.out = out; return this; } + + /** + * @return the option strings associated with the push operation + * @since 4.5 + */ + public List<String> getPushOptions() { + return pushOptions; + } + + /** + * Sets the option strings associated with the push operation. + * + * @param pushOptions + * @return {@code this} + * @since 4.5 + */ + public PushCommand setPushOptions(List<String> pushOptions) { + this.pushOptions = pushOptions; + return this; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index b7ef0854c9..313512f990 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -557,6 +557,7 @@ public class JGitText extends TranslationBundle { /***/ public String pushCertificateInvalidSignature; /***/ public String pushIsNotSupportedForBundleTransport; /***/ public String pushNotPermitted; + /***/ public String pushOptionsNotSupported; /***/ public String rawLogMessageDoesNotParseAsLogEntry; /***/ public String readingObjectsFromLocalRepositoryFailed; /***/ public String readTimedOut; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java index 266ca7b060..8550ec3a3f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchRefUpdate.java @@ -92,6 +92,9 @@ public class BatchRefUpdate { /** Whether updates should be atomic. */ private boolean atomic; + /** Push options associated with this update. */ + private List<String> pushOptions; + /** * Initialize a new batch update. * @@ -301,27 +304,40 @@ public class BatchRefUpdate { } /** + * Gets the list of option strings associated with this update. + * + * @return pushOptions + * @since 4.5 + */ + public List<String> getPushOptions() { + return pushOptions; + } + + /** * Execute this batch update. * <p> * The default implementation of this method performs a sequential reference * update over each reference. * <p> * Implementations must respect the atomicity requirements of the underlying - * database as described in {@link #setAtomic(boolean)} and {@link - * RefDatabase#performsAtomicTransactions()}. + * database as described in {@link #setAtomic(boolean)} and + * {@link RefDatabase#performsAtomicTransactions()}. * * @param walk * a RevWalk to parse tags in case the storage system wants to * store them pre-peeled, a common performance optimization. * @param monitor * progress monitor to receive update status on. + * @param options + * a list of option strings; set null to execute without * @throws IOException * the database is unable to accept the update. Individual * command status must be tested to determine if there is a * partial failure, or a total failure. + * @since 4.5 */ - public void execute(RevWalk walk, ProgressMonitor monitor) - throws IOException { + public void execute(RevWalk walk, ProgressMonitor monitor, + List<String> options) throws IOException { if (atomic && !refdb.performsAtomicTransactions()) { for (ReceiveCommand c : commands) { @@ -333,6 +349,10 @@ public class BatchRefUpdate { return; } + if (options != null) { + pushOptions = options; + } + monitor.beginTask(JGitText.get().updatingReferences, commands.size()); List<ReceiveCommand> commands2 = new ArrayList<ReceiveCommand>( commands.size()); @@ -412,6 +432,24 @@ public class BatchRefUpdate { monitor.endTask(); } + /** + * Execute this batch update without option strings. + * + * @param walk + * a RevWalk to parse tags in case the storage system wants to + * store them pre-peeled, a common performance optimization. + * @param monitor + * progress monitor to receive update status on. + * @throws IOException + * the database is unable to accept the update. Individual + * command status must be tested to determine if there is a + * partial failure, or a total failure. + */ + public void execute(RevWalk walk, ProgressMonitor monitor) + throws IOException { + execute(walk, monitor, null); + } + private static Collection<String> getTakenPrefixes( final Collection<String> names) { Collection<String> ref = new HashSet<String>(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java index 0cbbdc77e3..86cc484e34 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java @@ -52,6 +52,7 @@ import java.io.OutputStream; import java.text.MessageFormat; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; @@ -113,14 +114,24 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen */ public static final String CAPABILITY_SIDE_BAND_64K = GitProtocolConstants.CAPABILITY_SIDE_BAND_64K; + /** + * The server supports the receiving of push options. + * @since 4.5 + */ + public static final String CAPABILITY_PUSH_OPTIONS = GitProtocolConstants.CAPABILITY_PUSH_OPTIONS; + private final boolean thinPack; private final boolean atomic; + /** A list of option strings associated with this push. */ + private List<String> pushOptions; + private boolean capableAtomic; private boolean capableDeleteRefs; private boolean capableReport; private boolean capableSideBand; private boolean capableOfsDelta; + private boolean capablePushOptions; private boolean sentCommand; private boolean writePack; @@ -138,6 +149,7 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen super(packTransport); thinPack = transport.isPushThin(); atomic = transport.isPushAtomic(); + pushOptions = transport.getPushOptions(); } public void push(final ProgressMonitor monitor, @@ -197,6 +209,9 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen OutputStream outputStream) throws TransportException { try { writeCommands(refUpdates.values(), monitor, outputStream); + + if (pushOptions != null && capablePushOptions) + transmitOptions(); if (writePack) writePack(refUpdates, monitor); if (sentCommand) { @@ -232,6 +247,12 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen JGitText.get().atomicPushNotSupported); } + if (pushOptions != null && !capablePushOptions) { + throw new TransportException(uri, + MessageFormat.format(JGitText.get().pushOptionsNotSupported, + pushOptions.toString())); + } + for (final RemoteRefUpdate rru : refUpdates) { if (!capableDeleteRefs && rru.isDelete()) { rru.setStatus(Status.REJECTED_NODELETE); @@ -269,6 +290,14 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen outNeedsEnd = false; } + private void transmitOptions() throws IOException { + for (final String pushOption : pushOptions) { + pckOut.writeString(pushOption); + } + + pckOut.end(); + } + private String enableCapabilities(final ProgressMonitor monitor, OutputStream outputStream) { final StringBuilder line = new StringBuilder(); @@ -278,6 +307,10 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen capableDeleteRefs = wantCapability(line, CAPABILITY_DELETE_REFS); capableOfsDelta = wantCapability(line, CAPABILITY_OFS_DELTA); + if (pushOptions != null) { + capablePushOptions = wantCapability(line, CAPABILITY_PUSH_OPTIONS); + } + capableSideBand = wantCapability(line, CAPABILITY_SIDE_BAND_64K); if (capableSideBand) { in = new SideBandInputStream(in, monitor, getMessageWriter(), @@ -333,7 +366,8 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen throws IOException { final String unpackLine = readStringLongTimeout(); if (!unpackLine.startsWith("unpack ")) //$NON-NLS-1$ - throw new PackProtocolException(uri, MessageFormat.format(JGitText.get().unexpectedReportLine, unpackLine)); + throw new PackProtocolException(uri, MessageFormat + .format(JGitText.get().unexpectedReportLine, unpackLine)); final String unpackStatus = unpackLine.substring("unpack ".length()); //$NON-NLS-1$ if (unpackStatus.startsWith("error Pack exceeds the limit of")) {//$NON-NLS-1$ throw new TooLargePackException(uri, @@ -404,6 +438,16 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen } } + /** + * Gets the list of option strings associated with this push. + * + * @return pushOptions + * @since 4.5 + */ + public List<String> getPushOptions() { + return pushOptions; + } + private static class CheckingSideBandOutputStream extends OutputStream { private final InputStream in; private final OutputStream out; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java index aae4bd9c3c..b9923b95e2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java @@ -48,6 +48,7 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_ import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_QUIET; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS; +import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS; import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K; import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT; import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA; @@ -178,6 +179,9 @@ public abstract class BaseReceivePack { /** Should an incoming transfer permit non-fast-forward requests? */ private boolean allowNonFastForwards; + /** Should an incoming transfer permit push options? **/ + private boolean allowPushOptions; + /** * Should the requested ref updates be performed as a single atomic * transaction? @@ -247,6 +251,18 @@ public abstract class BaseReceivePack { private boolean quiet; + /** + * A list of option strings associated with a push. + * @since 4.5 + */ + protected List<String> pushOptions; + + /** + * Whether the client intends to use push options. + * @since 4.5 + */ + protected boolean usePushOptions; + /** Lock around the received pack file, while updating refs. */ private PackLock packLock; @@ -311,6 +327,7 @@ public abstract class BaseReceivePack { allowBranchDeletes = rc.allowDeletes; allowNonFastForwards = rc.allowNonFastForwards; allowOfsDelta = rc.allowOfsDelta; + allowPushOptions = rc.allowPushOptions; advertiseRefsHook = AdvertiseRefsHook.DEFAULT; refFilter = RefFilter.DEFAULT; advertisedHaves = new HashSet<ObjectId>(); @@ -330,6 +347,8 @@ public abstract class BaseReceivePack { final boolean allowDeletes; final boolean allowNonFastForwards; final boolean allowOfsDelta; + final boolean allowPushOptions; + final SignedPushConfig signedPush; ReceiveConfig(final Config config) { @@ -339,6 +358,8 @@ public abstract class BaseReceivePack { "denynonfastforwards", false); //$NON-NLS-1$ allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$ true); + allowPushOptions = config.getBoolean("receive", "pushoptions", //$NON-NLS-1$ //$NON-NLS-2$ + false); signedPush = SignedPushConfig.KEY.parse(config); } } @@ -788,6 +809,25 @@ public abstract class BaseReceivePack { } /** + * @return true if the server supports the receiving of push options. + * @since 4.5 + */ + public boolean isAllowPushOptions() { + return allowPushOptions; + } + + /** + * Configure if the server supports the receiving of push options. + * + * @param allow + * true to permit option strings. + * @since 4.5 + */ + public void setAllowPushOptions(boolean allow) { + allowPushOptions = allow; + } + + /** * True if the client wants less verbose output. * * @return true if the client has requested the server to be less verbose. @@ -805,6 +845,24 @@ public abstract class BaseReceivePack { } /** + * Gets the list of string options associated with this push. + * + * @return pushOptions + * @throws RequestNotYetReadException + * if the client's request has not yet been read from the wire, + * so we do not know if they expect push options. Note that the + * client may have already written the request, it just has not + * been read. + * @since 4.5 + */ + public List<String> getPushOptions() throws RequestNotYetReadException { + if (enabledCapabilities == null) { + throw new RequestNotYetReadException(); + } + return Collections.unmodifiableList(pushOptions); + } + + /** * Set the configuration for push certificate verification. * * @param cfg @@ -1076,6 +1134,10 @@ public abstract class BaseReceivePack { adv.advertiseCapability(CAPABILITY_ATOMIC); if (allowOfsDelta) adv.advertiseCapability(CAPABILITY_OFS_DELTA); + if (allowPushOptions) { + adv.advertiseCapability(CAPABILITY_PUSH_OPTIONS); + pushOptions = new ArrayList<>(); + } adv.advertiseCapability(OPTION_AGENT, UserAgent.get()); adv.send(getAdvertisedOrDefaultRefs()); for (ObjectId obj : advertisedHaves) @@ -1192,6 +1254,8 @@ public abstract class BaseReceivePack { protected void enableCapabilities() { sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K); quiet = allowQuiet && isCapabilityEnabled(CAPABILITY_QUIET); + usePushOptions = allowPushOptions + && isCapabilityEnabled(CAPABILITY_PUSH_OPTIONS); if (sideBand) { OutputStream out = rawOut; @@ -1205,6 +1269,17 @@ public abstract class BaseReceivePack { } /** + * Sets the client's intention regarding push options. + * + * @param usePushOptions + * whether the client intends to use push options + * @since 4.5 + */ + public void setUsePushOptions(boolean usePushOptions) { + this.usePushOptions = usePushOptions; + } + + /** * Check if the peer requested a capability. * * @param name diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java index efde062621..2031147820 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java @@ -208,6 +208,13 @@ public class GitProtocolConstants { */ public static final String OPTION_AGENT = "agent"; //$NON-NLS-1$ + /** + * The server supports the receiving of push options. + * + * @since 4.5 + */ + public static final String CAPABILITY_PUSH_OPTIONS = "push-options"; //$NON-NLS-1$ + static enum MultiAck { OFF, CONTINUE, DETAILED; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java index 5cea88215a..5590c2d256 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java @@ -49,6 +49,7 @@ import java.text.MessageFormat; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.eclipse.jgit.errors.MissingObjectException; @@ -87,6 +88,9 @@ class PushProcess { /** an outputstream to write messages to */ private final OutputStream out; + /** A list of option strings associated with this push */ + private List<String> pushOptions; + /** * Create process for specified transport and refs updates specification. * @@ -122,6 +126,7 @@ class PushProcess { this.transport = transport; this.toPush = new HashMap<String, RemoteRefUpdate>(); this.out = out; + this.pushOptions = transport.getPushOptions(); for (final RemoteRefUpdate rru : toPush) { if (this.toPush.put(rru.getRemoteName(), rru) != null) throw new TransportException(MessageFormat.format( @@ -294,4 +299,14 @@ class PushProcess { } } } + + /** + * Gets the list of option strings associated with this push. + * + * @return pushOptions + * @since 4.5 + */ + public List<String> getPushOptions() { + return pushOptions; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java index 2477806bd9..d16b723ff8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java @@ -174,6 +174,15 @@ public class ReceivePack extends BaseReceivePack { super.enableCapabilities(); } + private void readPushOptions() throws IOException { + String pushOption = pckIn.readString(); + + while (pushOption != PacketLineIn.END) { + pushOptions.add(pushOption); + pushOption = pckIn.readString(); + } + } + private void service() throws IOException { if (isBiDirectionalPipe()) { sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut)); @@ -184,6 +193,10 @@ public class ReceivePack extends BaseReceivePack { return; recvCommands(); if (hasCommands()) { + if (usePushOptions) { + readPushOptions(); + } + Throwable unpackError = null; if (needPack()) { try { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java index 862b3bdeb0..bc4843a8af 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java @@ -773,6 +773,9 @@ public abstract class Transport implements AutoCloseable { /** Assists with authentication the connection. */ private CredentialsProvider credentialsProvider; + /** The option strings associated with the push operation. */ + private List<String> pushOptions; + private PrintStream hookOutRedirect; private PrePushHook prePush; @@ -1121,6 +1124,25 @@ public abstract class Transport implements AutoCloseable { } /** + * @return the option strings associated with the push operation + * @since 4.5 + */ + public List<String> getPushOptions() { + return pushOptions; + } + + /** + * Sets the option strings associated with the push operation. + * + * @param pushOptions + * null if push options are unsupported + * @since 4.5 + */ + public void setPushOptions(final List<String> pushOptions) { + this.pushOptions = pushOptions; + } + + /** * Fetch objects and refs from the remote repository to the local one. * <p> * This is a utility function providing standard fetch behavior. Local |