HADOOP-7320. Refactor the copy and move commands to conform to new FsCommand class. Contributed by Daryn Sharp.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1127591 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a7ce0bbf8a
commit
77b4fd6572
@ -176,6 +176,9 @@ Trunk (unreleased changes)
|
|||||||
HADOOP-7329. Improve help message for "df" to include "-h" flag.
|
HADOOP-7329. Improve help message for "df" to include "-h" flag.
|
||||||
(Xie Xianshan via todd)
|
(Xie Xianshan via todd)
|
||||||
|
|
||||||
|
HADOOP-7320. Refactor the copy and move commands to conform to new
|
||||||
|
FsCommand class. (Daryn Sharp via todd)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
@ -17,15 +17,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.hadoop.fs;
|
package org.apache.hadoop.fs;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URI;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -36,12 +29,9 @@
|
|||||||
import org.apache.hadoop.conf.Configured;
|
import org.apache.hadoop.conf.Configured;
|
||||||
import org.apache.hadoop.fs.shell.Command;
|
import org.apache.hadoop.fs.shell.Command;
|
||||||
import org.apache.hadoop.fs.shell.CommandFactory;
|
import org.apache.hadoop.fs.shell.CommandFactory;
|
||||||
import org.apache.hadoop.fs.shell.CommandFormat;
|
|
||||||
import org.apache.hadoop.fs.shell.FsCommand;
|
import org.apache.hadoop.fs.shell.FsCommand;
|
||||||
import org.apache.hadoop.fs.shell.PathExceptions.PathNotFoundException;
|
import org.apache.hadoop.fs.shell.PathExceptions.PathNotFoundException;
|
||||||
import org.apache.hadoop.io.IOUtils;
|
|
||||||
import org.apache.hadoop.ipc.RPC;
|
import org.apache.hadoop.ipc.RPC;
|
||||||
import org.apache.hadoop.ipc.RemoteException;
|
|
||||||
import org.apache.hadoop.util.StringUtils;
|
import org.apache.hadoop.util.StringUtils;
|
||||||
import org.apache.hadoop.util.Tool;
|
import org.apache.hadoop.util.Tool;
|
||||||
import org.apache.hadoop.util.ToolRunner;
|
import org.apache.hadoop.util.ToolRunner;
|
||||||
@ -56,14 +46,6 @@ public class FsShell extends Configured implements Tool {
|
|||||||
private Trash trash;
|
private Trash trash;
|
||||||
protected CommandFactory commandFactory;
|
protected CommandFactory commandFactory;
|
||||||
|
|
||||||
public static final SimpleDateFormat dateForm =
|
|
||||||
new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
|
||||||
static final int BORDER = 2;
|
|
||||||
|
|
||||||
static final String GET_SHORT_USAGE = "-get [-ignoreCrc] [-crc] <src> <localdst>";
|
|
||||||
static final String COPYTOLOCAL_SHORT_USAGE = GET_SHORT_USAGE.replace(
|
|
||||||
"-get", "-copyToLocal");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public FsShell() {
|
public FsShell() {
|
||||||
@ -95,398 +77,6 @@ protected void init() throws IOException {
|
|||||||
getConf().setQuietMode(true);
|
getConf().setQuietMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies from stdin to the indicated file.
|
|
||||||
*/
|
|
||||||
private void copyFromStdin(Path dst, FileSystem dstFs) throws IOException {
|
|
||||||
if (dstFs.isDirectory(dst)) {
|
|
||||||
throw new IOException("When source is stdin, destination must be a file.");
|
|
||||||
}
|
|
||||||
if (dstFs.exists(dst)) {
|
|
||||||
throw new IOException("Target " + dst.toString() + " already exists.");
|
|
||||||
}
|
|
||||||
FSDataOutputStream out = dstFs.create(dst);
|
|
||||||
try {
|
|
||||||
IOUtils.copyBytes(System.in, out, getConf(), false);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Print from src to stdout.
|
|
||||||
*/
|
|
||||||
private void printToStdout(InputStream in) throws IOException {
|
|
||||||
try {
|
|
||||||
IOUtils.copyBytes(in, System.out, getConf(), false);
|
|
||||||
} finally {
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add local files to the indicated FileSystem name. src is kept.
|
|
||||||
*/
|
|
||||||
void copyFromLocal(Path[] srcs, String dstf) throws IOException {
|
|
||||||
Path dstPath = new Path(dstf);
|
|
||||||
FileSystem dstFs = dstPath.getFileSystem(getConf());
|
|
||||||
if (srcs.length == 1 && srcs[0].toString().equals("-"))
|
|
||||||
copyFromStdin(dstPath, dstFs);
|
|
||||||
else
|
|
||||||
dstFs.copyFromLocalFile(false, false, srcs, dstPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add local files to the indicated FileSystem name. src is removed.
|
|
||||||
*/
|
|
||||||
void moveFromLocal(Path[] srcs, String dstf) throws IOException {
|
|
||||||
Path dstPath = new Path(dstf);
|
|
||||||
FileSystem dstFs = dstPath.getFileSystem(getConf());
|
|
||||||
dstFs.moveFromLocalFile(srcs, dstPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a local file to the indicated FileSystem name. src is removed.
|
|
||||||
*/
|
|
||||||
void moveFromLocal(Path src, String dstf) throws IOException {
|
|
||||||
moveFromLocal((new Path[]{src}), dstf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the indicated files that match the file pattern <i>srcf</i>
|
|
||||||
* and copy them to the local name. srcf is kept.
|
|
||||||
* When copying multiple files, the destination must be a directory.
|
|
||||||
* Otherwise, IOException is thrown.
|
|
||||||
* @param argv : arguments
|
|
||||||
* @param pos : Ignore everything before argv[pos]
|
|
||||||
* @throws Exception
|
|
||||||
* @see org.apache.hadoop.fs.FileSystem.globStatus
|
|
||||||
*/
|
|
||||||
void copyToLocal(String[]argv, int pos) throws Exception {
|
|
||||||
CommandFormat cf = new CommandFormat("copyToLocal", 2,2,"crc","ignoreCrc");
|
|
||||||
|
|
||||||
String srcstr = null;
|
|
||||||
String dststr = null;
|
|
||||||
try {
|
|
||||||
List<String> parameters = cf.parse(argv, pos);
|
|
||||||
srcstr = parameters.get(0);
|
|
||||||
dststr = parameters.get(1);
|
|
||||||
}
|
|
||||||
catch(IllegalArgumentException iae) {
|
|
||||||
System.err.println("Usage: java FsShell " + GET_SHORT_USAGE);
|
|
||||||
throw iae;
|
|
||||||
}
|
|
||||||
boolean copyCrc = cf.getOpt("crc");
|
|
||||||
final boolean verifyChecksum = !cf.getOpt("ignoreCrc");
|
|
||||||
|
|
||||||
if (dststr.equals("-")) {
|
|
||||||
if (copyCrc) {
|
|
||||||
System.err.println("-crc option is not valid when destination is stdout.");
|
|
||||||
}
|
|
||||||
|
|
||||||
List<String> catArgv = new ArrayList<String>();
|
|
||||||
catArgv.add("-cat");
|
|
||||||
if (cf.getOpt("ignoreCrc")) catArgv.add("-ignoreCrc");
|
|
||||||
catArgv.add(srcstr);
|
|
||||||
run(catArgv.toArray(new String[0]));
|
|
||||||
} else {
|
|
||||||
File dst = new File(dststr);
|
|
||||||
Path srcpath = new Path(srcstr);
|
|
||||||
FileSystem srcFS = getSrcFileSystem(srcpath, verifyChecksum);
|
|
||||||
if (copyCrc && !(srcFS instanceof ChecksumFileSystem)) {
|
|
||||||
System.err.println("-crc option is not valid when source file system " +
|
|
||||||
"does not have crc files. Automatically turn the option off.");
|
|
||||||
copyCrc = false;
|
|
||||||
}
|
|
||||||
FileStatus[] srcs = srcFS.globStatus(srcpath);
|
|
||||||
if (null == srcs) {
|
|
||||||
throw new PathNotFoundException(srcstr);
|
|
||||||
}
|
|
||||||
boolean dstIsDir = dst.isDirectory();
|
|
||||||
if (srcs.length > 1 && !dstIsDir) {
|
|
||||||
throw new IOException("When copying multiple files, "
|
|
||||||
+ "destination should be a directory.");
|
|
||||||
}
|
|
||||||
for (FileStatus status : srcs) {
|
|
||||||
Path p = status.getPath();
|
|
||||||
File f = dstIsDir? new File(dst, p.getName()): dst;
|
|
||||||
copyToLocal(srcFS, status, f, copyCrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the {@link FileSystem} specified by src and the conf.
|
|
||||||
* It the {@link FileSystem} supports checksum, set verifyChecksum.
|
|
||||||
*/
|
|
||||||
private FileSystem getSrcFileSystem(Path src, boolean verifyChecksum
|
|
||||||
) throws IOException {
|
|
||||||
FileSystem srcFs = src.getFileSystem(getConf());
|
|
||||||
srcFs.setVerifyChecksum(verifyChecksum);
|
|
||||||
return srcFs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The prefix for the tmp file used in copyToLocal.
|
|
||||||
* It must be at least three characters long, required by
|
|
||||||
* {@link java.io.File#createTempFile(String, String, File)}.
|
|
||||||
*/
|
|
||||||
static final String COPYTOLOCAL_PREFIX = "_copyToLocal_";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy a source file from a given file system to local destination.
|
|
||||||
* @param srcFS source file system
|
|
||||||
* @param src source path
|
|
||||||
* @param dst destination
|
|
||||||
* @param copyCrc copy CRC files?
|
|
||||||
* @exception IOException If some IO failed
|
|
||||||
*/
|
|
||||||
private void copyToLocal(final FileSystem srcFS, final FileStatus srcStatus,
|
|
||||||
final File dst, final boolean copyCrc)
|
|
||||||
throws IOException {
|
|
||||||
/* Keep the structure similar to ChecksumFileSystem.copyToLocal().
|
|
||||||
* Ideal these two should just invoke FileUtil.copy() and not repeat
|
|
||||||
* recursion here. Of course, copy() should support two more options :
|
|
||||||
* copyCrc and useTmpFile (may be useTmpFile need not be an option).
|
|
||||||
*/
|
|
||||||
|
|
||||||
Path src = srcStatus.getPath();
|
|
||||||
if (srcStatus.isFile()) {
|
|
||||||
if (dst.exists()) {
|
|
||||||
// match the error message in FileUtil.checkDest():
|
|
||||||
throw new IOException("Target " + dst + " already exists");
|
|
||||||
}
|
|
||||||
|
|
||||||
// use absolute name so that tmp file is always created under dest dir
|
|
||||||
File tmp = FileUtil.createLocalTempFile(dst.getAbsoluteFile(),
|
|
||||||
COPYTOLOCAL_PREFIX, true);
|
|
||||||
if (!FileUtil.copy(srcFS, src, tmp, false, srcFS.getConf())) {
|
|
||||||
throw new IOException("Failed to copy " + src + " to " + dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tmp.renameTo(dst)) {
|
|
||||||
throw new IOException("Failed to rename tmp file " + tmp +
|
|
||||||
" to local destination \"" + dst + "\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copyCrc) {
|
|
||||||
if (!(srcFS instanceof ChecksumFileSystem)) {
|
|
||||||
throw new IOException("Source file system does not have crc files");
|
|
||||||
}
|
|
||||||
|
|
||||||
ChecksumFileSystem csfs = (ChecksumFileSystem) srcFS;
|
|
||||||
File dstcs = FileSystem.getLocal(srcFS.getConf())
|
|
||||||
.pathToFile(csfs.getChecksumFile(new Path(dst.getCanonicalPath())));
|
|
||||||
FileSystem fs = csfs.getRawFileSystem();
|
|
||||||
FileStatus status = csfs.getFileStatus(csfs.getChecksumFile(src));
|
|
||||||
copyToLocal(fs, status, dstcs, false);
|
|
||||||
}
|
|
||||||
} else if (srcStatus.isSymlink()) {
|
|
||||||
throw new AssertionError("Symlinks unsupported");
|
|
||||||
} else {
|
|
||||||
// once FileUtil.copy() supports tmp file, we don't need to mkdirs().
|
|
||||||
if (!dst.mkdirs()) {
|
|
||||||
throw new IOException("Failed to create local destination \"" +
|
|
||||||
dst + "\".");
|
|
||||||
}
|
|
||||||
for(FileStatus status : srcFS.listStatus(src)) {
|
|
||||||
copyToLocal(srcFS, status,
|
|
||||||
new File(dst, status.getPath().getName()), copyCrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the indicated file and copy to the local name.
|
|
||||||
* srcf is removed.
|
|
||||||
*/
|
|
||||||
void moveToLocal(String srcf, Path dst) throws IOException {
|
|
||||||
System.err.println("Option '-moveToLocal' is not implemented yet.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move files that match the file pattern <i>srcf</i>
|
|
||||||
* to a destination file.
|
|
||||||
* When moving mutiple files, the destination must be a directory.
|
|
||||||
* Otherwise, IOException is thrown.
|
|
||||||
* @param srcf a file pattern specifying source files
|
|
||||||
* @param dstf a destination local file/directory
|
|
||||||
* @throws IOException
|
|
||||||
* @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
|
|
||||||
*/
|
|
||||||
void rename(String srcf, String dstf) throws IOException {
|
|
||||||
Path srcPath = new Path(srcf);
|
|
||||||
Path dstPath = new Path(dstf);
|
|
||||||
FileSystem fs = srcPath.getFileSystem(getConf());
|
|
||||||
URI srcURI = fs.getUri();
|
|
||||||
URI dstURI = dstPath.getFileSystem(getConf()).getUri();
|
|
||||||
if (srcURI.compareTo(dstURI) != 0) {
|
|
||||||
throw new IOException("src and destination filesystems do not match.");
|
|
||||||
}
|
|
||||||
Path[] srcs = FileUtil.stat2Paths(fs.globStatus(srcPath), srcPath);
|
|
||||||
Path dst = new Path(dstf);
|
|
||||||
if (srcs.length > 1 && !fs.isDirectory(dst)) {
|
|
||||||
throw new IOException("When moving multiple files, "
|
|
||||||
+ "destination should be a directory.");
|
|
||||||
}
|
|
||||||
for(int i=0; i<srcs.length; i++) {
|
|
||||||
if (!fs.rename(srcs[i], dst)) {
|
|
||||||
FileStatus srcFstatus = null;
|
|
||||||
FileStatus dstFstatus = null;
|
|
||||||
try {
|
|
||||||
srcFstatus = fs.getFileStatus(srcs[i]);
|
|
||||||
} catch(FileNotFoundException e) {
|
|
||||||
throw new PathNotFoundException(srcs[i].toString());
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
dstFstatus = fs.getFileStatus(dst);
|
|
||||||
} catch(IOException e) {
|
|
||||||
LOG.debug("Error getting file status of " + dst, e);
|
|
||||||
}
|
|
||||||
if((srcFstatus!= null) && (dstFstatus!= null)) {
|
|
||||||
if (srcFstatus.isDirectory() && !dstFstatus.isDirectory()) {
|
|
||||||
throw new IOException("cannot overwrite non directory "
|
|
||||||
+ dst + " with directory " + srcs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IOException("Failed to rename " + srcs[i] + " to " + dst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Move/rename file(s) to a destination file. Multiple source
|
|
||||||
* files can be specified. The destination is the last element of
|
|
||||||
* the argvp[] array.
|
|
||||||
* If multiple source files are specified, then the destination
|
|
||||||
* must be a directory. Otherwise, IOException is thrown.
|
|
||||||
* @exception: IOException
|
|
||||||
*/
|
|
||||||
private int rename(String argv[], Configuration conf) throws IOException {
|
|
||||||
int i = 0;
|
|
||||||
int exitCode = 0;
|
|
||||||
String cmd = argv[i++];
|
|
||||||
String dest = argv[argv.length-1];
|
|
||||||
//
|
|
||||||
// If the user has specified multiple source files, then
|
|
||||||
// the destination has to be a directory
|
|
||||||
//
|
|
||||||
if (argv.length > 3) {
|
|
||||||
Path dst = new Path(dest);
|
|
||||||
FileSystem dstFs = dst.getFileSystem(getConf());
|
|
||||||
if (!dstFs.isDirectory(dst)) {
|
|
||||||
throw new IOException("When moving multiple files, "
|
|
||||||
+ "destination " + dest + " should be a directory.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// for each source file, issue the rename
|
|
||||||
//
|
|
||||||
for (; i < argv.length - 1; i++) {
|
|
||||||
try {
|
|
||||||
//
|
|
||||||
// issue the rename to the fs
|
|
||||||
//
|
|
||||||
rename(argv[i], dest);
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
LOG.debug("Error renaming " + argv[i], e);
|
|
||||||
//
|
|
||||||
// This is a error returned by hadoop server. Print
|
|
||||||
// out the first line of the error mesage.
|
|
||||||
//
|
|
||||||
exitCode = -1;
|
|
||||||
try {
|
|
||||||
String[] content;
|
|
||||||
content = e.getLocalizedMessage().split("\n");
|
|
||||||
System.err.println(cmd.substring(1) + ": " + content[0]);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
System.err.println(cmd.substring(1) + ": " +
|
|
||||||
ex.getLocalizedMessage());
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.debug("Error renaming " + argv[i], e);
|
|
||||||
//
|
|
||||||
// IO exception encountered locally.
|
|
||||||
//
|
|
||||||
exitCode = -1;
|
|
||||||
displayError(cmd, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy files that match the file pattern <i>srcf</i>
|
|
||||||
* to a destination file.
|
|
||||||
* When copying mutiple files, the destination must be a directory.
|
|
||||||
* Otherwise, IOException is thrown.
|
|
||||||
* @param srcf a file pattern specifying source files
|
|
||||||
* @param dstf a destination local file/directory
|
|
||||||
* @throws IOException
|
|
||||||
* @see org.apache.hadoop.fs.FileSystem#globStatus(Path)
|
|
||||||
*/
|
|
||||||
void copy(String srcf, String dstf, Configuration conf) throws IOException {
|
|
||||||
Path srcPath = new Path(srcf);
|
|
||||||
FileSystem srcFs = srcPath.getFileSystem(getConf());
|
|
||||||
Path dstPath = new Path(dstf);
|
|
||||||
FileSystem dstFs = dstPath.getFileSystem(getConf());
|
|
||||||
Path [] srcs = FileUtil.stat2Paths(srcFs.globStatus(srcPath), srcPath);
|
|
||||||
if (srcs.length > 1 && !dstFs.isDirectory(dstPath)) {
|
|
||||||
throw new IOException("When copying multiple files, "
|
|
||||||
+ "destination should be a directory.");
|
|
||||||
}
|
|
||||||
for(int i=0; i<srcs.length; i++) {
|
|
||||||
FileUtil.copy(srcFs, srcs[i], dstFs, dstPath, false, conf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy file(s) to a destination file. Multiple source
|
|
||||||
* files can be specified. The destination is the last element of
|
|
||||||
* the argvp[] array.
|
|
||||||
* If multiple source files are specified, then the destination
|
|
||||||
* must be a directory. Otherwise, IOException is thrown.
|
|
||||||
* @exception: IOException
|
|
||||||
*/
|
|
||||||
private int copy(String argv[], Configuration conf) throws IOException {
|
|
||||||
int i = 0;
|
|
||||||
int exitCode = 0;
|
|
||||||
String cmd = argv[i++];
|
|
||||||
String dest = argv[argv.length-1];
|
|
||||||
//
|
|
||||||
// If the user has specified multiple source files, then
|
|
||||||
// the destination has to be a directory
|
|
||||||
//
|
|
||||||
if (argv.length > 3) {
|
|
||||||
Path dst = new Path(dest);
|
|
||||||
FileSystem pFS = dst.getFileSystem(conf);
|
|
||||||
if (!pFS.isDirectory(dst)) {
|
|
||||||
throw new IOException("When copying multiple files, "
|
|
||||||
+ "destination " + dest + " should be a directory.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// for each source file, issue the copy
|
|
||||||
//
|
|
||||||
for (; i < argv.length - 1; i++) {
|
|
||||||
try {
|
|
||||||
//
|
|
||||||
// issue the copy to the fs
|
|
||||||
//
|
|
||||||
copy(argv[i], dest, conf);
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOG.debug("Error copying " + argv[i], e);
|
|
||||||
exitCode = -1;
|
|
||||||
displayError(cmd, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Trash object associated with this shell.
|
* Returns the Trash object associated with this shell.
|
||||||
*/
|
*/
|
||||||
@ -516,11 +106,6 @@ private void printHelp(String cmd) {
|
|||||||
"The full syntax is: \n\n" +
|
"The full syntax is: \n\n" +
|
||||||
"hadoop fs [-fs <local | file system URI>] [-conf <configuration file>]\n\t" +
|
"hadoop fs [-fs <local | file system URI>] [-conf <configuration file>]\n\t" +
|
||||||
"[-D <property=value>]\n\t" +
|
"[-D <property=value>]\n\t" +
|
||||||
"[-mv <src> <dst>] [-cp <src> <dst>]\n\t" +
|
|
||||||
"[-put <localsrc> ... <dst>] [-copyFromLocal <localsrc> ... <dst>]\n\t" +
|
|
||||||
"[-moveFromLocal <localsrc> ... <dst>] [" +
|
|
||||||
GET_SHORT_USAGE + "\n\t" +
|
|
||||||
"[" + COPYTOLOCAL_SHORT_USAGE + "] [-moveToLocal <src> <localdst>]\n\t" +
|
|
||||||
"[-report]";
|
"[-report]";
|
||||||
|
|
||||||
String conf ="-conf <configuration file>: Specify an application configuration file.";
|
String conf ="-conf <configuration file>: Specify an application configuration file.";
|
||||||
@ -538,33 +123,6 @@ private void printHelp(String cmd) {
|
|||||||
"\t\tappear first on the command line. Exactly one additional\n" +
|
"\t\tappear first on the command line. Exactly one additional\n" +
|
||||||
"\t\targument must be specified. \n";
|
"\t\targument must be specified. \n";
|
||||||
|
|
||||||
String mv = "-mv <src> <dst>: Move files that match the specified file pattern <src>\n" +
|
|
||||||
"\t\tto a destination <dst>. When moving multiple files, the \n" +
|
|
||||||
"\t\tdestination must be a directory. \n";
|
|
||||||
|
|
||||||
String cp = "-cp <src> <dst>: Copy files that match the file pattern <src> to a \n" +
|
|
||||||
"\t\tdestination. When copying multiple files, the destination\n" +
|
|
||||||
"\t\tmust be a directory. \n";
|
|
||||||
|
|
||||||
String put = "-put <localsrc> ... <dst>: \tCopy files " +
|
|
||||||
"from the local file system \n\t\tinto fs. \n";
|
|
||||||
|
|
||||||
String copyFromLocal = "-copyFromLocal <localsrc> ... <dst>:" +
|
|
||||||
" Identical to the -put command.\n";
|
|
||||||
|
|
||||||
String moveFromLocal = "-moveFromLocal <localsrc> ... <dst>:" +
|
|
||||||
" Same as -put, except that the source is\n\t\tdeleted after it's copied.\n";
|
|
||||||
|
|
||||||
String get = GET_SHORT_USAGE
|
|
||||||
+ ": Copy files that match the file pattern <src> \n" +
|
|
||||||
"\t\tto the local name. <src> is kept. When copying mutiple, \n" +
|
|
||||||
"\t\tfiles, the destination must be a directory. \n";
|
|
||||||
|
|
||||||
String copyToLocal = COPYTOLOCAL_SHORT_USAGE
|
|
||||||
+ ": Identical to the -get command.\n";
|
|
||||||
|
|
||||||
String moveToLocal = "-moveToLocal <src> <localdst>: Not implemented yet \n";
|
|
||||||
|
|
||||||
String help = "-help [cmd]: \tDisplays help for given command or all commands if none\n" +
|
String help = "-help [cmd]: \tDisplays help for given command or all commands if none\n" +
|
||||||
"\t\tis specified.\n";
|
"\t\tis specified.\n";
|
||||||
|
|
||||||
@ -577,24 +135,6 @@ private void printHelp(String cmd) {
|
|||||||
System.out.println(conf);
|
System.out.println(conf);
|
||||||
} else if ("D".equals(cmd)) {
|
} else if ("D".equals(cmd)) {
|
||||||
System.out.println(D);
|
System.out.println(D);
|
||||||
} else if ("mv".equals(cmd)) {
|
|
||||||
System.out.println(mv);
|
|
||||||
} else if ("cp".equals(cmd)) {
|
|
||||||
System.out.println(cp);
|
|
||||||
} else if ("put".equals(cmd)) {
|
|
||||||
System.out.println(put);
|
|
||||||
} else if ("copyFromLocal".equals(cmd)) {
|
|
||||||
System.out.println(copyFromLocal);
|
|
||||||
} else if ("moveFromLocal".equals(cmd)) {
|
|
||||||
System.out.println(moveFromLocal);
|
|
||||||
} else if ("get".equals(cmd)) {
|
|
||||||
System.out.println(get);
|
|
||||||
} else if ("copyToLocal".equals(cmd)) {
|
|
||||||
System.out.println(copyToLocal);
|
|
||||||
} else if ("moveToLocal".equals(cmd)) {
|
|
||||||
System.out.println(moveToLocal);
|
|
||||||
} else if ("get".equals(cmd)) {
|
|
||||||
System.out.println(get);
|
|
||||||
} else if ("help".equals(cmd)) {
|
} else if ("help".equals(cmd)) {
|
||||||
System.out.println(help);
|
System.out.println(help);
|
||||||
} else {
|
} else {
|
||||||
@ -608,14 +148,6 @@ private void printHelp(String cmd) {
|
|||||||
System.out.println("\t[-help [cmd]]\n");
|
System.out.println("\t[-help [cmd]]\n");
|
||||||
|
|
||||||
System.out.println(fs);
|
System.out.println(fs);
|
||||||
System.out.println(mv);
|
|
||||||
System.out.println(cp);
|
|
||||||
System.out.println(put);
|
|
||||||
System.out.println(copyFromLocal);
|
|
||||||
System.out.println(moveFromLocal);
|
|
||||||
System.out.println(get);
|
|
||||||
System.out.println(copyToLocal);
|
|
||||||
System.out.println(moveToLocal);
|
|
||||||
|
|
||||||
for (String thisCmdName : commandFactory.getNames()) {
|
for (String thisCmdName : commandFactory.getNames()) {
|
||||||
instance = commandFactory.getInstance(thisCmdName);
|
instance = commandFactory.getInstance(thisCmdName);
|
||||||
@ -662,30 +194,8 @@ private void printUsage(String cmd) {
|
|||||||
} else if ("-D".equals(cmd)) {
|
} else if ("-D".equals(cmd)) {
|
||||||
System.err.println("Usage: java FsShell" +
|
System.err.println("Usage: java FsShell" +
|
||||||
" [-D <[property=value>]");
|
" [-D <[property=value>]");
|
||||||
} else if ("-mv".equals(cmd) || "-cp".equals(cmd)) {
|
|
||||||
System.err.println("Usage: java FsShell" +
|
|
||||||
" [" + cmd + " <src> <dst>]");
|
|
||||||
} else if ("-put".equals(cmd) || "-copyFromLocal".equals(cmd) ||
|
|
||||||
"-moveFromLocal".equals(cmd)) {
|
|
||||||
System.err.println("Usage: java FsShell" +
|
|
||||||
" [" + cmd + " <localsrc> ... <dst>]");
|
|
||||||
} else if ("-get".equals(cmd)) {
|
|
||||||
System.err.println("Usage: java FsShell [" + GET_SHORT_USAGE + "]");
|
|
||||||
} else if ("-copyToLocal".equals(cmd)) {
|
|
||||||
System.err.println("Usage: java FsShell [" + COPYTOLOCAL_SHORT_USAGE+ "]");
|
|
||||||
} else if ("-moveToLocal".equals(cmd)) {
|
|
||||||
System.err.println("Usage: java FsShell" +
|
|
||||||
" [" + cmd + " [-crc] <src> <localdst>]");
|
|
||||||
} else {
|
} else {
|
||||||
System.err.println("Usage: java FsShell");
|
System.err.println("Usage: java FsShell");
|
||||||
System.err.println(" [-mv <src> <dst>]");
|
|
||||||
System.err.println(" [-cp <src> <dst>]");
|
|
||||||
System.err.println(" [-put <localsrc> ... <dst>]");
|
|
||||||
System.err.println(" [-copyFromLocal <localsrc> ... <dst>]");
|
|
||||||
System.err.println(" [-moveFromLocal <localsrc> ... <dst>]");
|
|
||||||
System.err.println(" [" + GET_SHORT_USAGE + "]");
|
|
||||||
System.err.println(" [" + COPYTOLOCAL_SHORT_USAGE + "]");
|
|
||||||
System.err.println(" [-moveToLocal [-crc] <src> <localdst>]");
|
|
||||||
for (String name : commandFactory.getNames()) {
|
for (String name : commandFactory.getNames()) {
|
||||||
instance = commandFactory.getInstance(name);
|
instance = commandFactory.getInstance(name);
|
||||||
if (!instance.isDeprecated()) {
|
if (!instance.isDeprecated()) {
|
||||||
@ -716,27 +226,6 @@ public int run(String argv[]) throws Exception {
|
|||||||
int exitCode = -1;
|
int exitCode = -1;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
String cmd = argv[i++];
|
String cmd = argv[i++];
|
||||||
//
|
|
||||||
// verify that we have enough command line parameters
|
|
||||||
//
|
|
||||||
if ("-put".equals(cmd) ||
|
|
||||||
"-copyFromLocal".equals(cmd) || "-moveFromLocal".equals(cmd)) {
|
|
||||||
if (argv.length < 3) {
|
|
||||||
printUsage(cmd);
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
} else if ("-get".equals(cmd) ||
|
|
||||||
"-copyToLocal".equals(cmd) || "-moveToLocal".equals(cmd)) {
|
|
||||||
if (argv.length < 3) {
|
|
||||||
printUsage(cmd);
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
} else if ("-mv".equals(cmd) || "-cp".equals(cmd)) {
|
|
||||||
if (argv.length < 3) {
|
|
||||||
printUsage(cmd);
|
|
||||||
return exitCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// initialize FsShell
|
// initialize FsShell
|
||||||
try {
|
try {
|
||||||
init();
|
init();
|
||||||
@ -752,38 +241,10 @@ public int run(String argv[]) throws Exception {
|
|||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
exitCode = 0;
|
|
||||||
try {
|
try {
|
||||||
Command instance = commandFactory.getInstance(cmd);
|
Command instance = commandFactory.getInstance(cmd);
|
||||||
if (instance != null) {
|
if (instance != null) {
|
||||||
try {
|
|
||||||
exitCode = instance.run(Arrays.copyOfRange(argv, i, argv.length));
|
exitCode = instance.run(Arrays.copyOfRange(argv, i, argv.length));
|
||||||
} catch (Exception e) {
|
|
||||||
exitCode = -1;
|
|
||||||
LOG.debug("Error", e);
|
|
||||||
instance.displayError(e);
|
|
||||||
if (e instanceof IllegalArgumentException) {
|
|
||||||
printUsage(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ("-put".equals(cmd) || "-copyFromLocal".equals(cmd)) {
|
|
||||||
Path[] srcs = new Path[argv.length-2];
|
|
||||||
for (int j=0 ; i < argv.length-1 ;)
|
|
||||||
srcs[j++] = new Path(argv[i++]);
|
|
||||||
copyFromLocal(srcs, argv[i++]);
|
|
||||||
} else if ("-moveFromLocal".equals(cmd)) {
|
|
||||||
Path[] srcs = new Path[argv.length-2];
|
|
||||||
for (int j=0 ; i < argv.length-1 ;)
|
|
||||||
srcs[j++] = new Path(argv[i++]);
|
|
||||||
moveFromLocal(srcs, argv[i++]);
|
|
||||||
} else if ("-get".equals(cmd) || "-copyToLocal".equals(cmd)) {
|
|
||||||
copyToLocal(argv, i);
|
|
||||||
} else if ("-moveToLocal".equals(cmd)) {
|
|
||||||
moveToLocal(argv[i++], new Path(argv[i++]));
|
|
||||||
} else if ("-mv".equals(cmd)) {
|
|
||||||
exitCode = rename(argv, getConf());
|
|
||||||
} else if ("-cp".equals(cmd)) {
|
|
||||||
exitCode = copy(argv, getConf());
|
|
||||||
} else if ("-help".equals(cmd)) {
|
} else if ("-help".equals(cmd)) {
|
||||||
if (i < argv.length) {
|
if (i < argv.length) {
|
||||||
printHelp(argv[i]);
|
printHelp(argv[i]);
|
||||||
@ -791,20 +252,17 @@ public int run(String argv[]) throws Exception {
|
|||||||
printHelp("");
|
printHelp("");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
exitCode = -1;
|
System.err.println(cmd + ": Unknown command");
|
||||||
System.err.println(cmd.substring(1) + ": Unknown command");
|
|
||||||
printUsage("");
|
printUsage("");
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException arge) {
|
} catch (Exception e) {
|
||||||
LOG.debug("Error", arge);
|
exitCode = 1;
|
||||||
|
LOG.debug("Error", e);
|
||||||
|
displayError(cmd, e);
|
||||||
|
if (e instanceof IllegalArgumentException) {
|
||||||
exitCode = -1;
|
exitCode = -1;
|
||||||
System.err.println(cmd.substring(1) + ": " + arge.getLocalizedMessage());
|
|
||||||
printUsage(cmd);
|
printUsage(cmd);
|
||||||
} catch (Exception re) {
|
}
|
||||||
LOG.debug("Error", re);
|
|
||||||
exitCode = -1;
|
|
||||||
displayError(cmd, re);
|
|
||||||
} finally {
|
|
||||||
}
|
}
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
151
src/java/org/apache/hadoop/fs/shell/CommandWithDestination.java
Normal file
151
src/java/org/apache/hadoop/fs/shell/CommandWithDestination.java
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/**
|
||||||
|
* 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.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathExistsException;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathIOException;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathIsNotDirectoryException;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides: argument processing to ensure the destination is valid
|
||||||
|
* for the number of source arguments. A processPaths that accepts both
|
||||||
|
* a source and resolved target. Sources are resolved as children of
|
||||||
|
* a destination directory.
|
||||||
|
*/
|
||||||
|
abstract class CommandWithDestination extends FsCommand {
|
||||||
|
protected PathData dst;
|
||||||
|
protected boolean overwrite = false;
|
||||||
|
|
||||||
|
// TODO: commands should implement a -f to enable this
|
||||||
|
protected void setOverwrite(boolean flag) {
|
||||||
|
overwrite = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last arg is expected to be a local path, if only one argument is
|
||||||
|
* given then the destination will be the current directory
|
||||||
|
* @param args is the list of arguments
|
||||||
|
*/
|
||||||
|
protected void getLocalDestination(LinkedList<String> args)
|
||||||
|
throws IOException {
|
||||||
|
String pathString = (args.size() < 2) ? Path.CUR_DIR : args.removeLast();
|
||||||
|
dst = new PathData(new File(pathString), getConf());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last arg is expected to be a remote path, if only one argument is
|
||||||
|
* given then the destination will be the remote user's directory
|
||||||
|
* @param args is the list of arguments
|
||||||
|
* @throws PathIOException if path doesn't exist or matches too many times
|
||||||
|
*/
|
||||||
|
protected void getRemoteDestination(LinkedList<String> args)
|
||||||
|
throws IOException {
|
||||||
|
if (args.size() < 2) {
|
||||||
|
dst = new PathData(Path.CUR_DIR, getConf());
|
||||||
|
} else {
|
||||||
|
String pathString = args.removeLast();
|
||||||
|
// if the path is a glob, then it must match one and only one path
|
||||||
|
PathData[] items = PathData.expandAsGlob(pathString, getConf());
|
||||||
|
switch (items.length) {
|
||||||
|
case 0:
|
||||||
|
throw new PathNotFoundException(pathString);
|
||||||
|
case 1:
|
||||||
|
dst = items[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new PathIOException(pathString, "Too many matches");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processArguments(LinkedList<PathData> args)
|
||||||
|
throws IOException {
|
||||||
|
// if more than one arg, the destination must be a directory
|
||||||
|
// if one arg, the dst must not exist or must be a directory
|
||||||
|
if (args.size() > 1) {
|
||||||
|
if (!dst.exists) {
|
||||||
|
throw new PathNotFoundException(dst.toString());
|
||||||
|
}
|
||||||
|
if (!dst.stat.isDirectory()) {
|
||||||
|
throw new PathIsNotDirectoryException(dst.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dst.exists && !dst.stat.isDirectory() && !overwrite) {
|
||||||
|
throw new PathExistsException(dst.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.processArguments(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPaths(PathData parent, PathData ... items)
|
||||||
|
throws IOException {
|
||||||
|
PathData savedDst = dst;
|
||||||
|
try {
|
||||||
|
// modify dst as we descend to append the basename of the
|
||||||
|
// current directory being processed
|
||||||
|
if (parent != null) dst = dst.getPathDataForChild(parent);
|
||||||
|
super.processPaths(parent, items);
|
||||||
|
} finally {
|
||||||
|
dst = savedDst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPath(PathData src) throws IOException {
|
||||||
|
PathData target;
|
||||||
|
// if the destination is a directory, make target a child path,
|
||||||
|
// else use the destination as-is
|
||||||
|
if (dst.exists && dst.stat.isDirectory()) {
|
||||||
|
target = dst.getPathDataForChild(src);
|
||||||
|
} else {
|
||||||
|
target = dst;
|
||||||
|
}
|
||||||
|
if (target.exists && !overwrite) {
|
||||||
|
throw new PathExistsException(target.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// invoke processPath with both a source and resolved target
|
||||||
|
processPath(src, target);
|
||||||
|
} catch (PathIOException e) {
|
||||||
|
// add the target unless it already has one
|
||||||
|
if (e.getTargetPath() == null) {
|
||||||
|
e.setTargetPath(target.toString());
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called with a source and target destination pair
|
||||||
|
* @param src for the operation
|
||||||
|
* @param target for the operation
|
||||||
|
* @throws IOException if anything goes wrong
|
||||||
|
*/
|
||||||
|
protected abstract void processPath(PathData src, PathData target)
|
||||||
|
throws IOException;
|
||||||
|
}
|
@ -1,72 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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.util.LinkedList;
|
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
|
||||||
import org.apache.hadoop.fs.FileUtil;
|
|
||||||
import org.apache.hadoop.fs.Path;
|
|
||||||
|
|
||||||
/** Various commands for copy files */
|
|
||||||
@InterfaceAudience.Private
|
|
||||||
@InterfaceStability.Evolving
|
|
||||||
|
|
||||||
class Copy extends FsCommand {
|
|
||||||
public static void registerCommands(CommandFactory factory) {
|
|
||||||
factory.addClass(Merge.class, "-getmerge");
|
|
||||||
}
|
|
||||||
|
|
||||||
/** merge multiple files together */
|
|
||||||
public static class Merge extends Copy {
|
|
||||||
public static final String NAME = "MergeToLocal";
|
|
||||||
public static final String USAGE = "<src> <localdst> [addnl]";
|
|
||||||
public static final String DESCRIPTION =
|
|
||||||
"Get all the files in the directories that\n" +
|
|
||||||
"match the source file pattern and merge and sort them to only\n" +
|
|
||||||
"one file on local fs. <src> is kept.\n";
|
|
||||||
|
|
||||||
protected PathData dst = null;
|
|
||||||
protected String delimiter = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processOptions(LinkedList<String> args) throws IOException {
|
|
||||||
CommandFormat cf = new CommandFormat(null, 2, 3);
|
|
||||||
cf.parse(args);
|
|
||||||
|
|
||||||
// TODO: this really should be a -nl option
|
|
||||||
if ((args.size() > 2) && Boolean.parseBoolean(args.removeLast())) {
|
|
||||||
delimiter = "\n";
|
|
||||||
} else {
|
|
||||||
delimiter = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path path = new Path(args.removeLast());
|
|
||||||
dst = new PathData(path.getFileSystem(getConf()), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void processPath(PathData src) throws IOException {
|
|
||||||
FileUtil.copyMerge(src.fs, src.path,
|
|
||||||
dst.fs, dst.path, false, getConf(), delimiter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
274
src/java/org/apache/hadoop/fs/shell/CopyCommands.java
Normal file
274
src/java/org/apache/hadoop/fs/shell/CopyCommands.java
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
/**
|
||||||
|
* 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.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.fs.ChecksumFileSystem;
|
||||||
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.FileUtil;
|
||||||
|
import org.apache.hadoop.fs.LocalFileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathExistsException;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathIOException;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathOperationException;
|
||||||
|
import org.apache.hadoop.io.IOUtils;
|
||||||
|
|
||||||
|
/** Various commands for copy files */
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
|
||||||
|
class CopyCommands {
|
||||||
|
public static void registerCommands(CommandFactory factory) {
|
||||||
|
factory.addClass(Merge.class, "-getmerge");
|
||||||
|
factory.addClass(Cp.class, "-cp");
|
||||||
|
factory.addClass(CopyFromLocal.class, "-copyFromLocal");
|
||||||
|
factory.addClass(CopyToLocal.class, "-copyToLocal");
|
||||||
|
factory.addClass(Get.class, "-get");
|
||||||
|
factory.addClass(Put.class, "-put");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** merge multiple files together */
|
||||||
|
public static class Merge extends FsCommand {
|
||||||
|
public static final String NAME = "getmerge";
|
||||||
|
public static final String USAGE = "<src> <localdst> [addnl]";
|
||||||
|
public static final String DESCRIPTION =
|
||||||
|
"Get all the files in the directories that\n" +
|
||||||
|
"match the source file pattern and merge and sort them to only\n" +
|
||||||
|
"one file on local fs. <src> is kept.";
|
||||||
|
|
||||||
|
protected PathData dst = null;
|
||||||
|
protected String delimiter = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processOptions(LinkedList<String> args) throws IOException {
|
||||||
|
CommandFormat cf = new CommandFormat(null, 2, 3);
|
||||||
|
cf.parse(args);
|
||||||
|
|
||||||
|
// TODO: this really should be a -nl option
|
||||||
|
if ((args.size() > 2) && Boolean.parseBoolean(args.removeLast())) {
|
||||||
|
delimiter = "\n";
|
||||||
|
} else {
|
||||||
|
delimiter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
dst = new PathData(new File(args.removeLast()), getConf());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPath(PathData src) throws IOException {
|
||||||
|
FileUtil.copyMerge(src.fs, src.path,
|
||||||
|
dst.fs, dst.path, false, getConf(), delimiter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Cp extends CommandWithDestination {
|
||||||
|
public static final String NAME = "cp";
|
||||||
|
public static final String USAGE = "<src> ... <dst>";
|
||||||
|
public static final String DESCRIPTION =
|
||||||
|
"Copy files that match the file pattern <src> to a\n" +
|
||||||
|
"destination. When copying multiple files, the destination\n" +
|
||||||
|
"must be a directory.";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processOptions(LinkedList<String> args) throws IOException {
|
||||||
|
CommandFormat cf = new CommandFormat(null, 2, Integer.MAX_VALUE);
|
||||||
|
cf.parse(args);
|
||||||
|
getRemoteDestination(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPath(PathData src, PathData target)
|
||||||
|
throws IOException {
|
||||||
|
if (!FileUtil.copy(src.fs, src.path, target.fs, target.path, false, getConf())) {
|
||||||
|
// we have no idea what the error is... FileUtils masks it and in
|
||||||
|
// some cases won't even report an error
|
||||||
|
throw new PathIOException(src.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy local files to a remote filesystem
|
||||||
|
*/
|
||||||
|
public static class Get extends CommandWithDestination {
|
||||||
|
public static final String NAME = "get";
|
||||||
|
public static final String USAGE =
|
||||||
|
"[-ignoreCrc] [-crc] <src> ... <localdst>";
|
||||||
|
public static final String DESCRIPTION =
|
||||||
|
"Copy files that match the file pattern <src>\n" +
|
||||||
|
"to the local name. <src> is kept. When copying multiple,\n" +
|
||||||
|
"files, the destination must be a directory.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The prefix for the tmp file used in copyToLocal.
|
||||||
|
* It must be at least three characters long, required by
|
||||||
|
* {@link java.io.File#createTempFile(String, String, File)}.
|
||||||
|
*/
|
||||||
|
private static final String COPYTOLOCAL_PREFIX = "_copyToLocal_";
|
||||||
|
private boolean copyCrc;
|
||||||
|
private boolean verifyChecksum;
|
||||||
|
private LocalFileSystem localFs;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processOptions(LinkedList<String> args)
|
||||||
|
throws IOException {
|
||||||
|
localFs = FileSystem.getLocal(getConf());
|
||||||
|
CommandFormat cf = new CommandFormat(
|
||||||
|
null, 1, Integer.MAX_VALUE, "crc", "ignoreCrc");
|
||||||
|
cf.parse(args);
|
||||||
|
copyCrc = cf.getOpt("crc");
|
||||||
|
verifyChecksum = !cf.getOpt("ignoreCrc");
|
||||||
|
|
||||||
|
setRecursive(true);
|
||||||
|
getLocalDestination(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPath(PathData src, PathData target)
|
||||||
|
throws IOException {
|
||||||
|
src.fs.setVerifyChecksum(verifyChecksum);
|
||||||
|
|
||||||
|
if (copyCrc && !(src.fs instanceof ChecksumFileSystem)) {
|
||||||
|
displayWarning(src.fs + ": Does not support checksums");
|
||||||
|
copyCrc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
File targetFile = localFs.pathToFile(target.path);
|
||||||
|
if (src.stat.isFile()) {
|
||||||
|
// copy the file and maybe its crc
|
||||||
|
copyFileToLocal(src, target.path);
|
||||||
|
if (copyCrc) {
|
||||||
|
copyCrcToLocal(src, target.path);
|
||||||
|
}
|
||||||
|
} else if (src.stat.isDirectory()) {
|
||||||
|
// create the remote directory structure locally
|
||||||
|
if (!targetFile.mkdirs()) {
|
||||||
|
throw new PathIOException(target.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new PathOperationException(src.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyFileToLocal(PathData src, Path target)
|
||||||
|
throws IOException {
|
||||||
|
File targetFile = localFs.pathToFile(target);
|
||||||
|
File tmpFile = FileUtil.createLocalTempFile(
|
||||||
|
targetFile, COPYTOLOCAL_PREFIX, true);
|
||||||
|
// too bad we can't tell exactly why it failed...
|
||||||
|
if (!FileUtil.copy(src.fs, src.path, tmpFile, false, getConf())) {
|
||||||
|
PathIOException e = new PathIOException(src.toString());
|
||||||
|
e.setOperation("copy");
|
||||||
|
e.setTargetPath(tmpFile.toString());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// too bad we can't tell exactly why it failed...
|
||||||
|
if (!tmpFile.renameTo(targetFile)) {
|
||||||
|
PathIOException e = new PathIOException(tmpFile.toString());
|
||||||
|
e.setOperation("rename");
|
||||||
|
e.setTargetPath(targetFile.toString());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyCrcToLocal(PathData src, Path target)
|
||||||
|
throws IOException {
|
||||||
|
ChecksumFileSystem srcFs = (ChecksumFileSystem)src.fs;
|
||||||
|
Path srcPath = srcFs.getChecksumFile(src.path);
|
||||||
|
src = new PathData(srcFs.getRawFileSystem(), srcPath);
|
||||||
|
copyFileToLocal(src, localFs.getChecksumFile(target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy local files to a remote filesystem
|
||||||
|
*/
|
||||||
|
public static class Put extends CommandWithDestination {
|
||||||
|
public static final String NAME = "put";
|
||||||
|
public static final String USAGE = "<localsrc> ... <dst>";
|
||||||
|
public static final String DESCRIPTION =
|
||||||
|
"Copy files from the local file system\n" +
|
||||||
|
"into fs.";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processOptions(LinkedList<String> args) throws IOException {
|
||||||
|
CommandFormat cf = new CommandFormat(null, 1, Integer.MAX_VALUE);
|
||||||
|
cf.parse(args);
|
||||||
|
getRemoteDestination(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// commands operating on local paths have no need for glob expansion
|
||||||
|
@Override
|
||||||
|
protected List<PathData> expandArgument(String arg) throws IOException {
|
||||||
|
List<PathData> items = new LinkedList<PathData>();
|
||||||
|
items.add(new PathData(new File(arg), getConf()));
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processArguments(LinkedList<PathData> args)
|
||||||
|
throws IOException {
|
||||||
|
// NOTE: this logic should be better, mimics previous implementation
|
||||||
|
if (args.size() == 1 && args.get(0).toString().equals("-")) {
|
||||||
|
if (dst.exists && !overwrite) {
|
||||||
|
throw new PathExistsException(dst.toString());
|
||||||
|
}
|
||||||
|
copyFromStdin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.processArguments(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPath(PathData src, PathData target)
|
||||||
|
throws IOException {
|
||||||
|
target.fs.copyFromLocalFile(false, false, src.path, target.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies from stdin to the destination file. */
|
||||||
|
protected void copyFromStdin() throws IOException {
|
||||||
|
FSDataOutputStream out = dst.fs.create(dst.path);
|
||||||
|
try {
|
||||||
|
IOUtils.copyBytes(System.in, out, getConf(), false);
|
||||||
|
} finally {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CopyFromLocal extends Put {
|
||||||
|
public static final String NAME = "copyFromLocal";
|
||||||
|
public static final String USAGE = Put.USAGE;
|
||||||
|
public static final String DESCRIPTION = "Identical to the -put command.";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CopyToLocal extends Get {
|
||||||
|
public static final String NAME = "copyToLocal";
|
||||||
|
public static final String USAGE = Get.USAGE;
|
||||||
|
public static final String DESCRIPTION = "Identical to the -get command.";
|
||||||
|
}
|
||||||
|
}
|
@ -43,7 +43,7 @@ abstract public class FsCommand extends Command {
|
|||||||
* @param factory where to register the class
|
* @param factory where to register the class
|
||||||
*/
|
*/
|
||||||
public static void registerCommands(CommandFactory factory) {
|
public static void registerCommands(CommandFactory factory) {
|
||||||
factory.registerCommands(Copy.class);
|
factory.registerCommands(CopyCommands.class);
|
||||||
factory.registerCommands(Count.class);
|
factory.registerCommands(Count.class);
|
||||||
factory.registerCommands(Delete.class);
|
factory.registerCommands(Delete.class);
|
||||||
factory.registerCommands(Display.class);
|
factory.registerCommands(Display.class);
|
||||||
@ -51,6 +51,7 @@ public static void registerCommands(CommandFactory factory) {
|
|||||||
factory.registerCommands(FsUsage.class);
|
factory.registerCommands(FsUsage.class);
|
||||||
factory.registerCommands(Ls.class);
|
factory.registerCommands(Ls.class);
|
||||||
factory.registerCommands(Mkdir.class);
|
factory.registerCommands(Mkdir.class);
|
||||||
|
factory.registerCommands(MoveCommands.class);
|
||||||
factory.registerCommands(SetReplication.class);
|
factory.registerCommands(SetReplication.class);
|
||||||
factory.registerCommands(Stat.class);
|
factory.registerCommands(Stat.class);
|
||||||
factory.registerCommands(Tail.class);
|
factory.registerCommands(Tail.class);
|
||||||
|
@ -127,9 +127,6 @@ private int maxLength(int n, Object value) {
|
|||||||
return Math.max(n, (value != null) ? String.valueOf(value).length() : 0);
|
return Math.max(n, (value != null) ? String.valueOf(value).length() : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int exitCodeForError() { return -1; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a recursive listing of all files in that match the file patterns.
|
* Get a recursive listing of all files in that match the file patterns.
|
||||||
* Same as "-ls -R"
|
* Same as "-ls -R"
|
||||||
|
98
src/java/org/apache/hadoop/fs/shell/MoveCommands.java
Normal file
98
src/java/org/apache/hadoop/fs/shell/MoveCommands.java
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/**
|
||||||
|
* 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.util.LinkedList;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
import org.apache.hadoop.fs.shell.CopyCommands.CopyFromLocal;
|
||||||
|
import org.apache.hadoop.fs.shell.PathExceptions.PathIOException;
|
||||||
|
|
||||||
|
/** Various commands for moving files */
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
|
||||||
|
class MoveCommands {
|
||||||
|
public static void registerCommands(CommandFactory factory) {
|
||||||
|
factory.addClass(MoveFromLocal.class, "-moveFromLocal");
|
||||||
|
factory.addClass(MoveToLocal.class, "-moveToLocal");
|
||||||
|
factory.addClass(Rename.class, "-mv");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move local files to a remote filesystem
|
||||||
|
*/
|
||||||
|
public static class MoveFromLocal extends CopyFromLocal {
|
||||||
|
public static final String NAME = "moveFromLocal";
|
||||||
|
public static final String USAGE = "<localsrc> ... <dst>";
|
||||||
|
public static final String DESCRIPTION =
|
||||||
|
"Same as -put, except that the source is\n" +
|
||||||
|
"deleted after it's copied.";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPath(PathData src, PathData target) throws IOException {
|
||||||
|
target.fs.moveFromLocalFile(src.path, target.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move remote files to a local filesystem
|
||||||
|
*/
|
||||||
|
public static class MoveToLocal extends FsCommand {
|
||||||
|
public static final String NAME = "moveToLocal";
|
||||||
|
public static final String USAGE = "<src> <localdst>";
|
||||||
|
public static final String DESCRIPTION = "Not implemented yet";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processOptions(LinkedList<String> args) throws IOException {
|
||||||
|
throw new IOException("Option '-moveToLocal' is not implemented yet.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** move/rename paths on the same fileystem */
|
||||||
|
public static class Rename extends CommandWithDestination {
|
||||||
|
public static final String NAME = "mv";
|
||||||
|
public static final String USAGE = "<src> ... <dst>";
|
||||||
|
public static final String DESCRIPTION =
|
||||||
|
"Move files that match the specified file pattern <src>\n" +
|
||||||
|
"to a destination <dst>. When moving multiple files, the\n" +
|
||||||
|
"destination must be a directory.";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processOptions(LinkedList<String> args) throws IOException {
|
||||||
|
CommandFormat cf = new CommandFormat(null, 2, Integer.MAX_VALUE);
|
||||||
|
cf.parse(args);
|
||||||
|
getRemoteDestination(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void processPath(PathData src, PathData target) throws IOException {
|
||||||
|
if (!src.fs.getUri().equals(target.fs.getUri())) {
|
||||||
|
throw new PathIOException(src.toString(),
|
||||||
|
"Does not match target filesystem");
|
||||||
|
}
|
||||||
|
if (!target.fs.rename(src.path, target.path)) {
|
||||||
|
// we have no way to know the actual error...
|
||||||
|
throw new PathIOException(src.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package org.apache.hadoop.fs.shell;
|
package org.apache.hadoop.fs.shell;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -58,6 +59,21 @@ public PathData(String pathString, Configuration conf) throws IOException {
|
|||||||
setStat(getStat(fs, path));
|
setStat(getStat(fs, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an object to wrap the given parameters as fields. The string
|
||||||
|
* used to create the path will be recorded since the Path object does not
|
||||||
|
* return exactly the same string used to initialize it
|
||||||
|
* @param localPath a local File
|
||||||
|
* @param conf the configuration file
|
||||||
|
* @throws IOException if anything goes wrong...
|
||||||
|
*/
|
||||||
|
public PathData(File localPath, Configuration conf) throws IOException {
|
||||||
|
this.string = localPath.toString();
|
||||||
|
this.path = new Path(this.string);
|
||||||
|
this.fs = FileSystem.getLocal(conf);
|
||||||
|
setStat(getStat(fs, path));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an object to wrap the given parameters as fields.
|
* Creates an object to wrap the given parameters as fields.
|
||||||
* @param fs the FileSystem
|
* @param fs the FileSystem
|
||||||
@ -156,6 +172,19 @@ public PathData[] getDirectoryContents() throws IOException {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new object for a child entry in this directory
|
||||||
|
* @param child the basename will be appended to this object's path
|
||||||
|
* @return PathData for the child
|
||||||
|
* @throws IOException if this object does not exist or is not a directory
|
||||||
|
*/
|
||||||
|
public PathData getPathDataForChild(PathData child) throws IOException {
|
||||||
|
if (!stat.isDirectory()) {
|
||||||
|
throw new PathIsNotDirectoryException(string);
|
||||||
|
}
|
||||||
|
return new PathData(fs, new Path(path, child.path.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand the given path as a glob pattern. Non-existent paths do not
|
* Expand the given path as a glob pattern. Non-existent paths do not
|
||||||
* throw an exception because creation commands like touch and mkdir need
|
* throw an exception because creation commands like touch and mkdir need
|
||||||
|
@ -40,7 +40,9 @@ public static class PathIOException extends IOException {
|
|||||||
// NOTE: this really should be a Path, but a Path is buggy and won't
|
// NOTE: this really should be a Path, but a Path is buggy and won't
|
||||||
// return the exact string used to construct the path, and it mangles
|
// return the exact string used to construct the path, and it mangles
|
||||||
// uris with no authority
|
// uris with no authority
|
||||||
|
private String operation;
|
||||||
private String path;
|
private String path;
|
||||||
|
private String targetPath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor a generic I/O error exception
|
* Constructor a generic I/O error exception
|
||||||
@ -74,17 +76,53 @@ protected PathIOException(String path, String error, Throwable cause) {
|
|||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Format:
|
||||||
|
* cmd: {operation} `path' {to `target'}: error string
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
String message = "`" + path + "': " + super.getMessage();
|
StringBuilder message = new StringBuilder();
|
||||||
if (getCause() != null) {
|
if (operation != null) {
|
||||||
message += ": " + getCause().getMessage();
|
message.append(operation + " ");
|
||||||
}
|
}
|
||||||
return message;
|
message.append(formatPath(path));
|
||||||
|
if (targetPath != null) {
|
||||||
|
message.append(" to " + formatPath(targetPath));
|
||||||
|
}
|
||||||
|
message.append(": " + super.getMessage());
|
||||||
|
if (getCause() != null) {
|
||||||
|
message.append(": " + getCause().getMessage());
|
||||||
|
}
|
||||||
|
return message.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return Path that generated the exception */
|
/** @return Path that generated the exception */
|
||||||
public Path getPath() { return new Path(path); }
|
public Path getPath() { return new Path(path); }
|
||||||
|
|
||||||
|
/** @return Path if the operation involved copying or moving, else null */
|
||||||
|
public Path getTargetPath() {
|
||||||
|
return (targetPath != null) ? new Path(targetPath) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional operation that will preface the path
|
||||||
|
* @param operation a string
|
||||||
|
*/
|
||||||
|
public void setOperation(String operation) {
|
||||||
|
this.operation = operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional path if the exception involved two paths, ex. a copy operation
|
||||||
|
* @param targetPath the of the operation
|
||||||
|
*/
|
||||||
|
public void setTargetPath(String targetPath) {
|
||||||
|
this.targetPath = targetPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatPath(String path) {
|
||||||
|
return "`" + path + "'";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** ENOENT */
|
/** ENOENT */
|
||||||
@ -144,4 +182,13 @@ public PathPermissionException(String path) {
|
|||||||
super(path, "Operation not permitted");
|
super(path, "Operation not permitted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ENOTSUP */
|
||||||
|
public static class PathOperationException extends PathExistsException {
|
||||||
|
static final long serialVersionUID = 0L;
|
||||||
|
/** @param path for the exception */
|
||||||
|
public PathOperationException(String path) {
|
||||||
|
super(path, "Operation not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -117,11 +117,11 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-get( )*\[-ignoreCrc\]( )*\[-crc\]( )*<src> <localdst>:( |\t)*Copy files that match the file pattern <src>( )*</expected-output>
|
<expected-output>^-get( )*\[-ignoreCrc\]( )*\[-crc\]( )*<src> \.\.\. <localdst>:( |\t)*Copy files that match the file pattern <src>( )*</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^( |\t)*to the local name.( )*<src> is kept.( )*When copying mutiple,( )*</expected-output>
|
<expected-output>^( |\t)*to the local name.( )*<src> is kept.( )*When copying multiple,( )*</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
@ -237,7 +237,7 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-mv <src> <dst>:( |\t)*Move files that match the specified file pattern <src>( )*</expected-output>
|
<expected-output>^-mv <src> \.\.\. <dst>:( |\t)*Move files that match the specified file pattern <src>( )*</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
@ -260,7 +260,7 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-cp <src> <dst>:( |\t)*Copy files that match the file pattern <src> to a( )*</expected-output>
|
<expected-output>^-cp <src> \.\.\. <dst>:( |\t)*Copy files that match the file pattern <src> to a( )*</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
@ -325,7 +325,7 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-put <localsrc> ... <dst>:( |\t)*Copy files from the local file system( )*</expected-output>
|
<expected-output>^-put <localsrc> \.\.\. <dst>:\s+Copy files from the local file system</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
@ -344,7 +344,7 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-copyFromLocal <localsrc> ... <dst>:( )*Identical to the -put command.( )*</expected-output>
|
<expected-output>^-copyFromLocal <localsrc> \.\.\. <dst>:\s+Identical to the -put command\.</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
</comparators>
|
</comparators>
|
||||||
</test>
|
</test>
|
||||||
@ -359,11 +359,11 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-moveFromLocal <localsrc> ... <dst>: Same as -put, except that the source is( )*</expected-output>
|
<expected-output>^-moveFromLocal <localsrc> \.\.\. <dst>:\s+Same as -put, except that the source is</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^( |\t)*deleted after it's copied.( )*</expected-output>
|
<expected-output>^( |\t)*deleted after it's copied.</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
</comparators>
|
</comparators>
|
||||||
</test>
|
</test>
|
||||||
@ -379,11 +379,11 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-get( )*\[-ignoreCrc\]( )*\[-crc\]( )*<src> <localdst>:( |\t)*Copy files that match the file pattern <src>( )*</expected-output>
|
<expected-output>^-get( )*\[-ignoreCrc\]( )*\[-crc\]( )*<src> \.\.\. <localdst>:( |\t)*Copy files that match the file pattern <src>( )*</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^( |\t)*to the local name.( )*<src> is kept.( )*When copying mutiple,( )*</expected-output>
|
<expected-output>^( |\t)*to the local name.( )*<src> is kept.( )*When copying multiple,( )*</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
@ -445,7 +445,7 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-copyToLocal \[-ignoreCrc\] \[-crc\] <src> <localdst>:( )*Identical to the -get command.( )*</expected-output>
|
<expected-output>^-copyToLocal \[-ignoreCrc\] \[-crc\] <src> \.\.\. <localdst>:\s+Identical to the -get command.</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
</comparators>
|
</comparators>
|
||||||
</test>
|
</test>
|
||||||
@ -460,7 +460,7 @@
|
|||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>RegexpComparator</type>
|
<type>RegexpComparator</type>
|
||||||
<expected-output>^-moveToLocal <src> <localdst>:( )*Not implemented yet( )*</expected-output>
|
<expected-output>^-moveToLocal <src> <localdst>:\s+Not implemented yet</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
</comparators>
|
</comparators>
|
||||||
</test>
|
</test>
|
||||||
|
@ -51,7 +51,7 @@ public class TestFsShellReturnCode {
|
|||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setup() throws IOException {
|
public static void setup() throws IOException {
|
||||||
conf.setClass("fs.file.impl", LocalFileSystemExtn.class, RawLocalFileSystem.class);
|
conf.setClass("fs.file.impl", LocalFileSystemExtn.class, LocalFileSystem.class);
|
||||||
fileSys = FileSystem.get(conf);
|
fileSys = FileSystem.get(conf);
|
||||||
fsShell = new FsShell(conf);
|
fsShell = new FsShell(conf);
|
||||||
}
|
}
|
||||||
@ -286,7 +286,7 @@ public void testGetWithInvalidSourcePathShouldNotDisplayNullInConsole()
|
|||||||
assertTrue("file exists", !fileSys.exists(new Path(args[1])));
|
assertTrue("file exists", !fileSys.exists(new Path(args[1])));
|
||||||
int run = shell.run(args);
|
int run = shell.run(args);
|
||||||
results = bytes.toString();
|
results = bytes.toString();
|
||||||
assertTrue("Return code should be -1", run == -1);
|
assertEquals("Return code should be 1", 1, run);
|
||||||
assertTrue(" Null is coming when source path is invalid. ",!results.contains("get: null"));
|
assertTrue(" Null is coming when source path is invalid. ",!results.contains("get: null"));
|
||||||
assertTrue(" Not displaying the intended message ",results.contains("get: `"+args[1]+"': No such file or directory"));
|
assertTrue(" Not displaying the intended message ",results.contains("get: `"+args[1]+"': No such file or directory"));
|
||||||
} finally {
|
} finally {
|
||||||
@ -326,7 +326,13 @@ public void testInvalidDefaultFS() throws Exception {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class LocalFileSystemExtn extends RawLocalFileSystem {
|
static class LocalFileSystemExtn extends LocalFileSystem {
|
||||||
|
public LocalFileSystemExtn() {
|
||||||
|
super(new RawLocalFileSystemExtn());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RawLocalFileSystemExtn extends RawLocalFileSystem {
|
||||||
protected static HashMap<String,String> owners = new HashMap<String,String>();
|
protected static HashMap<String,String> owners = new HashMap<String,String>();
|
||||||
protected static HashMap<String,String> groups = new HashMap<String,String>();
|
protected static HashMap<String,String> groups = new HashMap<String,String>();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user