]> source.dussan.org Git - jgit.git/commitdiff
Adapt Status and CleanCommand to support cleaning directories 72/4972/17
authorMarkus Duft <markus.duft@salomon.at>
Fri, 13 Jul 2012 06:31:10 +0000 (08:31 +0200)
committerChris Aniszczyk <zx@twitter.com>
Fri, 16 Nov 2012 20:17:28 +0000 (12:17 -0800)
This adds the possibility to:

 * retrieve untracked directories from the status
 * instruct the CleanCommand to clean those directories.
 * retrieve ignored paths from the status
 * instruct the CleanCommand to leave those ignored paths alone

Bug: 338717
Change-Id: Ibed0459005a5e306c010b9932f5b5fd107fb5448
Signed-off-by: Chris Aniszczyk <zx@twitter.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java
org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java

index 5ded3bce122ab046dbab1d121a68be7c9703d950..0405783bbb65090cec37ede5cc67d38b769f88b8 100644 (file)
@@ -71,8 +71,18 @@ public class CleanCommandTest extends RepositoryTestCase {
                writeTrashFile("File2.txt", "Delete Me");
                writeTrashFile("File3.txt", "Delete Me");
 
+               // create files in sub-directories.
+               writeTrashFile("sub-noclean/File1.txt", "Hello world");
+               writeTrashFile("sub-noclean/File2.txt", "Delete Me");
+               writeTrashFile("sub-clean/File4.txt", "Delete Me");
+               writeTrashFile("sub-noclean/Ignored.txt", "Ignored");
+               writeTrashFile(".gitignore", "/ignored-dir\n/sub-noclean/Ignored.txt");
+               writeTrashFile("ignored-dir/Ignored2.txt", "Ignored");
+
                // add and commit first file
                git.add().addFilepattern("File1.txt").call();
+               git.add().addFilepattern("sub-noclean/File1.txt").call();
+               git.add().addFilepattern(".gitignore").call();
                git.commit().setMessage("Initial commit").call();
        }
 
@@ -90,9 +100,34 @@ public class CleanCommandTest extends RepositoryTestCase {
                status = git.status().call();
                files = status.getUntracked();
 
-               assertEquals(0, files.size());
+               assertTrue(files.size() == 1); // one remains (directories not cleaned)
+               assertTrue(cleanedFiles.contains("File2.txt"));
+               assertTrue(cleanedFiles.contains("File3.txt"));
+               assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
+               assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
+               assertTrue(!cleanedFiles.contains("sub-clean/File4.txt"));
+       }
+
+       @Test
+       public void testCleanDirs() throws NoWorkTreeException, GitAPIException {
+               // create status
+               StatusCommand command = git.status();
+               Status status = command.call();
+               Set<String> files = status.getUntracked();
+               assertTrue(files.size() > 0);
+
+               // run clean
+               Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call();
+
+               status = git.status().call();
+               files = status.getUntracked();
+
+               assertTrue(files.size() == 0);
                assertTrue(cleanedFiles.contains("File2.txt"));
                assertTrue(cleanedFiles.contains("File3.txt"));
+               assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
+               assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
+               assertTrue(cleanedFiles.contains("sub-clean/"));
        }
 
        @Test
@@ -111,7 +146,7 @@ public class CleanCommandTest extends RepositoryTestCase {
 
                status = git.status().call();
                files = status.getUntracked();
-               assertEquals(1, files.size());
+               assertTrue(files.size() == 3);
                assertTrue(cleanedFiles.contains("File3.txt"));
                assertFalse(cleanedFiles.contains("File2.txt"));
        }
