SubmoduleSyncCommand.java

  1. /*
  2.  * Copyright (C) 2011, GitHub Inc. 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.util.ArrayList;
  13. import java.util.Collection;
  14. import java.util.HashMap;
  15. import java.util.Map;

  16. import org.eclipse.jgit.api.errors.GitAPIException;
  17. import org.eclipse.jgit.api.errors.JGitInternalException;
  18. import org.eclipse.jgit.errors.ConfigInvalidException;
  19. import org.eclipse.jgit.lib.ConfigConstants;
  20. import org.eclipse.jgit.lib.Constants;
  21. import org.eclipse.jgit.lib.Ref;
  22. import org.eclipse.jgit.lib.Repository;
  23. import org.eclipse.jgit.lib.StoredConfig;
  24. import org.eclipse.jgit.submodule.SubmoduleWalk;
  25. import org.eclipse.jgit.treewalk.filter.PathFilterGroup;

  26. /**
  27.  * A class used to execute a submodule sync command.
  28.  *
  29.  * This will set the remote URL in a submodule's repository to the current value
  30.  * in the .gitmodules file.
  31.  *
  32.  * @see <a href=
  33.  *      "http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
  34.  *      >Git documentation about submodules</a>
  35.  */
  36. public class SubmoduleSyncCommand extends GitCommand<Map<String, String>> {

  37.     private final Collection<String> paths;

  38.     /**
  39.      * Constructor for SubmoduleSyncCommand.
  40.      *
  41.      * @param repo
  42.      *            a {@link org.eclipse.jgit.lib.Repository} object.
  43.      */
  44.     public SubmoduleSyncCommand(Repository repo) {
  45.         super(repo);
  46.         paths = new ArrayList<>();
  47.     }

  48.     /**
  49.      * Add repository-relative submodule path to synchronize
  50.      *
  51.      * @param path
  52.      *            (with <code>/</code> as separator)
  53.      * @return this command
  54.      */
  55.     public SubmoduleSyncCommand addPath(String path) {
  56.         paths.add(path);
  57.         return this;
  58.     }

  59.     /**
  60.      * Get branch that HEAD currently points to
  61.      *
  62.      * @param subRepo
  63.      *            a {@link org.eclipse.jgit.lib.Repository} object.
  64.      * @return shortened branch name, null on failures
  65.      * @throws java.io.IOException
  66.      */
  67.     protected String getHeadBranch(Repository subRepo) throws IOException {
  68.         Ref head = subRepo.exactRef(Constants.HEAD);
  69.         if (head != null && head.isSymbolic()) {
  70.             return Repository.shortenRefName(head.getLeaf().getName());
  71.         }
  72.         return null;
  73.     }

  74.     /** {@inheritDoc} */
  75.     @Override
  76.     public Map<String, String> call() throws GitAPIException {
  77.         checkCallable();

  78.         try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
  79.             if (!paths.isEmpty())
  80.                 generator.setFilter(PathFilterGroup.createFromStrings(paths));
  81.             Map<String, String> synced = new HashMap<>();
  82.             StoredConfig config = repo.getConfig();
  83.             while (generator.next()) {
  84.                 String remoteUrl = generator.getRemoteUrl();
  85.                 if (remoteUrl == null)
  86.                     continue;

  87.                 String path = generator.getPath();
  88.                 config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  89.                         path, ConfigConstants.CONFIG_KEY_URL, remoteUrl);
  90.                 synced.put(path, remoteUrl);

  91.                 try (Repository subRepo = generator.getRepository()) {
  92.                     if (subRepo == null) {
  93.                         continue;
  94.                     }

  95.                     StoredConfig subConfig;
  96.                     String branch;

  97.                     subConfig = subRepo.getConfig();
  98.                     // Get name of remote associated with current branch and
  99.                     // fall back to default remote name as last resort
  100.                     branch = getHeadBranch(subRepo);
  101.                     String remote = null;
  102.                     if (branch != null) {
  103.                         remote = subConfig.getString(
  104.                                 ConfigConstants.CONFIG_BRANCH_SECTION, branch,
  105.                                 ConfigConstants.CONFIG_KEY_REMOTE);
  106.                     }
  107.                     if (remote == null) {
  108.                         remote = Constants.DEFAULT_REMOTE_NAME;
  109.                     }

  110.                     subConfig.setString(ConfigConstants.CONFIG_REMOTE_SECTION,
  111.                             remote, ConfigConstants.CONFIG_KEY_URL, remoteUrl);
  112.                     subConfig.save();
  113.                 }
  114.             }
  115.             if (!synced.isEmpty())
  116.                 config.save();
  117.             return synced;
  118.         } catch (IOException | ConfigInvalidException e) {
  119.             throw new JGitInternalException(e.getMessage(), e);
  120.         }
  121.     }
  122. }