LsRemoteCommand.java

  1. /*
  2.  * Copyright (C) 2011, 2022 Christoph Brill <egore911@egore911.de> and others
  3.  *
  4.  * This program and the accompanying materials are made available under the
  5.  * terms of the Eclipse Distribution License v. 1.0 which is available at
  6.  * https://www.eclipse.org/org/documents/edl-v10.php.
  7.  *
  8.  * SPDX-License-Identifier: BSD-3-Clause
  9.  */
  10. package org.eclipse.jgit.api;

  11. import java.io.IOException;
  12. import java.net.URISyntaxException;
  13. import java.text.MessageFormat;
  14. import java.util.ArrayList;
  15. import java.util.Collection;
  16. import java.util.Collections;
  17. import java.util.HashMap;
  18. import java.util.Map;

  19. import org.eclipse.jgit.api.errors.GitAPIException;
  20. import org.eclipse.jgit.api.errors.InvalidRemoteException;
  21. import org.eclipse.jgit.api.errors.JGitInternalException;
  22. import org.eclipse.jgit.errors.ConfigInvalidException;
  23. import org.eclipse.jgit.errors.NotSupportedException;
  24. import org.eclipse.jgit.internal.JGitText;
  25. import org.eclipse.jgit.lib.Constants;
  26. import org.eclipse.jgit.lib.Ref;
  27. import org.eclipse.jgit.lib.Repository;
  28. import org.eclipse.jgit.transport.FetchConnection;
  29. import org.eclipse.jgit.transport.RefSpec;
  30. import org.eclipse.jgit.transport.Transport;
  31. import org.eclipse.jgit.transport.URIish;
  32. import org.eclipse.jgit.transport.UrlConfig;
  33. import org.eclipse.jgit.util.SystemReader;

  34. /**
  35.  * The ls-remote command
  36.  *
  37.  * @see <a
  38.  *      href="http://www.kernel.org/pub/software/scm/git/docs/git-ls-remote.html"
  39.  *      >Git documentation about ls-remote</a>
  40.  */
  41. public class LsRemoteCommand extends
  42.         TransportCommand<LsRemoteCommand, Collection<Ref>> {

  43.     private String remote = Constants.DEFAULT_REMOTE_NAME;

  44.     private boolean heads;

  45.     private boolean tags;

  46.     private String uploadPack;

  47.     /**
  48.      * Constructor for LsRemoteCommand
  49.      *
  50.      * @param repo
  51.      *            local repository or null for operation without local
  52.      *            repository
  53.      */
  54.     public LsRemoteCommand(Repository repo) {
  55.         super(repo);
  56.     }

  57.     /**
  58.      * The remote (uri or name) used for the fetch operation. If no remote is
  59.      * set, the default value of <code>Constants.DEFAULT_REMOTE_NAME</code> will
  60.      * be used.
  61.      *
  62.      * @see Constants#DEFAULT_REMOTE_NAME
  63.      * @param remote
  64.      *            a {@link java.lang.String} object.
  65.      * @return {@code this}
  66.      */
  67.     public LsRemoteCommand setRemote(String remote) {
  68.         checkCallable();
  69.         this.remote = remote;
  70.         return this;
  71.     }

  72.     /**
  73.      * Include refs/heads in references results
  74.      *
  75.      * @param heads
  76.      *            whether to include refs/heads
  77.      * @return {@code this}
  78.      */
  79.     public LsRemoteCommand setHeads(boolean heads) {
  80.         this.heads = heads;
  81.         return this;
  82.     }

  83.     /**
  84.      * Include refs/tags in references results
  85.      *
  86.      * @param tags
  87.      *            whether to include tags
  88.      * @return {@code this}
  89.      */
  90.     public LsRemoteCommand setTags(boolean tags) {
  91.         this.tags = tags;
  92.         return this;
  93.     }

  94.     /**
  95.      * The full path of git-upload-pack on the remote host
  96.      *
  97.      * @param uploadPack
  98.      *            the full path of executable providing the git-upload-pack
  99.      *            service on remote host
  100.      * @return {@code this}
  101.      */
  102.     public LsRemoteCommand setUploadPack(String uploadPack) {
  103.         this.uploadPack = uploadPack;
  104.         return this;
  105.     }

  106.     /**
  107.      * {@inheritDoc}
  108.      * <p>
  109.      * Execute the {@code LsRemote} command with all the options and parameters
  110.      * collected by the setter methods (e.g. {@link #setHeads(boolean)}) of this
  111.      * class. Each instance of this class should only be used for one invocation
  112.      * of the command. Don't call this method twice on an instance.
  113.      */
  114.     @Override
  115.     public Collection<Ref> call() throws GitAPIException,
  116.             InvalidRemoteException,
  117.             org.eclipse.jgit.api.errors.TransportException {
  118.         return execute().values();
  119.     }

  120.     /**
  121.      * Same as {@link #call()}, but return Map instead of Collection.
  122.      *
  123.      * @return a map from names to references in the remote repository
  124.      * @throws org.eclipse.jgit.api.errors.GitAPIException
  125.      *             or subclass thereof when an error occurs
  126.      * @throws org.eclipse.jgit.api.errors.InvalidRemoteException
  127.      *             when called with an invalid remote uri
  128.      * @throws org.eclipse.jgit.api.errors.TransportException
  129.      *             for errors that occurs during transport
  130.      * @since 3.5
  131.      */
  132.     public Map<String, Ref> callAsMap() throws GitAPIException,
  133.             InvalidRemoteException,
  134.             org.eclipse.jgit.api.errors.TransportException {
  135.         return Collections.unmodifiableMap(execute());
  136.     }

  137.     private Map<String, Ref> execute() throws GitAPIException,
  138.             InvalidRemoteException,
  139.             org.eclipse.jgit.api.errors.TransportException {
  140.         checkCallable();

  141.         try (Transport transport = repo != null
  142.                 ? Transport.open(repo, remote)
  143.                 : Transport.open(new URIish(translate(remote)))) {
  144.             transport.setOptionUploadPack(uploadPack);
  145.             configure(transport);
  146.             Collection<RefSpec> refSpecs = new ArrayList<>(1);
  147.             if (tags)
  148.                 refSpecs.add(new RefSpec(
  149.                         "refs/tags/*:refs/remotes/origin/tags/*")); //$NON-NLS-1$
  150.             if (heads)
  151.                 refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$
  152.             Collection<Ref> refs;
  153.             Map<String, Ref> refmap = new HashMap<>();
  154.             try (FetchConnection fc = transport.openFetch(refSpecs)) {
  155.                 refs = fc.getRefs();
  156.                 if (refSpecs.isEmpty())
  157.                     for (Ref r : refs)
  158.                         refmap.put(r.getName(), r);
  159.                 else
  160.                     for (Ref r : refs)
  161.                         for (RefSpec rs : refSpecs)
  162.                             if (rs.matchSource(r)) {
  163.                                 refmap.put(r.getName(), r);
  164.                                 break;
  165.                             }
  166.                 return refmap;
  167.             }
  168.         } catch (URISyntaxException e) {
  169.             throw new InvalidRemoteException(MessageFormat.format(
  170.                     JGitText.get().invalidRemote, remote), e);
  171.         } catch (NotSupportedException e) {
  172.             throw new JGitInternalException(
  173.                     JGitText.get().exceptionCaughtDuringExecutionOfLsRemoteCommand,
  174.                     e);
  175.         } catch (IOException | ConfigInvalidException e) {
  176.             throw new org.eclipse.jgit.api.errors.TransportException(
  177.                     e.getMessage(), e);
  178.         }
  179.     }

  180.     private String translate(String uri)
  181.             throws IOException, ConfigInvalidException {
  182.         UrlConfig urls = new UrlConfig(
  183.                 SystemReader.getInstance().getUserConfig());
  184.         return urls.replace(uri);
  185.     }
  186. }