You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SubmoduleAddCommand.java 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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.File;
  12. import java.io.IOException;
  13. import java.text.MessageFormat;
  14. import org.eclipse.jgit.api.errors.GitAPIException;
  15. import org.eclipse.jgit.api.errors.JGitInternalException;
  16. import org.eclipse.jgit.api.errors.NoFilepatternException;
  17. import org.eclipse.jgit.errors.ConfigInvalidException;
  18. import org.eclipse.jgit.internal.JGitText;
  19. import org.eclipse.jgit.internal.submodule.SubmoduleValidator;
  20. import org.eclipse.jgit.lib.ConfigConstants;
  21. import org.eclipse.jgit.lib.Constants;
  22. import org.eclipse.jgit.lib.NullProgressMonitor;
  23. import org.eclipse.jgit.lib.ProgressMonitor;
  24. import org.eclipse.jgit.lib.Repository;
  25. import org.eclipse.jgit.lib.StoredConfig;
  26. import org.eclipse.jgit.storage.file.FileBasedConfig;
  27. import org.eclipse.jgit.submodule.SubmoduleWalk;
  28. import org.eclipse.jgit.treewalk.filter.PathFilter;
  29. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  30. /**
  31. * A class used to execute a submodule add command.
  32. *
  33. * This will clone the configured submodule, register the submodule in the
  34. * .gitmodules file and the repository config file, and also add the submodule
  35. * and .gitmodules file to the index.
  36. *
  37. * @see <a href=
  38. * "http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"
  39. * >Git documentation about submodules</a>
  40. */
  41. public class SubmoduleAddCommand extends
  42. TransportCommand<SubmoduleAddCommand, Repository> {
  43. private String name;
  44. private String path;
  45. private String uri;
  46. private ProgressMonitor monitor;
  47. /**
  48. * Constructor for SubmoduleAddCommand.
  49. *
  50. * @param repo
  51. * a {@link org.eclipse.jgit.lib.Repository} object.
  52. */
  53. public SubmoduleAddCommand(Repository repo) {
  54. super(repo);
  55. }
  56. /**
  57. * Set the submodule name
  58. *
  59. * @param name
  60. * @return this command
  61. * @since 5.1
  62. */
  63. public SubmoduleAddCommand setName(String name) {
  64. this.name = name;
  65. return this;
  66. }
  67. /**
  68. * Set repository-relative path of submodule
  69. *
  70. * @param path
  71. * (with <code>/</code> as separator)
  72. * @return this command
  73. */
  74. public SubmoduleAddCommand setPath(String path) {
  75. this.path = path;
  76. return this;
  77. }
  78. /**
  79. * Set URI to clone submodule from
  80. *
  81. * @param uri
  82. * a {@link java.lang.String} object.
  83. * @return this command
  84. */
  85. public SubmoduleAddCommand setURI(String uri) {
  86. this.uri = uri;
  87. return this;
  88. }
  89. /**
  90. * The progress monitor associated with the clone operation. By default,
  91. * this is set to <code>NullProgressMonitor</code>
  92. *
  93. * @see NullProgressMonitor
  94. * @param monitor
  95. * a {@link org.eclipse.jgit.lib.ProgressMonitor} object.
  96. * @return this command
  97. */
  98. public SubmoduleAddCommand setProgressMonitor(ProgressMonitor monitor) {
  99. this.monitor = monitor;
  100. return this;
  101. }
  102. /**
  103. * Is the configured already a submodule in the index?
  104. *
  105. * @return true if submodule exists in index, false otherwise
  106. * @throws java.io.IOException
  107. */
  108. protected boolean submoduleExists() throws IOException {
  109. TreeFilter filter = PathFilter.create(path);
  110. try (SubmoduleWalk w = SubmoduleWalk.forIndex(repo)) {
  111. return w.setFilter(filter).next();
  112. }
  113. }
  114. /**
  115. * {@inheritDoc}
  116. * <p>
  117. * Executes the {@code SubmoduleAddCommand}
  118. *
  119. * The {@code Repository} instance returned by this command needs to be
  120. * closed by the caller to free resources held by the {@code Repository}
  121. * instance. It is recommended to call this method as soon as you don't need
  122. * a reference to this {@code Repository} instance anymore.
  123. */
  124. @Override
  125. public Repository call() throws GitAPIException {
  126. checkCallable();
  127. if (path == null || path.length() == 0)
  128. throw new IllegalArgumentException(JGitText.get().pathNotConfigured);
  129. if (uri == null || uri.length() == 0)
  130. throw new IllegalArgumentException(JGitText.get().uriNotConfigured);
  131. if (name == null || name.length() == 0) {
  132. // Use the path as the default.
  133. name = path;
  134. }
  135. try {
  136. SubmoduleValidator.assertValidSubmoduleName(name);
  137. SubmoduleValidator.assertValidSubmodulePath(path);
  138. SubmoduleValidator.assertValidSubmoduleUri(uri);
  139. } catch (SubmoduleValidator.SubmoduleValidationException e) {
  140. throw new IllegalArgumentException(e.getMessage());
  141. }
  142. try {
  143. if (submoduleExists())
  144. throw new JGitInternalException(MessageFormat.format(
  145. JGitText.get().submoduleExists, path));
  146. } catch (IOException e) {
  147. throw new JGitInternalException(e.getMessage(), e);
  148. }
  149. final String resolvedUri;
  150. try {
  151. resolvedUri = SubmoduleWalk.getSubmoduleRemoteUrl(repo, uri);
  152. } catch (IOException e) {
  153. throw new JGitInternalException(e.getMessage(), e);
  154. }
  155. // Clone submodule repository
  156. File moduleDirectory = SubmoduleWalk.getSubmoduleDirectory(repo, path);
  157. CloneCommand clone = Git.cloneRepository();
  158. configure(clone);
  159. clone.setDirectory(moduleDirectory);
  160. clone.setGitDir(new File(new File(repo.getDirectory(),
  161. Constants.MODULES), path));
  162. clone.setURI(resolvedUri);
  163. if (monitor != null)
  164. clone.setProgressMonitor(monitor);
  165. Repository subRepo = null;
  166. try (Git git = clone.call()) {
  167. subRepo = git.getRepository();
  168. subRepo.incrementOpen();
  169. }
  170. // Save submodule URL to parent repository's config
  171. StoredConfig config = repo.getConfig();
  172. config.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION, name,
  173. ConfigConstants.CONFIG_KEY_URL, resolvedUri);
  174. try {
  175. config.save();
  176. } catch (IOException e) {
  177. throw new JGitInternalException(e.getMessage(), e);
  178. }
  179. // Save path and URL to parent repository's .gitmodules file
  180. FileBasedConfig modulesConfig = new FileBasedConfig(new File(
  181. repo.getWorkTree(), Constants.DOT_GIT_MODULES), repo.getFS());
  182. try {
  183. modulesConfig.load();
  184. modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  185. name, ConfigConstants.CONFIG_KEY_PATH, path);
  186. modulesConfig.setString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  187. name, ConfigConstants.CONFIG_KEY_URL, uri);
  188. modulesConfig.save();
  189. } catch (IOException | ConfigInvalidException e) {
  190. throw new JGitInternalException(e.getMessage(), e);
  191. }
  192. AddCommand add = new AddCommand(repo);
  193. // Add .gitmodules file to parent repository's index
  194. add.addFilepattern(Constants.DOT_GIT_MODULES);
  195. // Add submodule directory to parent repository's index
  196. add.addFilepattern(path);
  197. try {
  198. add.call();
  199. } catch (NoFilepatternException e) {
  200. throw new JGitInternalException(e.getMessage(), e);
  201. }
  202. return subRepo;
  203. }
  204. }