diff --git a/CHANGES.txt b/CHANGES.txt index 5b3418c035..b24f487778 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -141,6 +141,9 @@ Trunk (unreleased changes) HADOOP-7272. Remove unnecessary security related info logs. (suresh) + HADOOP-7275. Refactor the stat commands to conform to new FsCommand + class. (Daryn Sharp via szetszwo) + OPTIMIZATIONS BUG FIXES diff --git a/src/java/org/apache/hadoop/fs/FsShell.java b/src/java/org/apache/hadoop/fs/FsShell.java index 273f06f75b..a429263e6b 100644 --- a/src/java/org/apache/hadoop/fs/FsShell.java +++ b/src/java/org/apache/hadoop/fs/FsShell.java @@ -25,9 +25,7 @@ import java.net.URI; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.List; -import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -61,12 +59,8 @@ public class FsShell extends Configured implements Tool { public static final SimpleDateFormat dateForm = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - protected static final SimpleDateFormat modifFmt = - new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); static final int BORDER = 2; - static { - modifFmt.setTimeZone(TimeZone.getTimeZone("UTC")); - } + static final String GET_SHORT_USAGE = "-get [-ignoreCrc] [-crc] "; static final String COPYTOLOCAL_SHORT_USAGE = GET_SHORT_USAGE.replace( "-get", "-copyToLocal"); @@ -485,62 +479,6 @@ public class FsShell extends Configured implements Tool { } } - /** - * Print statistics about path in specified format. - * Format sequences: - * %b: Size of file in blocks - * %n: Filename - * %o: Block size - * %r: replication - * %y: UTC date as "yyyy-MM-dd HH:mm:ss" - * %Y: Milliseconds since January 1, 1970 UTC - */ - void stat(char[] fmt, String src) throws IOException { - Path srcPath = new Path(src); - FileSystem srcFs = srcPath.getFileSystem(getConf()); - FileStatus glob[] = srcFs.globStatus(srcPath); - if (null == glob) - throw new PathNotFoundException(src); - for (FileStatus f : glob) { - StringBuilder buf = new StringBuilder(); - for (int i = 0; i < fmt.length; ++i) { - if (fmt[i] != '%') { - buf.append(fmt[i]); - } else { - if (i + 1 == fmt.length) break; - switch(fmt[++i]) { - case 'b': - buf.append(f.getLen()); - break; - case 'F': - buf.append(f.isDirectory() ? "directory" - : (f.isFile() ? "regular file" : "symlink")); - break; - case 'n': - buf.append(f.getPath().getName()); - break; - case 'o': - buf.append(f.getBlockSize()); - break; - case 'r': - buf.append(f.getReplication()); - break; - case 'y': - buf.append(modifFmt.format(new Date(f.getModificationTime()))); - break; - case 'Y': - buf.append(f.getModificationTime()); - break; - default: - buf.append(fmt[i]); - break; - } - } - } - System.out.println(buf.toString()); - } - } - /** * Move files that match the file pattern srcf * to a destination file. @@ -827,7 +765,7 @@ public class FsShell extends Configured implements Tool { GET_SHORT_USAGE + "\n\t" + "[" + COPYTOLOCAL_SHORT_USAGE + "] [-moveToLocal ]\n\t" + "[-report]\n\t" + - "[-touchz ] [-test -[ezd] ] [-stat [format] ]"; + "[-touchz ] [-test -[ezd] ]"; String conf ="-conf : Specify an application configuration file."; @@ -907,10 +845,6 @@ public class FsShell extends Configured implements Tool { String test = "-test -[ezd] : If file { exists, has zero length, is a directory\n" + "\t\tthen return 0, else return 1.\n"; - String stat = "-stat [format] : Print statistics about the file/directory at \n" + - "\t\tin the specified format. Format accepts filesize in blocks (%b), filename (%n),\n" + - "\t\tblock size (%o), replication (%r), modification date (%y, %Y)\n"; - String expunge = "-expunge: Empty the Trash.\n"; String help = "-help [cmd]: \tDisplays help for given command or all commands if none\n" + @@ -959,8 +893,6 @@ public class FsShell extends Configured implements Tool { System.out.println(touchz); } else if ("test".equals(cmd)) { System.out.println(test); - } else if ("stat".equals(cmd)) { - System.out.println(stat); } else if ("help".equals(cmd)) { System.out.println(help); } else { @@ -987,7 +919,6 @@ public class FsShell extends Configured implements Tool { System.out.println(moveToLocal); System.out.println(touchz); System.out.println(test); - System.out.println(stat); for (String thisCmdName : commandFactory.getNames()) { printHelp(commandFactory.getInstance(thisCmdName)); @@ -1101,9 +1032,6 @@ public class FsShell extends Configured implements Tool { } else if ("-test".equals(cmd)) { System.err.println("Usage: java FsShell" + " [-test -[ezd] ]"); - } else if ("-stat".equals(cmd)) { - System.err.println("Usage: java FsShell" + - " [-stat [format] ]"); } else { System.err.println("Usage: java FsShell"); System.err.println(" [-df []]"); @@ -1122,7 +1050,6 @@ public class FsShell extends Configured implements Tool { System.err.println(" [-moveToLocal [-crc] ]"); System.err.println(" [-touchz ]"); System.err.println(" [-test -[ezd] ]"); - System.err.println(" [-stat [format] ]"); for (String name : commandFactory.getNames()) { instance = commandFactory.getInstance(name); System.err.println(" [" + instance.getUsage() + "]"); @@ -1172,7 +1099,7 @@ public class FsShell extends Configured implements Tool { return exitCode; } } else if ("-rm".equals(cmd) || "-rmr".equals(cmd) || - "-touchz".equals(cmd) || "-stat".equals(cmd)) { + "-touchz".equals(cmd)) { if (argv.length < 2) { printUsage(cmd); return exitCode; @@ -1245,12 +1172,6 @@ public class FsShell extends Configured implements Tool { exitCode = doall(cmd, argv, i); } else if ("-test".equals(cmd)) { exitCode = test(argv, i); - } else if ("-stat".equals(cmd)) { - if (i + 1 < argv.length) { - stat(argv[i++].toCharArray(), argv[i++]); - } else { - stat("%y".toCharArray(), argv[i]); - } } else if ("-help".equals(cmd)) { if (i < argv.length) { printHelp(argv[i]); diff --git a/src/java/org/apache/hadoop/fs/shell/FsCommand.java b/src/java/org/apache/hadoop/fs/shell/FsCommand.java index 177544e90e..79cbfb3df2 100644 --- a/src/java/org/apache/hadoop/fs/shell/FsCommand.java +++ b/src/java/org/apache/hadoop/fs/shell/FsCommand.java @@ -50,6 +50,7 @@ abstract public class FsCommand extends Command { factory.registerCommands(Ls.class); factory.registerCommands(Mkdir.class); factory.registerCommands(SetReplication.class); + factory.registerCommands(Stat.class); factory.registerCommands(Tail.class); } diff --git a/src/java/org/apache/hadoop/fs/shell/Stat.java b/src/java/org/apache/hadoop/fs/shell/Stat.java new file mode 100644 index 0000000000..716fe512a5 --- /dev/null +++ b/src/java/org/apache/hadoop/fs/shell/Stat.java @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.fs.shell; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.TimeZone; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.fs.FileStatus; + +/** + * Print statistics about path in specified format. + * Format sequences: + * %b: Size of file in blocks + * %n: Filename + * %o: Block size + * %r: replication + * %y: UTC date as "yyyy-MM-dd HH:mm:ss" + * %Y: Milliseconds since January 1, 1970 UTC + */ +@InterfaceAudience.Private +@InterfaceStability.Unstable + +class Stat extends FsCommand { + public static void registerCommands(CommandFactory factory) { + factory.addClass(Stat.class, "-stat"); + } + + public static final String NAME = "stat"; + public static final String USAGE = "[format] ..."; + public static final String DESCRIPTION = + "Print statistics about the file/directory at \n" + + "in the specified format. Format accepts filesize in blocks (%b), filename (%n),\n" + + "block size (%o), replication (%r), modification date (%y, %Y)\n"; + + protected static final SimpleDateFormat timeFmt; + static { + timeFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + timeFmt.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + // default format string + protected String format = "%y"; + + @Override + protected void processOptions(LinkedList args) throws IOException { + CommandFormat cf = new CommandFormat(null, 1, Integer.MAX_VALUE, "R"); + cf.parse(args); + setRecursive(cf.getOpt("R")); + if (args.getFirst().contains("%")) format = args.removeFirst(); + cf.parse(args); // make sure there's still at least one arg + } + + @Override + protected void processPath(PathData item) throws IOException { + FileStatus stat = item.stat; + StringBuilder buf = new StringBuilder(); + + char[] fmt = format.toCharArray(); + for (int i = 0; i < fmt.length; ++i) { + if (fmt[i] != '%') { + buf.append(fmt[i]); + } else { + // this silently drops a trailing %? + if (i + 1 == fmt.length) break; + switch (fmt[++i]) { + case 'b': + buf.append(stat.getLen()); + break; + case 'F': + buf.append(stat.isDirectory() + ? "directory" + : (stat.isFile() ? "regular file" : "symlink")); + break; + case 'n': + buf.append(item); + break; + case 'o': + buf.append(stat.getBlockSize()); + break; + case 'r': + buf.append(stat.getReplication()); + break; + case 'y': + buf.append(timeFmt.format(new Date(stat.getModificationTime()))); + break; + case 'Y': + buf.append(stat.getModificationTime()); + break; + default: + // this leaves % alone, which causes the potential for + // future format options to break strings; should use %% to + // escape percents + buf.append(fmt[i]); + break; + } + } + } + out.println(buf.toString()); + } +} \ No newline at end of file diff --git a/src/test/core/org/apache/hadoop/cli/testConf.xml b/src/test/core/org/apache/hadoop/cli/testConf.xml index d317d430f5..1b82fd2ef1 100644 --- a/src/test/core/org/apache/hadoop/cli/testConf.xml +++ b/src/test/core/org/apache/hadoop/cli/testConf.xml @@ -583,7 +583,7 @@ RegexpComparator - ^-stat \[format\] <path>: Print statistics about the file/directory at <path>( )* + ^-stat \[format\] <path> \.\.\.:( |\t)*Print statistics about the file/directory at <path>( )* RegexpComparator