HADOOP-6385. dfs should support -rmdir (was HDFS-639). Contributed by Daryn Sharp.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1150987 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Matthew Foley 2011-07-26 04:57:09 +00:00
parent 01cd616d17
commit 60e4947cc7
4 changed files with 94 additions and 6 deletions

View File

@ -60,6 +60,9 @@ Trunk (unreleased changes)
HADOOP-7460. Support pluggable trash policies. (Usman Masoon via suresh) HADOOP-7460. Support pluggable trash policies. (Usman Masoon via suresh)
HADOOP-6385. dfs should support -rmdir (was HDFS-639). (Daryn Sharp
via mattf)
IMPROVEMENTS IMPROVEMENTS
HADOOP-7042. Updates to test-patch.sh to include failed test names and HADOOP-7042. Updates to test-patch.sh to include failed test names and

View File

@ -27,6 +27,8 @@
import org.apache.hadoop.fs.Trash; import org.apache.hadoop.fs.Trash;
import org.apache.hadoop.fs.shell.PathExceptions.PathIOException; import org.apache.hadoop.fs.shell.PathExceptions.PathIOException;
import org.apache.hadoop.fs.shell.PathExceptions.PathIsDirectoryException; import org.apache.hadoop.fs.shell.PathExceptions.PathIsDirectoryException;
import org.apache.hadoop.fs.shell.PathExceptions.PathIsNotDirectoryException;
import org.apache.hadoop.fs.shell.PathExceptions.PathIsNotEmptyDirectoryException;
/** /**
* Classes that delete paths * Classes that delete paths
@ -34,9 +36,10 @@
@InterfaceAudience.Private @InterfaceAudience.Private
@InterfaceStability.Evolving @InterfaceStability.Evolving
class Delete extends FsCommand { class Delete {
public static void registerCommands(CommandFactory factory) { public static void registerCommands(CommandFactory factory) {
factory.addClass(Rm.class, "-rm"); factory.addClass(Rm.class, "-rm");
factory.addClass(Rmdir.class, "-rmdir");
factory.addClass(Rmr.class, "-rmr"); factory.addClass(Rmr.class, "-rmr");
factory.addClass(Expunge.class, "-expunge"); factory.addClass(Expunge.class, "-expunge");
} }
@ -44,26 +47,35 @@ public static void registerCommands(CommandFactory factory) {
/** remove non-directory paths */ /** remove non-directory paths */
public static class Rm extends FsCommand { public static class Rm extends FsCommand {
public static final String NAME = "rm"; public static final String NAME = "rm";
public static final String USAGE = "[-r|-R] [-skipTrash] <src> ..."; public static final String USAGE = "[-f] [-r|-R] [-skipTrash] <src> ...";
public static final String DESCRIPTION = public static final String DESCRIPTION =
"Delete all files that match the specified file pattern.\n" + "Delete all files that match the specified file pattern.\n" +
"Equivalent to the Unix command \"rm <src>\"\n" + "Equivalent to the Unix command \"rm <src>\"\n" +
"-skipTrash option bypasses trash, if enabled, and immediately\n" + "-skipTrash option bypasses trash, if enabled, and immediately\n" +
"deletes <src>\n" + "deletes <src>\n" +
" -f If the file does not exist, do not display a diagnostic\n" +
" message or modify the exit status to reflect an error.\n" +
" -[rR] Recursively deletes directories"; " -[rR] Recursively deletes directories";
private boolean skipTrash = false; private boolean skipTrash = false;
private boolean deleteDirs = false; private boolean deleteDirs = false;
private boolean ignoreFNF = false;
@Override @Override
protected void processOptions(LinkedList<String> args) throws IOException { protected void processOptions(LinkedList<String> args) throws IOException {
CommandFormat cf = new CommandFormat( CommandFormat cf = new CommandFormat(
1, Integer.MAX_VALUE, "r", "R", "skipTrash"); 1, Integer.MAX_VALUE, "f", "r", "R", "skipTrash");
cf.parse(args); cf.parse(args);
ignoreFNF = cf.getOpt("f");
deleteDirs = cf.getOpt("r") || cf.getOpt("R"); deleteDirs = cf.getOpt("r") || cf.getOpt("R");
skipTrash = cf.getOpt("skipTrash"); skipTrash = cf.getOpt("skipTrash");
} }
@Override
protected void processNonexistentPath(PathData item) throws IOException {
if (!ignoreFNF) super.processNonexistentPath(item);
}
@Override @Override
protected void processPath(PathData item) throws IOException { protected void processPath(PathData item) throws IOException {
if (item.stat.isDirectory() && !deleteDirs) { if (item.stat.isDirectory() && !deleteDirs) {
@ -113,6 +125,39 @@ public String getReplacementCommand() {
} }
} }
/** remove only empty directories */
static class Rmdir extends FsCommand {
public static final String NAME = "rmdir";
public static final String USAGE =
"[--ignore-fail-on-non-empty] <dir> ...";
public static final String DESCRIPTION =
"Removes the directory entry specified by each directory argument,\n" +
"provided it is empty.\n";
private boolean ignoreNonEmpty = false;
protected void processOptions(LinkedList<String> args) throws IOException {
CommandFormat cf = new CommandFormat(
1, Integer.MAX_VALUE, "-ignore-fail-on-non-empty");
cf.parse(args);
ignoreNonEmpty = cf.getOpt("-ignore-fail-on-non-empty");
}
@Override
protected void processPath(PathData item) throws IOException {
if (!item.stat.isDirectory()) {
throw new PathIsNotDirectoryException(item.toString());
}
if (item.fs.listStatus(item.path).length == 0) {
if (!item.fs.delete(item.path, false)) {
throw new PathIOException(item.toString());
}
} else if (!ignoreNonEmpty) {
throw new PathIsNotEmptyDirectoryException(item.toString());
}
}
}
/** empty the trash */ /** empty the trash */
static class Expunge extends FsCommand { static class Expunge extends FsCommand {
public static final String NAME = "expunge"; public static final String NAME = "expunge";

View File

@ -31,6 +31,7 @@
@InterfaceAudience.Private @InterfaceAudience.Private
@InterfaceStability.Unstable @InterfaceStability.Unstable
@SuppressWarnings("serial")
public class PathExceptions { public class PathExceptions {
/** EIO */ /** EIO */
@ -165,6 +166,14 @@ public PathIsNotDirectoryException(String path) {
} }
} }
/** Generated by rm commands */
public static class PathIsNotEmptyDirectoryException extends PathExistsException {
/** @param path for the exception */
public PathIsNotEmptyDirectoryException(String path) {
super(path, "Directory is not empty");
}
}
/** EACCES */ /** EACCES */
public static class PathAccessDeniedException extends PathIOException { public static class PathAccessDeniedException extends PathIOException {
static final long serialVersionUID = 0L; static final long serialVersionUID = 0L;

View File

@ -283,7 +283,7 @@
<comparators> <comparators>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^-rm \[-r\|-R\] \[-skipTrash\] &lt;src&gt; \.\.\.:( |\t)*Delete all files that match the specified file pattern.( )*</expected-output> <expected-output>^-rm \[-f\] \[-r\|-R\] \[-skipTrash\] &lt;src&gt; \.\.\.:( |\t)*Delete all files that match the specified file pattern.( )*</expected-output>
</comparator> </comparator>
<comparator> <comparator>
<type>RegexpComparator</type> <type>RegexpComparator</type>
@ -297,6 +297,37 @@
<type>RegexpComparator</type> <type>RegexpComparator</type>
<expected-output>^( |\t)*deletes &lt;src&gt;( )*</expected-output> <expected-output>^( |\t)*deletes &lt;src&gt;( )*</expected-output>
</comparator> </comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^\s+-f\s+If the file does not exist, do not display a diagnostic</expected-output>
</comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^\s+message or modify the exit status to reflect an error\.</expected-output>
</comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^\s+-\[rR\]\s+Recursively deletes directories</expected-output>
</comparator>
</comparators>
</test>
<test> <!-- TESTED -->
<description>help: help for rmdir</description>
<test-commands>
<command>-help rmdir</command>
</test-commands>
<cleanup-commands>
</cleanup-commands>
<comparators>
<comparator>
<type>RegexpComparator</type>
<expected-output>^-rmdir \[--ignore-fail-on-non-empty\] &lt;dir&gt; \.\.\.:\s+Removes the directory entry specified by each directory argument,</expected-output>
</comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>\s+provided it is empty.</expected-output>
</comparator>
</comparators> </comparators>
</test> </test>