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