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