1 /* 2 * Copyright (C) 2008-2009, Google Inc. 3 * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com> 4 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com> 5 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> 6 * and other copyright owners as documented in the project's IP log. 7 * 8 * This program and the accompanying materials are made available 9 * under the terms of the Eclipse Distribution License v1.0 which 10 * accompanies this distribution, is reproduced below, and is 11 * available at http://www.eclipse.org/org/documents/edl-v10.php 12 * 13 * All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or 16 * without modification, are permitted provided that the following 17 * conditions are met: 18 * 19 * - Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 22 * - Redistributions in binary form must reproduce the above 23 * copyright notice, this list of conditions and the following 24 * disclaimer in the documentation and/or other materials provided 25 * with the distribution. 26 * 27 * - Neither the name of the Eclipse Foundation, Inc. nor the 28 * names of its contributors may be used to endorse or promote 29 * products derived from this software without specific prior 30 * written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 33 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 34 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 37 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 39 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 40 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 41 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 42 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 44 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45 */ 46 47 package org.eclipse.jgit.transport; 48 49 import static java.nio.charset.StandardCharsets.UTF_8; 50 import static java.util.Objects.requireNonNull; 51 52 import java.io.BufferedReader; 53 import java.io.IOException; 54 import java.io.InputStreamReader; 55 import java.io.OutputStream; 56 import java.io.PrintStream; 57 import java.lang.ref.WeakReference; 58 import java.lang.reflect.Field; 59 import java.lang.reflect.Modifier; 60 import java.net.URISyntaxException; 61 import java.net.URL; 62 import java.text.MessageFormat; 63 import java.util.ArrayList; 64 import java.util.Collection; 65 import java.util.Collections; 66 import java.util.Enumeration; 67 import java.util.LinkedHashSet; 68 import java.util.LinkedList; 69 import java.util.List; 70 import java.util.Map; 71 import java.util.Vector; 72 import java.util.concurrent.CopyOnWriteArrayList; 73 74 import org.eclipse.jgit.annotations.NonNull; 75 import org.eclipse.jgit.api.errors.AbortedByHookException; 76 import org.eclipse.jgit.errors.NotSupportedException; 77 import org.eclipse.jgit.errors.TransportException; 78 import org.eclipse.jgit.hooks.Hooks; 79 import org.eclipse.jgit.hooks.PrePushHook; 80 import org.eclipse.jgit.internal.JGitText; 81 import org.eclipse.jgit.lib.Constants; 82 import org.eclipse.jgit.lib.ObjectChecker; 83 import org.eclipse.jgit.lib.ObjectId; 84 import org.eclipse.jgit.lib.ProgressMonitor; 85 import org.eclipse.jgit.lib.Ref; 86 import org.eclipse.jgit.lib.Repository; 87 import org.eclipse.jgit.storage.pack.PackConfig; 88 89 /** 90 * Connects two Git repositories together and copies objects between them. 91 * <p> 92 * A transport can be used for either fetching (copying objects into the 93 * caller's repository from the remote repository) or pushing (copying objects 94 * into the remote repository from the caller's repository). Each transport 95 * implementation is responsible for the details associated with establishing 96 * the network connection(s) necessary for the copy, as well as actually 97 * shuffling data back and forth. 98 * <p> 99 * Transport instances and the connections they create are not thread-safe. 100 * Callers must ensure a transport is accessed by only one thread at a time. 101 */ 102 public abstract class Transport implements AutoCloseable { 103 /** Type of operation a Transport is being opened for. */ 104 public enum Operation { 105 /** Transport is to fetch objects locally. */ 106 FETCH, 107 /** Transport is to push objects remotely. */ 108 PUSH; 109 } 110 111 private static final List<WeakReference<TransportProtocol>> protocols = 112 new CopyOnWriteArrayList<>(); 113 114 static { 115 // Registration goes backwards in order of priority. 116 register(TransportLocal.PROTO_LOCAL); 117 register(TransportBundleFile.PROTO_BUNDLE); 118 register(TransportAmazonS3.PROTO_S3); 119 register(TransportGitAnon.PROTO_GIT); 120 register(TransportSftp.PROTO_SFTP); 121 register(TransportHttp.PROTO_FTP); 122 register(TransportHttp.PROTO_HTTP); 123 register(TransportGitSsh.PROTO_SSH); 124 125 registerByService(); 126 } 127 128 private static void registerByService() { 129 ClassLoader ldr = Thread.currentThread().getContextClassLoader(); 130 if (ldr == null) 131 ldr = Transport.class.getClassLoader(); 132 Enumeration<URL> catalogs = catalogs(ldr); 133 while (catalogs.hasMoreElements()) 134 scan(ldr, catalogs.nextElement()); 135 } 136 137 private static Enumeration<URL> catalogs(ClassLoader ldr) { 138 try { 139 String prefix = "META-INF/services/"; //$NON-NLS-1$ 140 String name = prefix + Transport.class.getName(); 141 return ldr.getResources(name); 142 } catch (IOException err) { 143 return new Vector<URL>().elements(); 144 } 145 } 146 147 private static void scan(ClassLoader ldr, URL url) { 148 try (BufferedReader br = new BufferedReader( 149 new InputStreamReader(url.openStream(), UTF_8))) { 150 String line; 151 while ((line = br.readLine()) != null) { 152 line = line.trim(); 153 if (line.length() == 0) 154 continue; 155 int comment = line.indexOf('#'); 156 if (comment == 0) 157 continue; 158 if (comment != -1) 159 line = line.substring(0, comment).trim(); 160 load(ldr, line); 161 } 162 } catch (IOException e) { 163 // Ignore errors 164 } 165 } 166 167 private static void load(ClassLoader ldr, String cn) { 168 Class<?> clazz; 169 try { 170 clazz = Class.forName(cn, false, ldr); 171 } catch (ClassNotFoundException notBuiltin) { 172 // Doesn't exist, even though the service entry is present. 173 // 174 return; 175 } 176 177 for (Field f : clazz.getDeclaredFields()) { 178 if ((f.getModifiers() & Modifier.STATIC) == Modifier.STATIC 179 && TransportProtocol.class.isAssignableFrom(f.getType())) { 180 TransportProtocol proto; 181 try { 182 proto = (TransportProtocol) f.get(null); 183 } catch (IllegalArgumentException | IllegalAccessException e) { 184 // If we cannot access the field, don't. 185 continue; 186 } 187 if (proto != null) 188 register(proto); 189 } 190 } 191 } 192 193 /** 194 * Register a TransportProtocol instance for use during open. 195 * <p> 196 * Protocol definitions are held by WeakReference, allowing them to be 197 * garbage collected when the calling application drops all strongly held 198 * references to the TransportProtocol. Therefore applications should use a 199 * singleton pattern as described in 200 * {@link org.eclipse.jgit.transport.TransportProtocol}'s class 201 * documentation to ensure their protocol does not get disabled by garbage 202 * collection earlier than expected. 203 * <p> 204 * The new protocol is registered in front of all earlier protocols, giving 205 * it higher priority than the built-in protocol definitions. 206 * 207 * @param proto 208 * the protocol definition. Must not be null. 209 */ 210 public static void register(TransportProtocol proto) { 211 protocols.add(0, new WeakReference<>(proto)); 212 } 213 214 /** 215 * Unregister a TransportProtocol instance. 216 * <p> 217 * Unregistering a protocol usually isn't necessary, as protocols are held 218 * by weak references and will automatically clear when they are garbage 219 * collected by the JVM. Matching is handled by reference equality, so the 220 * exact reference given to {@link #register(TransportProtocol)} must be 221 * used. 222 * 223 * @param proto 224 * the exact object previously given to register. 225 */ 226 public static void unregister(TransportProtocol proto) { 227 for (WeakReference<TransportProtocol> ref : protocols) { 228 TransportProtocol refProto = ref.get(); 229 if (refProto == null || refProto == proto) 230 protocols.remove(ref); 231 } 232 } 233 234 /** 235 * Obtain a copy of the registered protocols. 236 * 237 * @return an immutable copy of the currently registered protocols. 238 */ 239 public static List<TransportProtocol> getTransportProtocols() { 240 int cnt = protocols.size(); 241 List<TransportProtocol> res = new ArrayList<>(cnt); 242 for (WeakReference<TransportProtocol> ref : protocols) { 243 TransportProtocol proto = ref.get(); 244 if (proto != null) 245 res.add(proto); 246 else 247 protocols.remove(ref); 248 } 249 return Collections.unmodifiableList(res); 250 } 251 252 /** 253 * Open a new transport instance to connect two repositories. 254 * <p> 255 * This method assumes 256 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}. 257 * 258 * @param local 259 * existing local repository. 260 * @param remote 261 * location of the remote repository - may be URI or remote 262 * configuration name. 263 * @return the new transport instance. Never null. In case of multiple URIs 264 * in remote configuration, only the first is chosen. 265 * @throws java.net.URISyntaxException 266 * the location is not a remote defined in the configuration 267 * file and is not a well-formed URL. 268 * @throws org.eclipse.jgit.errors.NotSupportedException 269 * the protocol specified is not supported. 270 * @throws org.eclipse.jgit.errors.TransportException 271 * the transport cannot open this URI. 272 */ 273 public static Transport open(Repository local, String remote) 274 throws NotSupportedException, URISyntaxException, 275 TransportException { 276 return open(local, remote, Operation.FETCH); 277 } 278 279 /** 280 * Open a new transport instance to connect two repositories. 281 * 282 * @param local 283 * existing local repository. 284 * @param remote 285 * location of the remote repository - may be URI or remote 286 * configuration name. 287 * @param op 288 * planned use of the returned Transport; the URI may differ 289 * based on the type of connection desired. 290 * @return the new transport instance. Never null. In case of multiple URIs 291 * in remote configuration, only the first is chosen. 292 * @throws java.net.URISyntaxException 293 * the location is not a remote defined in the configuration 294 * file and is not a well-formed URL. 295 * @throws org.eclipse.jgit.errors.NotSupportedException 296 * the protocol specified is not supported. 297 * @throws org.eclipse.jgit.errors.TransportException 298 * the transport cannot open this URI. 299 */ 300 public static Transport open(final Repository local, final String remote, 301 final Operation op) throws NotSupportedException, 302 URISyntaxException, TransportException { 303 if (local != null) { 304 final RemoteConfigteConfig.html#RemoteConfig">RemoteConfig cfg = new RemoteConfig(local.getConfig(), remote); 305 if (doesNotExist(cfg)) 306 return open(local, new URIish(remote), null); 307 return open(local, cfg, op); 308 } else 309 return open(new URIish(remote)); 310 311 } 312 313 /** 314 * Open new transport instances to connect two repositories. 315 * <p> 316 * This method assumes 317 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}. 318 * 319 * @param local 320 * existing local repository. 321 * @param remote 322 * location of the remote repository - may be URI or remote 323 * configuration name. 324 * @return the list of new transport instances for every URI in remote 325 * configuration. 326 * @throws java.net.URISyntaxException 327 * the location is not a remote defined in the configuration 328 * file and is not a well-formed URL. 329 * @throws org.eclipse.jgit.errors.NotSupportedException 330 * the protocol specified is not supported. 331 * @throws org.eclipse.jgit.errors.TransportException 332 * the transport cannot open this URI. 333 */ 334 public static List<Transport> openAll(final Repository local, 335 final String remote) throws NotSupportedException, 336 URISyntaxException, TransportException { 337 return openAll(local, remote, Operation.FETCH); 338 } 339 340 /** 341 * Open new transport instances to connect two repositories. 342 * 343 * @param local 344 * existing local repository. 345 * @param remote 346 * location of the remote repository - may be URI or remote 347 * configuration name. 348 * @param op 349 * planned use of the returned Transport; the URI may differ 350 * based on the type of connection desired. 351 * @return the list of new transport instances for every URI in remote 352 * configuration. 353 * @throws java.net.URISyntaxException 354 * the location is not a remote defined in the configuration 355 * file and is not a well-formed URL. 356 * @throws org.eclipse.jgit.errors.NotSupportedException 357 * the protocol specified is not supported. 358 * @throws org.eclipse.jgit.errors.TransportException 359 * the transport cannot open this URI. 360 */ 361 public static List<Transport> openAll(final Repository local, 362 final String remote, final Operation op) 363 throws NotSupportedException, URISyntaxException, 364 TransportException { 365 final RemoteConfigteConfig.html#RemoteConfig">RemoteConfig cfg = new RemoteConfig(local.getConfig(), remote); 366 if (doesNotExist(cfg)) { 367 final ArrayList<Transport> transports = new ArrayList<>(1); 368 transports.add(open(local, new URIish(remote), null)); 369 return transports; 370 } 371 return openAll(local, cfg, op); 372 } 373 374 /** 375 * Open a new transport instance to connect two repositories. 376 * <p> 377 * This method assumes 378 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}. 379 * 380 * @param local 381 * existing local repository. 382 * @param cfg 383 * configuration describing how to connect to the remote 384 * repository. 385 * @return the new transport instance. Never null. In case of multiple URIs 386 * in remote configuration, only the first is chosen. 387 * @throws org.eclipse.jgit.errors.NotSupportedException 388 * the protocol specified is not supported. 389 * @throws org.eclipse.jgit.errors.TransportException 390 * the transport cannot open this URI. 391 * @throws java.lang.IllegalArgumentException 392 * if provided remote configuration doesn't have any URI 393 * associated. 394 */ 395 public static Transport open(Repository local, RemoteConfig cfg) 396 throws NotSupportedException, TransportException { 397 return open(local, cfg, Operation.FETCH); 398 } 399 400 /** 401 * Open a new transport instance to connect two repositories. 402 * 403 * @param local 404 * existing local repository. 405 * @param cfg 406 * configuration describing how to connect to the remote 407 * repository. 408 * @param op 409 * planned use of the returned Transport; the URI may differ 410 * based on the type of connection desired. 411 * @return the new transport instance. Never null. In case of multiple URIs 412 * in remote configuration, only the first is chosen. 413 * @throws org.eclipse.jgit.errors.NotSupportedException 414 * the protocol specified is not supported. 415 * @throws org.eclipse.jgit.errors.TransportException 416 * the transport cannot open this URI. 417 * @throws java.lang.IllegalArgumentException 418 * if provided remote configuration doesn't have any URI 419 * associated. 420 */ 421 public static Transport open(final Repository local, 422 final RemoteConfig cfg, final Operation op) 423 throws NotSupportedException, TransportException { 424 final List<URIish> uris = getURIs(cfg, op); 425 if (uris.isEmpty()) 426 throw new IllegalArgumentException(MessageFormat.format( 427 JGitText.get().remoteConfigHasNoURIAssociated, cfg.getName())); 428 final Transport tn = open(local, uris.get(0), cfg.getName()); 429 tn.applyConfig(cfg); 430 return tn; 431 } 432 433 /** 434 * Open new transport instances to connect two repositories. 435 * <p> 436 * This method assumes 437 * {@link org.eclipse.jgit.transport.Transport.Operation#FETCH}. 438 * 439 * @param local 440 * existing local repository. 441 * @param cfg 442 * configuration describing how to connect to the remote 443 * repository. 444 * @return the list of new transport instances for every URI in remote 445 * configuration. 446 * @throws org.eclipse.jgit.errors.NotSupportedException 447 * the protocol specified is not supported. 448 * @throws org.eclipse.jgit.errors.TransportException 449 * the transport cannot open this URI. 450 */ 451 public static List<Transport> openAll(final Repository local, 452 final RemoteConfig cfg) throws NotSupportedException, 453 TransportException { 454 return openAll(local, cfg, Operation.FETCH); 455 } 456 457 /** 458 * Open new transport instances to connect two repositories. 459 * 460 * @param local 461 * existing local repository. 462 * @param cfg 463 * configuration describing how to connect to the remote 464 * repository. 465 * @param op 466 * planned use of the returned Transport; the URI may differ 467 * based on the type of connection desired. 468 * @return the list of new transport instances for every URI in remote 469 * configuration. 470 * @throws org.eclipse.jgit.errors.NotSupportedException 471 * the protocol specified is not supported. 472 * @throws org.eclipse.jgit.errors.TransportException 473 * the transport cannot open this URI. 474 */ 475 public static List<Transport> openAll(final Repository local, 476 final RemoteConfig cfg, final Operation op) 477 throws NotSupportedException, TransportException { 478 final List<URIish> uris = getURIs(cfg, op); 479 final List<Transport> transports = new ArrayList<>(uris.size()); 480 for (URIish uri : uris) { 481 final Transport tn = open(local, uri, cfg.getName()); 482 tn.applyConfig(cfg); 483 transports.add(tn); 484 } 485 return transports; 486 } 487 488 private static List<URIish> getURIs(final RemoteConfig cfg, 489 final Operation op) { 490 switch (op) { 491 case FETCH: 492 return cfg.getURIs(); 493 case PUSH: { 494 List<URIish> uris = cfg.getPushURIs(); 495 if (uris.isEmpty()) 496 uris = cfg.getURIs(); 497 return uris; 498 } 499 default: 500 throw new IllegalArgumentException(op.toString()); 501 } 502 } 503 504 private static boolean doesNotExist(RemoteConfig cfg) { 505 return cfg.getURIs().isEmpty() && cfg.getPushURIs().isEmpty(); 506 } 507 508 /** 509 * Open a new transport instance to connect two repositories. 510 * 511 * @param local 512 * existing local repository. 513 * @param uri 514 * location of the remote repository. 515 * @return the new transport instance. Never null. 516 * @throws org.eclipse.jgit.errors.NotSupportedException 517 * the protocol specified is not supported. 518 * @throws org.eclipse.jgit.errors.TransportException 519 * the transport cannot open this URI. 520 */ 521 public static Transport open(Repository local, URIish uri) 522 throws NotSupportedException, TransportException { 523 return open(local, uri, null); 524 } 525 526 /** 527 * Open a new transport instance to connect two repositories. 528 * 529 * @param local 530 * existing local repository. 531 * @param uri 532 * location of the remote repository. 533 * @param remoteName 534 * name of the remote, if the remote as configured in 535 * {@code local}; otherwise null. 536 * @return the new transport instance. Never null. 537 * @throws org.eclipse.jgit.errors.NotSupportedException 538 * the protocol specified is not supported. 539 * @throws org.eclipse.jgit.errors.TransportException 540 * the transport cannot open this URI. 541 */ 542 public static Transport open(Repository local, URIish uri, String remoteName) 543 throws NotSupportedException, TransportException { 544 for (WeakReference<TransportProtocol> ref : protocols) { 545 TransportProtocol proto = ref.get(); 546 if (proto == null) { 547 protocols.remove(ref); 548 continue; 549 } 550 551 if (proto.canHandle(uri, local, remoteName)) { 552 Transport tn = proto.open(uri, local, remoteName); 553 tn.prePush = Hooks.prePush(local, tn.hookOutRedirect); 554 tn.prePush.setRemoteLocation(uri.toString()); 555 tn.prePush.setRemoteName(remoteName); 556 return tn; 557 } 558 } 559 560 throw new NotSupportedException(MessageFormat.format(JGitText.get().URINotSupported, uri)); 561 } 562 563 /** 564 * Open a new transport with no local repository. 565 * <p> 566 * Note that the resulting transport instance can not be used for fetching 567 * or pushing, but only for reading remote refs. 568 * 569 * @param uri a {@link org.eclipse.jgit.transport.URIish} object. 570 * @return new Transport instance 571 * @throws org.eclipse.jgit.errors.NotSupportedException 572 * @throws org.eclipse.jgit.errors.TransportException 573 */ 574 public static Transport open(URIish uri) throws NotSupportedException, TransportException { 575 for (WeakReference<TransportProtocol> ref : protocols) { 576 TransportProtocol proto = ref.get(); 577 if (proto == null) { 578 protocols.remove(ref); 579 continue; 580 } 581 582 if (proto.canHandle(uri, null, null)) 583 return proto.open(uri); 584 } 585 586 throw new NotSupportedException(MessageFormat.format(JGitText.get().URINotSupported, uri)); 587 } 588 589 /** 590 * Convert push remote refs update specification from 591 * {@link org.eclipse.jgit.transport.RefSpec} form to 592 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands 593 * wildcards by matching source part to local refs. expectedOldObjectId in 594 * RemoteRefUpdate is set when specified in leases. Tracking branch is 595 * configured if RefSpec destination matches source of any fetch ref spec 596 * for this transport remote configuration. 597 * 598 * @param db 599 * local database. 600 * @param specs 601 * collection of RefSpec to convert. 602 * @param leases 603 * map from ref to lease (containing expected old object id) 604 * @param fetchSpecs 605 * fetch specifications used for finding localtracking refs. May 606 * be null or empty collection. 607 * @return collection of set up 608 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. 609 * @throws java.io.IOException 610 * when problem occurred during conversion or specification set 611 * up: most probably, missing objects or refs. 612 * @since 4.7 613 */ 614 public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor( 615 final Repository db, final Collection<RefSpec> specs, 616 final Map<String, RefLeaseSpec> leases, 617 Collection<RefSpec> fetchSpecs) throws IOException { 618 if (fetchSpecs == null) 619 fetchSpecs = Collections.emptyList(); 620 final List<RemoteRefUpdate> result = new LinkedList<>(); 621 final Collection<RefSpec> procRefs = expandPushWildcardsFor(db, specs); 622 623 for (RefSpec spec : procRefs) { 624 String srcSpec = spec.getSource(); 625 final Ref srcRef = db.findRef(srcSpec); 626 if (srcRef != null) 627 srcSpec = srcRef.getName(); 628 629 String destSpec = spec.getDestination(); 630 if (destSpec == null) { 631 // No destination (no-colon in ref-spec), DWIMery assumes src 632 // 633 destSpec = srcSpec; 634 } 635 636 if (srcRef != null && !destSpec.startsWith(Constants.R_REFS)) { 637 // Assume the same kind of ref at the destination, e.g. 638 // "refs/heads/foo:master", DWIMery assumes master is also 639 // under "refs/heads/". 640 // 641 final String n = srcRef.getName(); 642 final int kindEnd = n.indexOf('/', Constants.R_REFS.length()); 643 destSpec = n.substring(0, kindEnd + 1) + destSpec; 644 } 645 646 final boolean forceUpdate = spec.isForceUpdate(); 647 final String localName = findTrackingRefName(destSpec, fetchSpecs); 648 final RefLeaseSpec leaseSpec = leases.get(destSpec); 649 final ObjectId expected = leaseSpec == null ? null : 650 db.resolve(leaseSpec.getExpected()); 651 final RemoteRefUpdateefUpdate.html#RemoteRefUpdate">RemoteRefUpdate rru = new RemoteRefUpdate(db, srcSpec, 652 destSpec, forceUpdate, localName, expected); 653 result.add(rru); 654 } 655 return result; 656 } 657 658 /** 659 * Convert push remote refs update specification from 660 * {@link org.eclipse.jgit.transport.RefSpec} form to 661 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands 662 * wildcards by matching source part to local refs. expectedOldObjectId in 663 * RemoteRefUpdate is always set as null. Tracking branch is configured if 664 * RefSpec destination matches source of any fetch ref spec for this 665 * transport remote configuration. 666 * 667 * @param db 668 * local database. 669 * @param specs 670 * collection of RefSpec to convert. 671 * @param fetchSpecs 672 * fetch specifications used for finding localtracking refs. May 673 * be null or empty collection. 674 * @return collection of set up 675 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. 676 * @throws java.io.IOException 677 * when problem occurred during conversion or specification set 678 * up: most probably, missing objects or refs. 679 */ 680 public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor( 681 final Repository db, final Collection<RefSpec> specs, 682 Collection<RefSpec> fetchSpecs) throws IOException { 683 return findRemoteRefUpdatesFor(db, specs, Collections.emptyMap(), 684 fetchSpecs); 685 } 686 687 private static Collection<RefSpec> expandPushWildcardsFor( 688 final Repository db, final Collection<RefSpec> specs) 689 throws IOException { 690 final List<Ref> localRefs = db.getRefDatabase().getRefs(); 691 final Collection<RefSpec> procRefs = new LinkedHashSet<>(); 692 693 for (RefSpec spec : specs) { 694 if (spec.isWildcard()) { 695 for (Ref localRef : localRefs) { 696 if (spec.matchSource(localRef)) 697 procRefs.add(spec.expandFromSource(localRef)); 698 } 699 } else { 700 procRefs.add(spec); 701 } 702 } 703 return procRefs; 704 } 705 706 private static String findTrackingRefName(final String remoteName, 707 final Collection<RefSpec> fetchSpecs) { 708 // try to find matching tracking refs 709 for (RefSpec fetchSpec : fetchSpecs) { 710 if (fetchSpec.matchSource(remoteName)) { 711 if (fetchSpec.isWildcard()) 712 return fetchSpec.expandFromSource(remoteName) 713 .getDestination(); 714 else 715 return fetchSpec.getDestination(); 716 } 717 } 718 return null; 719 } 720 721 /** 722 * Default setting for {@link #fetchThin} option. 723 */ 724 public static final boolean DEFAULT_FETCH_THIN = true; 725 726 /** 727 * Default setting for {@link #pushThin} option. 728 */ 729 public static final boolean DEFAULT_PUSH_THIN = false; 730 731 /** 732 * Specification for fetch or push operations, to fetch or push all tags. 733 * Acts as --tags. 734 */ 735 public static final RefSpechtml#RefSpec">RefSpec REFSPEC_TAGS = new RefSpec( 736 "refs/tags/*:refs/tags/*"); //$NON-NLS-1$ 737 738 /** 739 * Specification for push operation, to push all refs under refs/heads. Acts 740 * as --all. 741 */ 742 public static final RefSpec#RefSpec">RefSpec REFSPEC_PUSH_ALL = new RefSpec( 743 "refs/heads/*:refs/heads/*"); //$NON-NLS-1$ 744 745 /** The repository this transport fetches into, or pushes out of. */ 746 protected final Repository local; 747 748 /** The URI used to create this transport. */ 749 protected final URIish uri; 750 751 /** Name of the upload pack program, if it must be executed. */ 752 private String optionUploadPack = RemoteConfig.DEFAULT_UPLOAD_PACK; 753 754 /** Specifications to apply during fetch. */ 755 private List<RefSpec> fetch = Collections.emptyList(); 756 757 /** 758 * How {@link #fetch(ProgressMonitor, Collection)} should handle tags. 759 * <p> 760 * We default to {@link TagOpt#NO_TAGS} so as to avoid fetching annotated 761 * tags during one-shot fetches used for later merges. This prevents 762 * dragging down tags from repositories that we do not have established 763 * tracking branches for. If we do not track the source repository, we most 764 * likely do not care about any tags it publishes. 765 */ 766 private TagOpt tagopt = TagOpt.NO_TAGS; 767 768 /** Should fetch request thin-pack if remote repository can produce it. */ 769 private boolean fetchThin = DEFAULT_FETCH_THIN; 770 771 /** Name of the receive pack program, if it must be executed. */ 772 private String optionReceivePack = RemoteConfig.DEFAULT_RECEIVE_PACK; 773 774 /** Specifications to apply during push. */ 775 private List<RefSpec> push = Collections.emptyList(); 776 777 /** Should push produce thin-pack when sending objects to remote repository. */ 778 private boolean pushThin = DEFAULT_PUSH_THIN; 779 780 /** Should push be all-or-nothing atomic behavior? */ 781 private boolean pushAtomic; 782 783 /** Should push just check for operation result, not really push. */ 784 private boolean dryRun; 785 786 /** Should an incoming (fetch) transfer validate objects? */ 787 private ObjectChecker objectChecker; 788 789 /** Should refs no longer on the source be pruned from the destination? */ 790 private boolean removeDeletedRefs; 791 792 private FilterSpec filterSpec = FilterSpec.NO_FILTER; 793 794 /** Timeout in seconds to wait before aborting an IO read or write. */ 795 private int timeout; 796 797 /** Pack configuration used by this transport to make pack file. */ 798 private PackConfig packConfig; 799 800 /** Assists with authentication the connection. */ 801 private CredentialsProvider credentialsProvider; 802 803 /** The option strings associated with the push operation. */ 804 private List<String> pushOptions; 805 806 private PrintStream hookOutRedirect; 807 808 private PrePushHook prePush; 809 /** 810 * Create a new transport instance. 811 * 812 * @param local 813 * the repository this instance will fetch into, or push out of. 814 * This must be the repository passed to 815 * {@link #open(Repository, URIish)}. 816 * @param uri 817 * the URI used to access the remote repository. This must be the 818 * URI passed to {@link #open(Repository, URIish)}. 819 */ 820 protected Transport(Repository local, URIish uri) { 821 final TransferConfig tc = local.getConfig().get(TransferConfig.KEY); 822 this.local = local; 823 this.uri = uri; 824 this.objectChecker = tc.newObjectChecker(); 825 this.credentialsProvider = CredentialsProvider.getDefault(); 826 prePush = Hooks.prePush(local, hookOutRedirect); 827 } 828 829 /** 830 * Create a minimal transport instance not tied to a single repository. 831 * 832 * @param uri 833 * a {@link org.eclipse.jgit.transport.URIish} object. 834 */ 835 protected Transport(URIish uri) { 836 this.uri = uri; 837 this.local = null; 838 this.objectChecker = new ObjectChecker(); 839 this.credentialsProvider = CredentialsProvider.getDefault(); 840 } 841 842 /** 843 * Get the URI this transport connects to. 844 * <p> 845 * Each transport instance connects to at most one URI at any point in time. 846 * 847 * @return the URI describing the location of the remote repository. 848 */ 849 public URIish getURI() { 850 return uri; 851 } 852 853 /** 854 * Get the name of the remote executable providing upload-pack service. 855 * 856 * @return typically "git-upload-pack". 857 */ 858 public String getOptionUploadPack() { 859 return optionUploadPack; 860 } 861 862 /** 863 * Set the name of the remote executable providing upload-pack services. 864 * 865 * @param where 866 * name of the executable. 867 */ 868 public void setOptionUploadPack(String where) { 869 if (where != null && where.length() > 0) 870 optionUploadPack = where; 871 else 872 optionUploadPack = RemoteConfig.DEFAULT_UPLOAD_PACK; 873 } 874 875 /** 876 * Get the description of how annotated tags should be treated during fetch. 877 * 878 * @return option indicating the behavior of annotated tags in fetch. 879 */ 880 public TagOpt getTagOpt() { 881 return tagopt; 882 } 883 884 /** 885 * Set the description of how annotated tags should be treated on fetch. 886 * 887 * @param option 888 * method to use when handling annotated tags. 889 */ 890 public void setTagOpt(TagOpt option) { 891 tagopt = option != null ? option : TagOpt.AUTO_FOLLOW; 892 } 893 894 /** 895 * Default setting is: {@link #DEFAULT_FETCH_THIN} 896 * 897 * @return true if fetch should request thin-pack when possible; false 898 * otherwise 899 * @see PackTransport 900 */ 901 public boolean isFetchThin() { 902 return fetchThin; 903 } 904 905 /** 906 * Set the thin-pack preference for fetch operation. Default setting is: 907 * {@link #DEFAULT_FETCH_THIN} 908 * 909 * @param fetchThin 910 * true when fetch should request thin-pack when possible; false 911 * when it shouldn't 912 * @see PackTransport 913 */ 914 public void setFetchThin(boolean fetchThin) { 915 this.fetchThin = fetchThin; 916 } 917 918 /** 919 * Whether fetch will verify if received objects are formatted correctly. 920 * 921 * @return true if fetch will verify received objects are formatted 922 * correctly. Validating objects requires more CPU time on the 923 * client side of the connection. 924 */ 925 public boolean isCheckFetchedObjects() { 926 return getObjectChecker() != null; 927 } 928 929 /** 930 * Configure if checking received objects is enabled 931 * 932 * @param check 933 * true to enable checking received objects; false to assume all 934 * received objects are valid. 935 * @see #setObjectChecker(ObjectChecker) 936 */ 937 public void setCheckFetchedObjects(boolean check) { 938 if (check && objectChecker == null) 939 setObjectChecker(new ObjectChecker()); 940 else if (!check && objectChecker != null) 941 setObjectChecker(null); 942 } 943 944 /** 945 * Get configured object checker for received objects 946 * 947 * @return configured object checker for received objects, or null. 948 * @since 3.6 949 */ 950 public ObjectChecker getObjectChecker() { 951 return objectChecker; 952 } 953 954 /** 955 * Set the object checker to verify each received object with 956 * 957 * @param impl 958 * if non-null the object checking instance to verify each 959 * received object with; null to disable object checking. 960 * @since 3.6 961 */ 962 public void setObjectChecker(ObjectChecker impl) { 963 objectChecker = impl; 964 } 965 966 /** 967 * Default setting is: 968 * {@link org.eclipse.jgit.transport.RemoteConfig#DEFAULT_RECEIVE_PACK} 969 * 970 * @return remote executable providing receive-pack service for pack 971 * transports. 972 * @see PackTransport 973 */ 974 public String getOptionReceivePack() { 975 return optionReceivePack; 976 } 977 978 /** 979 * Set remote executable providing receive-pack service for pack transports. 980 * Default setting is: 981 * {@link org.eclipse.jgit.transport.RemoteConfig#DEFAULT_RECEIVE_PACK} 982 * 983 * @param optionReceivePack 984 * remote executable, if null or empty default one is set; 985 */ 986 public void setOptionReceivePack(String optionReceivePack) { 987 if (optionReceivePack != null && optionReceivePack.length() > 0) 988 this.optionReceivePack = optionReceivePack; 989 else 990 this.optionReceivePack = RemoteConfig.DEFAULT_RECEIVE_PACK; 991 } 992 993 /** 994 * Default setting is: {@value #DEFAULT_PUSH_THIN} 995 * 996 * @return true if push should produce thin-pack in pack transports 997 * @see PackTransport 998 */ 999 public boolean isPushThin() { 1000 return pushThin; 1001 } 1002 1003 /** 1004 * Set thin-pack preference for push operation. Default setting is: 1005 * {@value #DEFAULT_PUSH_THIN} 1006 * 1007 * @param pushThin 1008 * true when push should produce thin-pack in pack transports; 1009 * false when it shouldn't 1010 * @see PackTransport 1011 */ 1012 public void setPushThin(boolean pushThin) { 1013 this.pushThin = pushThin; 1014 } 1015 1016 /** 1017 * Default setting is false. 1018 * 1019 * @return true if push requires all-or-nothing atomic behavior. 1020 * @since 4.2 1021 */ 1022 public boolean isPushAtomic() { 1023 return pushAtomic; 1024 } 1025 1026 /** 1027 * Request atomic push (all references succeed, or none do). 1028 * <p> 1029 * Server must also support atomic push. If the server does not support the 1030 * feature the push will abort without making changes. 1031 * 1032 * @param atomic 1033 * true when push should be an all-or-nothing operation. 1034 * @see PackTransport 1035 * @since 4.2 1036 */ 1037 public void setPushAtomic(boolean atomic) { 1038 this.pushAtomic = atomic; 1039 } 1040 1041 /** 1042 * Whether destination refs should be removed if they no longer exist at the 1043 * source repository. 1044 * 1045 * @return true if destination refs should be removed if they no longer 1046 * exist at the source repository. 1047 */ 1048 public boolean isRemoveDeletedRefs() { 1049 return removeDeletedRefs; 1050 } 1051 1052 /** 1053 * Set whether or not to remove refs which no longer exist in the source. 1054 * <p> 1055 * If true, refs at the destination repository (local for fetch, remote for 1056 * push) are deleted if they no longer exist on the source side (remote for 1057 * fetch, local for push). 1058 * <p> 1059 * False by default, as this may cause data to become unreachable, and 1060 * eventually be deleted on the next GC. 1061 * 1062 * @param remove true to remove refs that no longer exist. 1063 */ 1064 public void setRemoveDeletedRefs(boolean remove) { 1065 removeDeletedRefs = remove; 1066 } 1067 1068 /** 1069 * @return the blob limit value set with {@link #setFilterBlobLimit} or 1070 * {@link #setFilterSpec(FilterSpec)}, or -1 if no blob limit value 1071 * was set 1072 * @since 5.0 1073 * @deprecated Use {@link #getFilterSpec()} instead 1074 */ 1075 @Deprecated 1076 public final long getFilterBlobLimit() { 1077 return filterSpec.getBlobLimit(); 1078 } 1079 1080 /** 1081 * @param bytes exclude blobs of size greater than this 1082 * @since 5.0 1083 * @deprecated Use {@link #setFilterSpec(FilterSpec)} instead 1084 */ 1085 @Deprecated 1086 public final void setFilterBlobLimit(long bytes) { 1087 setFilterSpec(FilterSpec.withBlobLimit(bytes)); 1088 } 1089 1090 /** 1091 * @return the last filter spec set with {@link #setFilterSpec(FilterSpec)}, 1092 * or {@link FilterSpec#NO_FILTER} if it was never invoked. 1093 * @since 5.4 1094 */ 1095 public final FilterSpec getFilterSpec() { 1096 return filterSpec; 1097 } 1098 1099 /** 1100 * @param filter a new filter to use for this transport 1101 * @since 5.4 1102 */ 1103 public final void setFilterSpec(@NonNull FilterSpec filter) { 1104 filterSpec = requireNonNull(filter); 1105 } 1106 1107 /** 1108 * Apply provided remote configuration on this transport. 1109 * 1110 * @param cfg 1111 * configuration to apply on this transport. 1112 */ 1113 public void applyConfig(RemoteConfig cfg) { 1114 setOptionUploadPack(cfg.getUploadPack()); 1115 setOptionReceivePack(cfg.getReceivePack()); 1116 setTagOpt(cfg.getTagOpt()); 1117 fetch = cfg.getFetchRefSpecs(); 1118 push = cfg.getPushRefSpecs(); 1119 timeout = cfg.getTimeout(); 1120 } 1121 1122 /** 1123 * Whether push operation should just check for possible result and not 1124 * really update remote refs 1125 * 1126 * @return true if push operation should just check for possible result and 1127 * not really update remote refs, false otherwise - when push should 1128 * act normally. 1129 */ 1130 public boolean isDryRun() { 1131 return dryRun; 1132 } 1133 1134 /** 1135 * Set dry run option for push operation. 1136 * 1137 * @param dryRun 1138 * true if push operation should just check for possible result 1139 * and not really update remote refs, false otherwise - when push 1140 * should act normally. 1141 */ 1142 public void setDryRun(boolean dryRun) { 1143 this.dryRun = dryRun; 1144 } 1145 1146 /** 1147 * Get timeout (in seconds) before aborting an IO operation. 1148 * 1149 * @return timeout (in seconds) before aborting an IO operation. 1150 */ 1151 public int getTimeout() { 1152 return timeout; 1153 } 1154 1155 /** 1156 * Set the timeout before willing to abort an IO call. 1157 * 1158 * @param seconds 1159 * number of seconds to wait (with no data transfer occurring) 1160 * before aborting an IO read or write operation with this 1161 * remote. 1162 */ 1163 public void setTimeout(int seconds) { 1164 timeout = seconds; 1165 } 1166 1167 /** 1168 * Get the configuration used by the pack generator to make packs. 1169 * 1170 * If {@link #setPackConfig(PackConfig)} was previously given null a new 1171 * PackConfig is created on demand by this method using the source 1172 * repository's settings. 1173 * 1174 * @return the pack configuration. Never null. 1175 */ 1176 public PackConfig getPackConfig() { 1177 if (packConfig == null) 1178 packConfig = new PackConfig(local); 1179 return packConfig; 1180 } 1181 1182 /** 1183 * Set the configuration used by the pack generator. 1184 * 1185 * @param pc 1186 * configuration controlling packing parameters. If null the 1187 * source repository's settings will be used. 1188 */ 1189 public void setPackConfig(PackConfig pc) { 1190 packConfig = pc; 1191 } 1192 1193 /** 1194 * A credentials provider to assist with authentication connections.. 1195 * 1196 * @param credentialsProvider 1197 * the credentials provider, or null if there is none 1198 */ 1199 public void setCredentialsProvider(CredentialsProvider credentialsProvider) { 1200 this.credentialsProvider = credentialsProvider; 1201 } 1202 1203 /** 1204 * The configured credentials provider. 1205 * 1206 * @return the credentials provider, or null if no credentials provider is 1207 * associated with this transport. 1208 */ 1209 public CredentialsProvider getCredentialsProvider() { 1210 return credentialsProvider; 1211 } 1212 1213 /** 1214 * Get the option strings associated with the push operation 1215 * 1216 * @return the option strings associated with the push operation 1217 * @since 4.5 1218 */ 1219 public List<String> getPushOptions() { 1220 return pushOptions; 1221 } 1222 1223 /** 1224 * Sets the option strings associated with the push operation. 1225 * 1226 * @param pushOptions 1227 * null if push options are unsupported 1228 * @since 4.5 1229 */ 1230 public void setPushOptions(List<String> pushOptions) { 1231 this.pushOptions = pushOptions; 1232 } 1233 1234 /** 1235 * Fetch objects and refs from the remote repository to the local one. 1236 * <p> 1237 * This is a utility function providing standard fetch behavior. Local 1238 * tracking refs associated with the remote repository are automatically 1239 * updated if this transport was created from a 1240 * {@link org.eclipse.jgit.transport.RemoteConfig} with fetch RefSpecs 1241 * defined. 1242 * 1243 * @param monitor 1244 * progress monitor to inform the user about our processing 1245 * activity. Must not be null. Use 1246 * {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress 1247 * updates are not interesting or necessary. 1248 * @param toFetch 1249 * specification of refs to fetch locally. May be null or the 1250 * empty collection to use the specifications from the 1251 * RemoteConfig. Source for each RefSpec can't be null. 1252 * @return information describing the tracking refs updated. 1253 * @throws org.eclipse.jgit.errors.NotSupportedException 1254 * this transport implementation does not support fetching 1255 * objects. 1256 * @throws org.eclipse.jgit.errors.TransportException 1257 * the remote connection could not be established or object 1258 * copying (if necessary) failed or update specification was 1259 * incorrect. 1260 */ 1261 public FetchResult fetch(final ProgressMonitor monitor, 1262 Collection<RefSpec> toFetch) throws NotSupportedException, 1263 TransportException { 1264 if (toFetch == null || toFetch.isEmpty()) { 1265 // If the caller did not ask for anything use the defaults. 1266 // 1267 if (fetch.isEmpty()) 1268 throw new TransportException(JGitText.get().nothingToFetch); 1269 toFetch = fetch; 1270 } else if (!fetch.isEmpty()) { 1271 // If the caller asked for something specific without giving 1272 // us the local tracking branch see if we can update any of 1273 // the local tracking branches without incurring additional 1274 // object transfer overheads. 1275 // 1276 final Collection<RefSpec> tmp = new ArrayList<>(toFetch); 1277 for (RefSpec requested : toFetch) { 1278 final String reqSrc = requested.getSource(); 1279 for (RefSpec configured : fetch) { 1280 final String cfgSrc = configured.getSource(); 1281 final String cfgDst = configured.getDestination(); 1282 if (cfgSrc.equals(reqSrc) && cfgDst != null) { 1283 tmp.add(configured); 1284 break; 1285 } 1286 } 1287 } 1288 toFetch = tmp; 1289 } 1290 1291 final FetchResultesult.html#FetchResult">FetchResult result = new FetchResult(); 1292 new FetchProcess(this, toFetch).execute(monitor, result); 1293 1294 local.autoGC(monitor); 1295 1296 return result; 1297 } 1298 1299 /** 1300 * Push objects and refs from the local repository to the remote one. 1301 * <p> 1302 * This is a utility function providing standard push behavior. It updates 1303 * remote refs and send there necessary objects according to remote ref 1304 * update specification. After successful remote ref update, associated 1305 * locally stored tracking branch is updated if set up accordingly. Detailed 1306 * operation result is provided after execution. 1307 * <p> 1308 * For setting up remote ref update specification from ref spec, see helper 1309 * method {@link #findRemoteRefUpdatesFor(Collection)}, predefined refspecs 1310 * ({@link #REFSPEC_TAGS}, {@link #REFSPEC_PUSH_ALL}) or consider using 1311 * directly {@link org.eclipse.jgit.transport.RemoteRefUpdate} for more 1312 * possibilities. 1313 * <p> 1314 * When {@link #isDryRun()} is true, result of this operation is just 1315 * estimation of real operation result, no real action is performed. 1316 * 1317 * @see RemoteRefUpdate 1318 * @param monitor 1319 * progress monitor to inform the user about our processing 1320 * activity. Must not be null. Use 1321 * {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress 1322 * updates are not interesting or necessary. 1323 * @param toPush 1324 * specification of refs to push. May be null or the empty 1325 * collection to use the specifications from the RemoteConfig 1326 * converted by {@link #findRemoteRefUpdatesFor(Collection)}. No 1327 * more than 1 RemoteRefUpdate with the same remoteName is 1328 * allowed. These objects are modified during this call. 1329 * @param out 1330 * output stream to write messages to 1331 * @return information about results of remote refs updates, tracking refs 1332 * updates and refs advertised by remote repository. 1333 * @throws org.eclipse.jgit.errors.NotSupportedException 1334 * this transport implementation does not support pushing 1335 * objects. 1336 * @throws org.eclipse.jgit.errors.TransportException 1337 * the remote connection could not be established or object 1338 * copying (if necessary) failed at I/O or protocol level or 1339 * update specification was incorrect. 1340 * @since 3.0 1341 */ 1342 public PushResult push(final ProgressMonitor monitor, 1343 Collection<RemoteRefUpdate> toPush, OutputStream out) 1344 throws NotSupportedException, 1345 TransportException { 1346 if (toPush == null || toPush.isEmpty()) { 1347 // If the caller did not ask for anything use the defaults. 1348 try { 1349 toPush = findRemoteRefUpdatesFor(push); 1350 } catch (final IOException e) { 1351 throw new TransportException(MessageFormat.format( 1352 JGitText.get().problemWithResolvingPushRefSpecsLocally, e.getMessage()), e); 1353 } 1354 if (toPush.isEmpty()) 1355 throw new TransportException(JGitText.get().nothingToPush); 1356 } 1357 if (prePush != null) { 1358 try { 1359 prePush.setRefs(toPush); 1360 prePush.call(); 1361 } catch (AbortedByHookException | IOException e) { 1362 throw new TransportException(e.getMessage(), e); 1363 } 1364 } 1365 1366 final PushProcess.html#PushProcess">PushProcess pushProcess = new PushProcess(this, toPush, out); 1367 return pushProcess.execute(monitor); 1368 } 1369 1370 /** 1371 * Push objects and refs from the local repository to the remote one. 1372 * <p> 1373 * This is a utility function providing standard push behavior. It updates 1374 * remote refs and sends necessary objects according to remote ref update 1375 * specification. After successful remote ref update, associated locally 1376 * stored tracking branch is updated if set up accordingly. Detailed 1377 * operation result is provided after execution. 1378 * <p> 1379 * For setting up remote ref update specification from ref spec, see helper 1380 * method {@link #findRemoteRefUpdatesFor(Collection)}, predefined refspecs 1381 * ({@link #REFSPEC_TAGS}, {@link #REFSPEC_PUSH_ALL}) or consider using 1382 * directly {@link org.eclipse.jgit.transport.RemoteRefUpdate} for more 1383 * possibilities. 1384 * <p> 1385 * When {@link #isDryRun()} is true, result of this operation is just 1386 * estimation of real operation result, no real action is performed. 1387 * 1388 * @see RemoteRefUpdate 1389 * @param monitor 1390 * progress monitor to inform the user about our processing 1391 * activity. Must not be null. Use 1392 * {@link org.eclipse.jgit.lib.NullProgressMonitor} if progress 1393 * updates are not interesting or necessary. 1394 * @param toPush 1395 * specification of refs to push. May be null or the empty 1396 * collection to use the specifications from the RemoteConfig 1397 * converted by {@link #findRemoteRefUpdatesFor(Collection)}. No 1398 * more than 1 RemoteRefUpdate with the same remoteName is 1399 * allowed. These objects are modified during this call. 1400 * @return information about results of remote refs updates, tracking refs 1401 * updates and refs advertised by remote repository. 1402 * @throws org.eclipse.jgit.errors.NotSupportedException 1403 * this transport implementation does not support pushing 1404 * objects. 1405 * @throws org.eclipse.jgit.errors.TransportException 1406 * the remote connection could not be established or object 1407 * copying (if necessary) failed at I/O or protocol level or 1408 * update specification was incorrect. 1409 */ 1410 public PushResult push(final ProgressMonitor monitor, 1411 Collection<RemoteRefUpdate> toPush) throws NotSupportedException, 1412 TransportException { 1413 return push(monitor, toPush, null); 1414 } 1415 1416 /** 1417 * Convert push remote refs update specification from 1418 * {@link org.eclipse.jgit.transport.RefSpec} form to 1419 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands 1420 * wildcards by matching source part to local refs. expectedOldObjectId in 1421 * RemoteRefUpdate is always set as null. Tracking branch is configured if 1422 * RefSpec destination matches source of any fetch ref spec for this 1423 * transport remote configuration. 1424 * <p> 1425 * Conversion is performed for context of this transport (database, fetch 1426 * specifications). 1427 * 1428 * @param specs 1429 * collection of RefSpec to convert. 1430 * @return collection of set up 1431 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. 1432 * @throws java.io.IOException 1433 * when problem occurred during conversion or specification set 1434 * up: most probably, missing objects or refs. 1435 */ 1436 public Collection<RemoteRefUpdate> findRemoteRefUpdatesFor( 1437 final Collection<RefSpec> specs) throws IOException { 1438 return findRemoteRefUpdatesFor(local, specs, Collections.emptyMap(), 1439 fetch); 1440 } 1441 1442 /** 1443 * Convert push remote refs update specification from 1444 * {@link org.eclipse.jgit.transport.RefSpec} form to 1445 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. Conversion expands 1446 * wildcards by matching source part to local refs. expectedOldObjectId in 1447 * RemoteRefUpdate is set according to leases. Tracking branch is configured 1448 * if RefSpec destination matches source of any fetch ref spec for this 1449 * transport remote configuration. 1450 * <p> 1451 * Conversion is performed for context of this transport (database, fetch 1452 * specifications). 1453 * 1454 * @param specs 1455 * collection of RefSpec to convert. 1456 * @param leases 1457 * map from ref to lease (containing expected old object id) 1458 * @return collection of set up 1459 * {@link org.eclipse.jgit.transport.RemoteRefUpdate}. 1460 * @throws java.io.IOException 1461 * when problem occurred during conversion or specification set 1462 * up: most probably, missing objects or refs. 1463 * @since 4.7 1464 */ 1465 public Collection<RemoteRefUpdate> findRemoteRefUpdatesFor( 1466 final Collection<RefSpec> specs, 1467 final Map<String, RefLeaseSpec> leases) throws IOException { 1468 return findRemoteRefUpdatesFor(local, specs, leases, 1469 fetch); 1470 } 1471 1472 /** 1473 * Begins a new connection for fetching from the remote repository. 1474 * <p> 1475 * If the transport has no local repository, the fetch connection can only 1476 * be used for reading remote refs. 1477 * 1478 * @return a fresh connection to fetch from the remote repository. 1479 * @throws org.eclipse.jgit.errors.NotSupportedException 1480 * the implementation does not support fetching. 1481 * @throws org.eclipse.jgit.errors.TransportException 1482 * the remote connection could not be established. 1483 */ 1484 public abstract FetchConnection openFetch() throws NotSupportedException, 1485 TransportException; 1486 1487 /** 1488 * Begins a new connection for pushing into the remote repository. 1489 * 1490 * @return a fresh connection to push into the remote repository. 1491 * @throws org.eclipse.jgit.errors.NotSupportedException 1492 * the implementation does not support pushing. 1493 * @throws org.eclipse.jgit.errors.TransportException 1494 * the remote connection could not be established 1495 */ 1496 public abstract PushConnection openPush() throws NotSupportedException, 1497 TransportException; 1498 1499 /** 1500 * {@inheritDoc} 1501 * <p> 1502 * Close any resources used by this transport. 1503 * <p> 1504 * If the remote repository is contacted by a network socket this method 1505 * must close that network socket, disconnecting the two peers. If the 1506 * remote repository is actually local (same system) this method must close 1507 * any open file handles used to read the "remote" repository. 1508 * <p> 1509 * {@code AutoClosable.close()} declares that it throws {@link Exception}. 1510 * Implementers shouldn't throw checked exceptions. This override narrows 1511 * the signature to prevent them from doing so. 1512 */ 1513 @Override 1514 public abstract void close(); 1515 }