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.

RmCommand.java 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * Copyright (C) 2010, 2012 Chris Aniszczyk <caniszczyk@gmail.com> 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.util.ArrayList;
  14. import java.util.Collection;
  15. import java.util.LinkedList;
  16. import java.util.List;
  17. import org.eclipse.jgit.api.errors.GitAPIException;
  18. import org.eclipse.jgit.api.errors.JGitInternalException;
  19. import org.eclipse.jgit.api.errors.NoFilepatternException;
  20. import org.eclipse.jgit.dircache.DirCache;
  21. import org.eclipse.jgit.dircache.DirCacheBuildIterator;
  22. import org.eclipse.jgit.dircache.DirCacheBuilder;
  23. import org.eclipse.jgit.events.WorkingTreeModifiedEvent;
  24. import org.eclipse.jgit.internal.JGitText;
  25. import org.eclipse.jgit.lib.Constants;
  26. import org.eclipse.jgit.lib.FileMode;
  27. import org.eclipse.jgit.lib.Repository;
  28. import org.eclipse.jgit.treewalk.TreeWalk;
  29. import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
  30. /**
  31. * Remove files from the index and working directory (or optionally only from
  32. * the index).
  33. * <p>
  34. * It has setters for all supported options and arguments of this command and a
  35. * {@link #call()} method to finally execute the command. Each instance of this
  36. * class should only be used for one invocation of the command (means: one call
  37. * to {@link #call()}).
  38. * <p>
  39. * Examples (<code>git</code> is a {@link org.eclipse.jgit.api.Git} instance):
  40. * <p>
  41. * Remove file "test.txt" from both index and working directory:
  42. *
  43. * <pre>
  44. * git.rm().addFilepattern(&quot;test.txt&quot;).call();
  45. * </pre>
  46. * <p>
  47. * Remove file "new.txt" from the index (but not from the working directory):
  48. *
  49. * <pre>
  50. * git.rm().setCached(true).addFilepattern(&quot;new.txt&quot;).call();
  51. * </pre>
  52. *
  53. * @see <a href="http://www.kernel.org/pub/software/scm/git/docs/git-rm.html"
  54. * >Git documentation about Rm</a>
  55. */
  56. public class RmCommand extends GitCommand<DirCache> {
  57. private Collection<String> filepatterns;
  58. /** Only remove files from index, not from working directory */
  59. private boolean cached = false;
  60. /**
  61. * Constructor for RmCommand.
  62. *
  63. * @param repo
  64. * the {@link org.eclipse.jgit.lib.Repository}
  65. */
  66. public RmCommand(Repository repo) {
  67. super(repo);
  68. filepatterns = new LinkedList<>();
  69. }
  70. /**
  71. * Add file name pattern of files to be removed
  72. *
  73. * @param filepattern
  74. * repository-relative path of file to remove (with
  75. * <code>/</code> as separator)
  76. * @return {@code this}
  77. */
  78. public RmCommand addFilepattern(String filepattern) {
  79. checkCallable();
  80. filepatterns.add(filepattern);
  81. return this;
  82. }
  83. /**
  84. * Only remove the specified files from the index.
  85. *
  86. * @param cached
  87. * {@code true} if files should only be removed from index,
  88. * {@code false} if files should also be deleted from the working
  89. * directory
  90. * @return {@code this}
  91. * @since 2.2
  92. */
  93. public RmCommand setCached(boolean cached) {
  94. checkCallable();
  95. this.cached = cached;
  96. return this;
  97. }
  98. /**
  99. * {@inheritDoc}
  100. * <p>
  101. * Executes the {@code Rm} command. Each instance of this class should only
  102. * be used for one invocation of the command. Don't call this method twice
  103. * on an instance.
  104. */
  105. @Override
  106. public DirCache call() throws GitAPIException,
  107. NoFilepatternException {
  108. if (filepatterns.isEmpty())
  109. throw new NoFilepatternException(JGitText.get().atLeastOnePatternIsRequired);
  110. checkCallable();
  111. DirCache dc = null;
  112. List<String> actuallyDeletedFiles = new ArrayList<>();
  113. try (TreeWalk tw = new TreeWalk(repo)) {
  114. dc = repo.lockDirCache();
  115. DirCacheBuilder builder = dc.builder();
  116. tw.reset(); // drop the first empty tree, which we do not need here
  117. tw.setRecursive(true);
  118. tw.setFilter(PathFilterGroup.createFromStrings(filepatterns));
  119. tw.addTree(new DirCacheBuildIterator(builder));
  120. while (tw.next()) {
  121. if (!cached) {
  122. final FileMode mode = tw.getFileMode(0);
  123. if (mode.getObjectType() == Constants.OBJ_BLOB) {
  124. String relativePath = tw.getPathString();
  125. final File path = new File(repo.getWorkTree(),
  126. relativePath);
  127. // Deleting a blob is simply a matter of removing
  128. // the file or symlink named by the tree entry.
  129. if (delete(path)) {
  130. actuallyDeletedFiles.add(relativePath);
  131. }
  132. }
  133. }
  134. }
  135. builder.commit();
  136. setCallable(false);
  137. } catch (IOException e) {
  138. throw new JGitInternalException(
  139. JGitText.get().exceptionCaughtDuringExecutionOfRmCommand, e);
  140. } finally {
  141. try {
  142. if (dc != null) {
  143. dc.unlock();
  144. }
  145. } finally {
  146. if (!actuallyDeletedFiles.isEmpty()) {
  147. repo.fireEvent(new WorkingTreeModifiedEvent(null,
  148. actuallyDeletedFiles));
  149. }
  150. }
  151. }
  152. return dc;
  153. }
  154. private boolean delete(File p) {
  155. boolean deleted = false;
  156. while (p != null && !p.equals(repo.getWorkTree()) && p.delete()) {
  157. deleted = true;
  158. p = p.getParentFile();
  159. }
  160. return deleted;
  161. }
  162. }