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