@@ -131,9 +166,65 @@ public class CleanCommandTest extends RepositoryTestCase {
                status = git.status().call();
                files = status.getUntracked();
 
-               assertEquals(2, files.size());
+               assertEquals(4, files.size());
                assertTrue(cleanedFiles.contains("File2.txt"));
                assertTrue(cleanedFiles.contains("File3.txt"));
+               assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
+               assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
+       }
+
+       @Test
+       public void testCleanDirsWithDryRun() throws NoWorkTreeException,
+                       GitAPIException {
+               // create status
+               StatusCommand command = git.status();
+               Status status = command.call();
+               Set<String> files = status.getUntracked();
+               assertTrue(files.size() > 0);
+
+               // run clean
+               Set<String> cleanedFiles = git.clean().setDryRun(true)
+                               .setCleanDirectories(true).call();
+
+               status = git.status().call();
+               files = status.getUntracked();
+
+               assertTrue(files.size() == 4);
+               assertTrue(cleanedFiles.contains("File2.txt"));
+               assertTrue(cleanedFiles.contains("File3.txt"));
+               assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
+               assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
+               assertTrue(cleanedFiles.contains("sub-clean/"));
+       }
+
+       @Test
+       public void testCleanWithDryRunAndNoIgnore() throws NoWorkTreeException,
+                       GitAPIException {
+               // run clean
+               Set<String> cleanedFiles = git.clean().setDryRun(true).setIgnore(false)
+                               .call();
+
+               Status status = git.status().call();
+               Set<String> files = status.getIgnoredNotInIndex();
+
+               assertTrue(files.size() == 2);
+               assertTrue(cleanedFiles.contains("sub-noclean/Ignored.txt"));
+               assertTrue(!cleanedFiles.contains("ignored-dir/"));
+       }
+
+       @Test
+       public void testCleanDirsWithDryRunAndNoIgnore()
+                       throws NoWorkTreeException, GitAPIException {
+               // run clean
+               Set<String> cleanedFiles = git.clean().setDryRun(true).setIgnore(false)
+                               .setCleanDirectories(true).call();
+
+               Status status = git.status().call();
+               Set<String> files = status.getIgnoredNotInIndex();
+
+               assertTrue(files.size() == 2);
+               assertTrue(cleanedFiles.contains("sub-noclean/Ignored.txt"));
+               assertTrue(cleanedFiles.contains("ignored-dir/"));
        }
 
 }
index c9a6048695155f4b148c1653790b53df927bf709..7856b0d8717ce2b769558a22f640237ee27db4e5 100644 (file)
@@ -44,6 +44,7 @@ package org.eclipse.jgit.api;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.io.File;
 import java.io.IOException;
