From f64237d5ff240cd62179f25fac7c40a9ffd5b2b8 Mon Sep 17 00:00:00 2001 From: Markus Duft Date: Fri, 13 Jul 2012 08:31:10 +0200 Subject: Adapt Status and CleanCommand to support cleaning directories 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 --- .../tst/org/eclipse/jgit/api/CleanCommandTest.java | 97 +++++++++++++++++++++- .../org/eclipse/jgit/api/StatusCommandTest.java | 5 ++ .../src/org/eclipse/jgit/api/CleanCommand.java | 96 ++++++++++++++++++++- .../src/org/eclipse/jgit/api/Status.java | 14 ++++ 4 files changed, 207 insertions(+), 5 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java index 5ded3bce12..0405783bbb 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CleanCommandTest.java @@ -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 files = status.getUntracked(); + assertTrue(files.size() > 0); + + // run clean + Set 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 files = status.getUntracked(); + assertTrue(files.size() > 0); + + // run clean + Set 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 cleanedFiles = git.clean().setDryRun(true).setIgnore(false) + .call(); + + Status status = git.status().call(); + Set 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 cleanedFiles = git.clean().setDryRun(true).setIgnore(false) + .setCleanDirectories(true).call(); + + Status status = git.status().call(); + Set files = status.getIgnoredNotInIndex(); + + assertTrue(files.size() == 2); + assertTrue(cleanedFiles.contains("sub-noclean/Ignored.txt")); + assertTrue(cleanedFiles.contains("ignored-dir/")); } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java index c9a6048695..7856b0d871 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StatusCommandTest.java @@ -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 set(String... elements) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java index 1c19e93736..f76d98afd3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CleanCommand.java @@ -68,6 +68,10 @@ public class CleanCommand extends GitCommand> { private boolean dryRun; + private boolean directories; + + private boolean ignore = true; + /** * @param repo */ @@ -90,19 +94,82 @@ public class CleanCommand extends GitCommand> { try { StatusCommand command = new StatusCommand(repo); Status status = command.call(); - for (String file : status.getUntracked()) { + + Set untrackedAndIgnoredFiles = new TreeSet( + status.getUntracked()); + Set untrackedAndIgnoredDirs = new TreeSet( + 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 filtered = filterFolders(untrackedAndIgnoredFiles, + untrackedAndIgnoredDirs); + + Set notIgnoredFiles = filterIgnorePaths(filtered, + status.getIgnoredNotInIndex(), true); + Set 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 filterIgnorePaths(Set inputPaths, + Set ignoredNotInIndex, boolean exact) { + if (ignore) { + Set filtered = new TreeSet(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 filterFolders(Set untracked, + Set untrackedFolders) { + Set filtered = new TreeSet(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> { 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; + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java index 8ebd279aa7..cb2ae6bf01 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/Status.java @@ -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 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 getConflicting() { return Collections.unmodifiableSet(diff.getConflicting()); } + + /** + * @return set of files and folders that are ignored and not in the index. + */ + public Set getIgnoredNotInIndex() { + return Collections.unmodifiableSet(diff.getIgnoredNotInIndex()); + } } -- cgit v1.2.3