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.

SubmoduleWalk.java 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /*
  2. * Copyright (C) 2011, GitHub Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.submodule;
  44. import java.io.File;
  45. import java.io.IOException;
  46. import java.text.MessageFormat;
  47. import java.util.HashMap;
  48. import java.util.Map;
  49. import org.eclipse.jgit.dircache.DirCache;
  50. import org.eclipse.jgit.dircache.DirCacheIterator;
  51. import org.eclipse.jgit.errors.ConfigInvalidException;
  52. import org.eclipse.jgit.errors.CorruptObjectException;
  53. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  54. import org.eclipse.jgit.errors.MissingObjectException;
  55. import org.eclipse.jgit.errors.RepositoryNotFoundException;
  56. import org.eclipse.jgit.internal.JGitText;
  57. import org.eclipse.jgit.lib.AnyObjectId;
  58. import org.eclipse.jgit.lib.BlobBasedConfig;
  59. import org.eclipse.jgit.lib.Config;
  60. import org.eclipse.jgit.lib.ConfigConstants;
  61. import org.eclipse.jgit.lib.Constants;
  62. import org.eclipse.jgit.lib.FileMode;
  63. import org.eclipse.jgit.lib.ObjectId;
  64. import org.eclipse.jgit.lib.Ref;
  65. import org.eclipse.jgit.lib.Repository;
  66. import org.eclipse.jgit.lib.RepositoryBuilder;
  67. import org.eclipse.jgit.lib.StoredConfig;
  68. import org.eclipse.jgit.storage.file.FileBasedConfig;
  69. import org.eclipse.jgit.treewalk.AbstractTreeIterator;
  70. import org.eclipse.jgit.treewalk.CanonicalTreeParser;
  71. import org.eclipse.jgit.treewalk.TreeWalk;
  72. import org.eclipse.jgit.treewalk.filter.PathFilter;
  73. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  74. import org.eclipse.jgit.util.FS;
  75. /**
  76. * Walker that visits all submodule entries found in a tree
  77. */
  78. public class SubmoduleWalk implements AutoCloseable {
  79. /**
  80. * The values for the config parameter submodule.<name>.ignore
  81. *
  82. * @since 3.6
  83. */
  84. public enum IgnoreSubmoduleMode {
  85. /**
  86. * Ignore all modifications to submodules
  87. */
  88. ALL,
  89. /**
  90. * Ignore changes to the working tree of a submodule
  91. */
  92. DIRTY,
  93. /**
  94. * Ignore changes to untracked files in the working tree of a submodule
  95. */
  96. UNTRACKED,
  97. /**
  98. * Ignore nothing. That's the default
  99. */
  100. NONE;
  101. }
  102. /**
  103. * Create a generator to walk over the submodule entries currently in the
  104. * index
  105. *
  106. * The {@code .gitmodules} file is read from the index.
  107. *
  108. * @param repository
  109. * a {@link org.eclipse.jgit.lib.Repository} object.
  110. * @return generator over submodule index entries. The caller is responsible
  111. * for calling {@link #close()}.
  112. * @throws java.io.IOException
  113. */
  114. public static SubmoduleWalk forIndex(Repository repository)
  115. throws IOException {
  116. @SuppressWarnings("resource") // The caller closes it
  117. SubmoduleWalk generator = new SubmoduleWalk(repository);
  118. try {
  119. DirCache index = repository.readDirCache();
  120. generator.setTree(new DirCacheIterator(index));
  121. } catch (IOException e) {
  122. generator.close();
  123. throw e;
  124. }
  125. return generator;
  126. }
  127. /**
  128. * Create a generator and advance it to the submodule entry at the given
  129. * path
  130. *
  131. * @param repository
  132. * a {@link org.eclipse.jgit.lib.Repository} object.
  133. * @param treeId
  134. * the root of a tree containing both a submodule at the given
  135. * path and .gitmodules at the root.
  136. * @param path
  137. * a {@link java.lang.String} object.
  138. * @return generator at given path, null if no submodule at given path
  139. * @throws java.io.IOException
  140. */
  141. public static SubmoduleWalk forPath(Repository repository,
  142. AnyObjectId treeId, String path) throws IOException {
  143. try (SubmoduleWalk generator = new SubmoduleWalk(repository)) {
  144. generator.setTree(treeId);
  145. PathFilter filter = PathFilter.create(path);
  146. generator.setFilter(filter);
  147. generator.setRootTree(treeId);
  148. while (generator.next()) {
  149. if (filter.isDone(generator.walk)) {
  150. return generator;
  151. }
  152. }
  153. return null;
  154. } catch (IOException e) {
  155. throw e;
  156. }
  157. }
  158. /**
  159. * Create a generator and advance it to the submodule entry at the given
  160. * path
  161. *
  162. * @param repository
  163. * a {@link org.eclipse.jgit.lib.Repository} object.
  164. * @param iterator
  165. * the root of a tree containing both a submodule at the given
  166. * path and .gitmodules at the root.
  167. * @param path
  168. * a {@link java.lang.String} object.
  169. * @return generator at given path, null if no submodule at given path
  170. * @throws java.io.IOException
  171. */
  172. public static SubmoduleWalk forPath(Repository repository,
  173. AbstractTreeIterator iterator, String path) throws IOException {
  174. try (SubmoduleWalk generator = new SubmoduleWalk(repository)) {
  175. generator.setTree(iterator);
  176. PathFilter filter = PathFilter.create(path);
  177. generator.setFilter(filter);
  178. generator.setRootTree(iterator);
  179. while (generator.next()) {
  180. if (filter.isDone(generator.walk)) {
  181. return generator;
  182. }
  183. }
  184. return null;
  185. } catch (IOException e) {
  186. throw e;
  187. }
  188. }
  189. /**
  190. * Get submodule directory
  191. *
  192. * @param parent
  193. * the {@link org.eclipse.jgit.lib.Repository}.
  194. * @param path
  195. * submodule path
  196. * @return directory
  197. */
  198. public static File getSubmoduleDirectory(final Repository parent,
  199. final String path) {
  200. return new File(parent.getWorkTree(), path);
  201. }
  202. /**
  203. * Get submodule repository
  204. *
  205. * @param parent
  206. * the {@link org.eclipse.jgit.lib.Repository}.
  207. * @param path
  208. * submodule path
  209. * @return repository or null if repository doesn't exist
  210. * @throws java.io.IOException
  211. */
  212. public static Repository getSubmoduleRepository(final Repository parent,
  213. final String path) throws IOException {
  214. return getSubmoduleRepository(parent.getWorkTree(), path,
  215. parent.getFS());
  216. }
  217. /**
  218. * Get submodule repository at path
  219. *
  220. * @param parent
  221. * the parent
  222. * @param path
  223. * submodule path
  224. * @return repository or null if repository doesn't exist
  225. * @throws java.io.IOException
  226. */
  227. public static Repository getSubmoduleRepository(final File parent,
  228. final String path) throws IOException {
  229. return getSubmoduleRepository(parent, path, FS.DETECTED);
  230. }
  231. /**
  232. * Get submodule repository at path, using the specified file system
  233. * abstraction
  234. *
  235. * @param parent
  236. * @param path
  237. * @param fs
  238. * the file system abstraction to be used
  239. * @return repository or null if repository doesn't exist
  240. * @throws IOException
  241. * @since 4.10
  242. */
  243. public static Repository getSubmoduleRepository(final File parent,
  244. final String path, FS fs) throws IOException {
  245. File subWorkTree = new File(parent, path);
  246. if (!subWorkTree.isDirectory())
  247. return null;
  248. File workTree = new File(parent, path);
  249. try {
  250. return new RepositoryBuilder() //
  251. .setMustExist(true) //
  252. .setFS(fs) //
  253. .setWorkTree(workTree) //
  254. .build();
  255. } catch (RepositoryNotFoundException e) {
  256. return null;
  257. }
  258. }
  259. /**
  260. * Resolve submodule repository URL.
  261. * <p>
  262. * This handles relative URLs that are typically specified in the
  263. * '.gitmodules' file by resolving them against the remote URL of the parent
  264. * repository.
  265. * <p>
  266. * Relative URLs will be resolved against the parent repository's working
  267. * directory if the parent repository has no configured remote URL.
  268. *
  269. * @param parent
  270. * parent repository
  271. * @param url
  272. * absolute or relative URL of the submodule repository
  273. * @return resolved URL
  274. * @throws java.io.IOException
  275. */
  276. public static String getSubmoduleRemoteUrl(final Repository parent,
  277. final String url) throws IOException {
  278. if (!url.startsWith("./") && !url.startsWith("../")) //$NON-NLS-1$ //$NON-NLS-2$
  279. return url;
  280. String remoteName = null;
  281. // Look up remote URL associated wit HEAD ref
  282. Ref ref = parent.exactRef(Constants.HEAD);
  283. if (ref != null) {
  284. if (ref.isSymbolic())
  285. ref = ref.getLeaf();
  286. remoteName = parent.getConfig().getString(
  287. ConfigConstants.CONFIG_BRANCH_SECTION,
  288. Repository.shortenRefName(ref.getName()),
  289. ConfigConstants.CONFIG_KEY_REMOTE);
  290. }
  291. // Fall back to 'origin' if current HEAD ref has no remote URL
  292. if (remoteName == null)
  293. remoteName = Constants.DEFAULT_REMOTE_NAME;
  294. String remoteUrl = parent.getConfig().getString(
  295. ConfigConstants.CONFIG_REMOTE_SECTION, remoteName,
  296. ConfigConstants.CONFIG_KEY_URL);
  297. // Fall back to parent repository's working directory if no remote URL
  298. if (remoteUrl == null) {
  299. remoteUrl = parent.getWorkTree().getAbsolutePath();
  300. // Normalize slashes to '/'
  301. if ('\\' == File.separatorChar)
  302. remoteUrl = remoteUrl.replace('\\', '/');
  303. }
  304. // Remove trailing '/'
  305. if (remoteUrl.charAt(remoteUrl.length() - 1) == '/')
  306. remoteUrl = remoteUrl.substring(0, remoteUrl.length() - 1);
  307. char separator = '/';
  308. String submoduleUrl = url;
  309. while (submoduleUrl.length() > 0) {
  310. if (submoduleUrl.startsWith("./")) //$NON-NLS-1$
  311. submoduleUrl = submoduleUrl.substring(2);
  312. else if (submoduleUrl.startsWith("../")) { //$NON-NLS-1$
  313. int lastSeparator = remoteUrl.lastIndexOf('/');
  314. if (lastSeparator < 1) {
  315. lastSeparator = remoteUrl.lastIndexOf(':');
  316. separator = ':';
  317. }
  318. if (lastSeparator < 1)
  319. throw new IOException(MessageFormat.format(
  320. JGitText.get().submoduleParentRemoteUrlInvalid,
  321. remoteUrl));
  322. remoteUrl = remoteUrl.substring(0, lastSeparator);
  323. submoduleUrl = submoduleUrl.substring(3);
  324. } else
  325. break;
  326. }
  327. return remoteUrl + separator + submoduleUrl;
  328. }
  329. private final Repository repository;
  330. private final TreeWalk walk;
  331. private StoredConfig repoConfig;
  332. private AbstractTreeIterator rootTree;
  333. private Config modulesConfig;
  334. private String path;
  335. private Map<String, String> pathToName;
  336. /**
  337. * Create submodule generator
  338. *
  339. * @param repository
  340. * the {@link org.eclipse.jgit.lib.Repository}.
  341. * @throws java.io.IOException
  342. */
  343. public SubmoduleWalk(Repository repository) throws IOException {
  344. this.repository = repository;
  345. repoConfig = repository.getConfig();
  346. walk = new TreeWalk(repository);
  347. walk.setRecursive(true);
  348. }
  349. /**
  350. * Set the config used by this walk.
  351. *
  352. * This method need only be called if constructing a walk manually instead of
  353. * with one of the static factory methods above.
  354. *
  355. * @param config
  356. * .gitmodules config object
  357. * @return this generator
  358. */
  359. public SubmoduleWalk setModulesConfig(Config config) {
  360. modulesConfig = config;
  361. loadPathNames();
  362. return this;
  363. }
  364. /**
  365. * Set the tree used by this walk for finding {@code .gitmodules}.
  366. * <p>
  367. * The root tree is not read until the first submodule is encountered by the
  368. * walk.
  369. * <p>
  370. * This method need only be called if constructing a walk manually instead of
  371. * with one of the static factory methods above.
  372. *
  373. * @param tree
  374. * tree containing .gitmodules
  375. * @return this generator
  376. */
  377. public SubmoduleWalk setRootTree(AbstractTreeIterator tree) {
  378. rootTree = tree;
  379. modulesConfig = null;
  380. pathToName = null;
  381. return this;
  382. }
  383. /**
  384. * Set the tree used by this walk for finding {@code .gitmodules}.
  385. * <p>
  386. * The root tree is not read until the first submodule is encountered by the
  387. * walk.
  388. * <p>
  389. * This method need only be called if constructing a walk manually instead of
  390. * with one of the static factory methods above.
  391. *
  392. * @param id
  393. * ID of a tree containing .gitmodules
  394. * @return this generator
  395. * @throws java.io.IOException
  396. */
  397. public SubmoduleWalk setRootTree(AnyObjectId id) throws IOException {
  398. final CanonicalTreeParser p = new CanonicalTreeParser();
  399. p.reset(walk.getObjectReader(), id);
  400. rootTree = p;
  401. modulesConfig = null;
  402. pathToName = null;
  403. return this;
  404. }
  405. /**
  406. * Load the config for this walk from {@code .gitmodules}.
  407. * <p>
  408. * Uses the root tree if {@link #setRootTree(AbstractTreeIterator)} was
  409. * previously called, otherwise uses the working tree.
  410. * <p>
  411. * If no submodule config is found, loads an empty config.
  412. *
  413. * @return this generator
  414. * @throws java.io.IOException
  415. * if an error occurred, or if the repository is bare
  416. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  417. */
  418. public SubmoduleWalk loadModulesConfig() throws IOException, ConfigInvalidException {
  419. if (rootTree == null) {
  420. File modulesFile = new File(repository.getWorkTree(),
  421. Constants.DOT_GIT_MODULES);
  422. FileBasedConfig config = new FileBasedConfig(modulesFile,
  423. repository.getFS());
  424. config.load();
  425. modulesConfig = config;
  426. loadPathNames();
  427. } else {
  428. try (TreeWalk configWalk = new TreeWalk(repository)) {
  429. configWalk.addTree(rootTree);
  430. // The root tree may be part of the submodule walk, so we need to revert
  431. // it after this walk.
  432. int idx;
  433. for (idx = 0; !rootTree.first(); idx++) {
  434. rootTree.back(1);
  435. }
  436. try {
  437. configWalk.setRecursive(false);
  438. PathFilter filter = PathFilter.create(Constants.DOT_GIT_MODULES);
  439. configWalk.setFilter(filter);
  440. while (configWalk.next()) {
  441. if (filter.isDone(configWalk)) {
  442. modulesConfig = new BlobBasedConfig(null, repository,
  443. configWalk.getObjectId(0));
  444. loadPathNames();
  445. return this;
  446. }
  447. }
  448. modulesConfig = new Config();
  449. pathToName = null;
  450. } finally {
  451. if (idx > 0)
  452. rootTree.next(idx);
  453. }
  454. }
  455. }
  456. return this;
  457. }
  458. private void loadPathNames() {
  459. pathToName = null;
  460. if (modulesConfig != null) {
  461. HashMap<String, String> pathNames = new HashMap<>();
  462. for (String name : modulesConfig
  463. .getSubsections(ConfigConstants.CONFIG_SUBMODULE_SECTION)) {
  464. pathNames.put(modulesConfig.getString(
  465. ConfigConstants.CONFIG_SUBMODULE_SECTION, name,
  466. ConfigConstants.CONFIG_KEY_PATH), name);
  467. }
  468. pathToName = pathNames;
  469. }
  470. }
  471. /**
  472. * Checks whether the working tree contains a .gitmodules file. That's a
  473. * hint that the repo contains submodules.
  474. *
  475. * @param repository
  476. * the repository to check
  477. * @return <code>true</code> if the working tree contains a .gitmodules file,
  478. * <code>false</code> otherwise. Always returns <code>false</code>
  479. * for bare repositories.
  480. * @throws java.io.IOException
  481. * @throws CorruptObjectException if any.
  482. * @since 3.6
  483. */
  484. public static boolean containsGitModulesFile(Repository repository)
  485. throws IOException {
  486. if (repository.isBare()) {
  487. return false;
  488. }
  489. File modulesFile = new File(repository.getWorkTree(),
  490. Constants.DOT_GIT_MODULES);
  491. return (modulesFile.exists());
  492. }
  493. private void lazyLoadModulesConfig() throws IOException, ConfigInvalidException {
  494. if (modulesConfig == null) {
  495. loadModulesConfig();
  496. }
  497. }
  498. private String getModuleName(String modulePath) {
  499. String name = pathToName != null ? pathToName.get(modulePath) : null;
  500. return name != null ? name : modulePath;
  501. }
  502. /**
  503. * Set tree filter
  504. *
  505. * @param filter
  506. * a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} object.
  507. * @return this generator
  508. */
  509. public SubmoduleWalk setFilter(TreeFilter filter) {
  510. walk.setFilter(filter);
  511. return this;
  512. }
  513. /**
  514. * Set the tree iterator used for finding submodule entries
  515. *
  516. * @param iterator
  517. * an {@link org.eclipse.jgit.treewalk.AbstractTreeIterator}
  518. * object.
  519. * @return this generator
  520. * @throws org.eclipse.jgit.errors.CorruptObjectException
  521. */
  522. public SubmoduleWalk setTree(AbstractTreeIterator iterator)
  523. throws CorruptObjectException {
  524. walk.addTree(iterator);
  525. return this;
  526. }
  527. /**
  528. * Set the tree used for finding submodule entries
  529. *
  530. * @param treeId
  531. * an {@link org.eclipse.jgit.lib.AnyObjectId} object.
  532. * @return this generator
  533. * @throws java.io.IOException
  534. * @throws IncorrectObjectTypeException
  535. * if any.
  536. * @throws MissingObjectException
  537. * if any.
  538. */
  539. public SubmoduleWalk setTree(AnyObjectId treeId) throws IOException {
  540. walk.addTree(treeId);
  541. return this;
  542. }
  543. /**
  544. * Reset generator and start new submodule walk
  545. *
  546. * @return this generator
  547. */
  548. public SubmoduleWalk reset() {
  549. repoConfig = repository.getConfig();
  550. modulesConfig = null;
  551. pathToName = null;
  552. walk.reset();
  553. return this;
  554. }
  555. /**
  556. * Get directory that will be the root of the submodule's local repository
  557. *
  558. * @return submodule repository directory
  559. */
  560. public File getDirectory() {
  561. return getSubmoduleDirectory(repository, path);
  562. }
  563. /**
  564. * Advance to next submodule in the index tree.
  565. *
  566. * The object id and path of the next entry can be obtained by calling
  567. * {@link #getObjectId()} and {@link #getPath()}.
  568. *
  569. * @return true if entry found, false otherwise
  570. * @throws java.io.IOException
  571. */
  572. public boolean next() throws IOException {
  573. while (walk.next()) {
  574. if (FileMode.GITLINK != walk.getFileMode(0))
  575. continue;
  576. path = walk.getPathString();
  577. return true;
  578. }
  579. path = null;
  580. return false;
  581. }
  582. /**
  583. * Get path of current submodule entry
  584. *
  585. * @return path
  586. */
  587. public String getPath() {
  588. return path;
  589. }
  590. /**
  591. * The module name for the current submodule entry (used for the section name of .git/config)
  592. * @since 4.10
  593. * @return name
  594. */
  595. public String getModuleName() {
  596. return getModuleName(path);
  597. }
  598. /**
  599. * Get object id of current submodule entry
  600. *
  601. * @return object id
  602. */
  603. public ObjectId getObjectId() {
  604. return walk.getObjectId(0);
  605. }
  606. /**
  607. * Get the configured path for current entry. This will be the value from
  608. * the .gitmodules file in the current repository's working tree.
  609. *
  610. * @return configured path
  611. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  612. * @throws java.io.IOException
  613. */
  614. public String getModulesPath() throws IOException, ConfigInvalidException {
  615. lazyLoadModulesConfig();
  616. return modulesConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  617. getModuleName(), ConfigConstants.CONFIG_KEY_PATH);
  618. }
  619. /**
  620. * Get the configured remote URL for current entry. This will be the value
  621. * from the repository's config.
  622. *
  623. * @return configured URL
  624. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  625. * @throws java.io.IOException
  626. */
  627. public String getConfigUrl() throws IOException, ConfigInvalidException {
  628. return repoConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  629. getModuleName(), ConfigConstants.CONFIG_KEY_URL);
  630. }
  631. /**
  632. * Get the configured remote URL for current entry. This will be the value
  633. * from the .gitmodules file in the current repository's working tree.
  634. *
  635. * @return configured URL
  636. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  637. * @throws java.io.IOException
  638. */
  639. public String getModulesUrl() throws IOException, ConfigInvalidException {
  640. lazyLoadModulesConfig();
  641. return modulesConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  642. getModuleName(), ConfigConstants.CONFIG_KEY_URL);
  643. }
  644. /**
  645. * Get the configured update field for current entry. This will be the value
  646. * from the repository's config.
  647. *
  648. * @return update value
  649. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  650. * @throws java.io.IOException
  651. */
  652. public String getConfigUpdate() throws IOException, ConfigInvalidException {
  653. return repoConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  654. getModuleName(), ConfigConstants.CONFIG_KEY_UPDATE);
  655. }
  656. /**
  657. * Get the configured update field for current entry. This will be the value
  658. * from the .gitmodules file in the current repository's working tree.
  659. *
  660. * @return update value
  661. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  662. * @throws java.io.IOException
  663. */
  664. public String getModulesUpdate() throws IOException, ConfigInvalidException {
  665. lazyLoadModulesConfig();
  666. return modulesConfig.getString(ConfigConstants.CONFIG_SUBMODULE_SECTION,
  667. getModuleName(), ConfigConstants.CONFIG_KEY_UPDATE);
  668. }
  669. /**
  670. * Get the configured ignore field for the current entry. This will be the
  671. * value from the .gitmodules file in the current repository's working tree.
  672. *
  673. * @return ignore value
  674. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  675. * @throws java.io.IOException
  676. * @since 3.6
  677. */
  678. public IgnoreSubmoduleMode getModulesIgnore() throws IOException,
  679. ConfigInvalidException {
  680. lazyLoadModulesConfig();
  681. return modulesConfig.getEnum(IgnoreSubmoduleMode.values(),
  682. ConfigConstants.CONFIG_SUBMODULE_SECTION, getModuleName(),
  683. ConfigConstants.CONFIG_KEY_IGNORE, IgnoreSubmoduleMode.NONE);
  684. }
  685. /**
  686. * Get repository for current submodule entry
  687. *
  688. * @return repository or null if non-existent
  689. * @throws java.io.IOException
  690. */
  691. public Repository getRepository() throws IOException {
  692. return getSubmoduleRepository(repository, path);
  693. }
  694. /**
  695. * Get commit id that HEAD points to in the current submodule's repository
  696. *
  697. * @return object id of HEAD reference
  698. * @throws java.io.IOException
  699. */
  700. public ObjectId getHead() throws IOException {
  701. try (Repository subRepo = getRepository()) {
  702. if (subRepo == null) {
  703. return null;
  704. }
  705. return subRepo.resolve(Constants.HEAD);
  706. }
  707. }
  708. /**
  709. * Get ref that HEAD points to in the current submodule's repository
  710. *
  711. * @return ref name, null on failures
  712. * @throws java.io.IOException
  713. */
  714. public String getHeadRef() throws IOException {
  715. try (Repository subRepo = getRepository()) {
  716. if (subRepo == null) {
  717. return null;
  718. }
  719. Ref head = subRepo.exactRef(Constants.HEAD);
  720. return head != null ? head.getLeaf().getName() : null;
  721. }
  722. }
  723. /**
  724. * Get the resolved remote URL for the current submodule.
  725. * <p>
  726. * This method resolves the value of {@link #getModulesUrl()} to an absolute
  727. * URL
  728. *
  729. * @return resolved remote URL
  730. * @throws java.io.IOException
  731. * @throws org.eclipse.jgit.errors.ConfigInvalidException
  732. */
  733. public String getRemoteUrl() throws IOException, ConfigInvalidException {
  734. String url = getModulesUrl();
  735. return url != null ? getSubmoduleRemoteUrl(repository, url) : null;
  736. }
  737. /**
  738. * {@inheritDoc}
  739. * <p>
  740. * Release any resources used by this walker's reader.
  741. *
  742. * @since 4.0
  743. */
  744. @Override
  745. public void close() {
  746. walk.close();
  747. }
  748. }