@@ -125,6 +126,10 @@ public class StatusCommandTest extends RepositoryTestCase {
                assertEquals(set("a"), stat.getUntracked());
                git.commit().setMessage("t").call();
 
+               writeTrashFile("sub/a", "sub-file");
+               stat = git.status().call();
+               assertEquals(1, stat.getUntrackedFolders().size());
+               assertTrue(stat.getUntrackedFolders().contains("sub"));
        }
 
        public static Set<String> set(String... elements) {
index 1c19e937364d1475c266b0723d5cd4bad04183e1..f76d98afd3a4ef41baa617aaadc0af90827d77c2 100644 (file)
@@ -68,6 +68,10 @@ public class CleanCommand extends GitCommand<Set<String>> {
 
        private boolean dryRun;
 
+       private boolean directories;
+
+       private boolean ignore = true;
+
        /**
         * @param repo
         */
@@ -90,19 +94,82 @@ public class CleanCommand extends GitCommand<Set<String>> {
                try {
                        StatusCommand command = new StatusCommand(repo);
                        Status status = command.call();
-                       for (String file : status.getUntracked()) {
+
+                       Set<String> untrackedAndIgnoredFiles = new TreeSet<String>(
+                                       status.getUntracked());
+                       Set<String> untrackedAndIgnoredDirs = new TreeSet<String>(
+                                       status.getUntrackedFolders());
+
+                       for (String p : status.getIgnoredNotInIndex()) {
+                               File f = new File(repo.getWorkTree(), p);
+                               if (f.isFile()) {
+                                       untrackedAndIgnoredFiles.add(p);
+                               } else if (f.isDirectory()) {
+                                       untrackedAndIgnoredDirs.add(p);
+                               }
+                       }
+
+                       Set<String> filtered = filterFolders(untrackedAndIgnoredFiles,
+                                       untrackedAndIgnoredDirs);
+
+                       Set<String> notIgnoredFiles = filterIgnorePaths(filtered,
+                                       status.getIgnoredNotInIndex(), true);
+                       Set<String> notIgnoredDirs = filterIgnorePaths(
+                                       untrackedAndIgnoredDirs,
+                                       status.getIgnoredNotInIndex(), false);
+
+                       for (String file : notIgnoredFiles)
                                if (paths.isEmpty() || paths.contains(file)) {
                                        if (!dryRun)
                                                FileUtils.delete(new File(repo.getWorkTree(), file));
                                        files.add(file);
                                }
-                       }
+
+                       if (directories)
+                               for (String dir : notIgnoredDirs)
+                                       if (paths.isEmpty() || paths.contains(dir)) {
+                                               if (!dryRun)
+                                                       FileUtils.delete(new File(repo.getWorkTree(), dir),
+                                                                       FileUtils.RECURSIVE);
+                                               files.add(dir + "/");
+                                       }
                } catch (IOException e) {
                        throw new JGitInternalException(e.getMessage(), e);
                }
                return files;
        }
 
+       private Set<String> filterIgnorePaths(Set<String> inputPaths,
+                       Set<String> ignoredNotInIndex, boolean exact) {
+               if (ignore) {
+                       Set<String> filtered = new TreeSet<String>(inputPaths);
+                       for (String path : inputPaths)
+                               for (String ignored : ignoredNotInIndex)
+                                       if ((exact && path.equals(ignored))
+                                                       || (!exact && path.startsWith(ignored))) {
+                                               filtered.remove(path);
+                                               break;
+                                       }
+
+                       return filtered;
+               }
+               return inputPaths;
+       }
+
+       private Set<String> filterFolders(Set<String> untracked,
+                       Set<String> untrackedFolders) {
+               Set<String> filtered = new TreeSet<String>(untracked);
+               for (String file : untracked)
+                       for (String folder : untrackedFolders)
+                               if (file.startsWith(folder)) {
+                                       filtered.remove(file);
+                                       break;
+                               }
+
+
+               return filtered;
+       }
+
        /**
         * If paths are set, only these paths are affected by the cleaning.
         *
@@ -126,4 +193,29 @@ public class CleanCommand extends GitCommand<Set<String>> {
                this.dryRun = dryRun;
                return this;
        }
+
+       /**
+        * If dirs is set, in addition to files, also clean directories.
+        *
+        * @param dirs
+        *            whether to clean directories too, or only files.
+        * @return {@code this}
+        */
+       public CleanCommand setCleanDirectories(boolean dirs) {
+               directories = dirs;
+               return this;
+       }
+
+       /**
+        * If ignore is set, don't report/clean files/directories that are ignored
+        * by a .gitignore. otherwise do handle them.
+        *
+        * @param ignore
+        *            whether to respect .gitignore or not.
+        * @return {@code this}
+        */
+       public CleanCommand setIgnore(boolean ignore) {
+               this.ignore = ignore;
+               return this;
+       }
 }
index 8ebd279aa71d95e1c320b313f37faed1aa0db4a9..cb2ae6bf01c31df89e21972f04ef00d06a3f3827 100644 (file)
@@ -137,6 +137,13 @@ public class Status {
                return Collections.unmodifiableSet(diff.getUntracked());
        }
 
+       /**
+        * @return set of directories that are not ignored, and not in the index.
+        */
+       public Set<String> getUntrackedFolders() {
+               return Collections.unmodifiableSet(diff.getUntrackedFolders());
+       }
+
        /**
         * @return list of files that are in conflict. (e.g what you get if you
         *         modify file that was modified by someone else in the meantime)
@@ -144,4 +151,11 @@ public class Status {
        public Set<String> getConflicting() {
                return Collections.unmodifiableSet(diff.getConflicting());
        }
+
+       /**
+        * @return set of files and folders that are ignored and not in the index.
+        */
+       public Set<String> getIgnoredNotInIndex() {
+               return Collections.unmodifiableSet(diff.getIgnoredNotInIndex());
+       }
 }