nextflow.file.CopyMoveHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nxf-commons Show documentation
Show all versions of nxf-commons Show documentation
A DSL modelled around the UNIX pipe concept, that simplifies writing parallel and scalable pipelines in a portable manner
/*
* Copyright (c) 2013-2018, Centre for Genomic Regulation (CRG).
* Copyright (c) 2013-2018, Paolo Di Tommaso and the respective authors.
*
* This file is part of 'Nextflow'.
*
* Nextflow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Nextflow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Nextflow. If not, see .
*/
package nextflow.file;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.CopyOption;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper class to handle copy/move files and directories
*/
class CopyMoveHelper {
private static Logger log = LoggerFactory.getLogger(CopyMoveHelper.class);
private CopyMoveHelper() { }
/**
* Parses the arguments for a file copy operation.
*/
private static class CopyOptions {
boolean replaceExisting = false;
boolean copyAttributes = false;
boolean followLinks = true;
private CopyOptions() { }
static CopyOptions parse(CopyOption... options) {
CopyOptions result = new CopyOptions();
for (CopyOption option: options) {
if (option == StandardCopyOption.REPLACE_EXISTING) {
result.replaceExisting = true;
continue;
}
if (option == LinkOption.NOFOLLOW_LINKS) {
result.followLinks = false;
continue;
}
if (option == StandardCopyOption.COPY_ATTRIBUTES) {
result.copyAttributes = true;
continue;
}
if (option == null)
throw new NullPointerException();
throw new UnsupportedOperationException("'" + option +
"' is not a recognized copy option");
}
return result;
}
}
/**
* Converts the given array of options for moving a file to options suitable
* for copying the file when a move is implemented as copy + delete.
*/
private static CopyOption[] convertMoveToCopyOptions(CopyOption... options)
throws AtomicMoveNotSupportedException
{
int len = options.length;
CopyOption[] newOptions = new CopyOption[len+1];
for (int i=0; i visitor = new SimpleFileVisitor() {
public FileVisitResult preVisitDirectory(Path current, BasicFileAttributes attr)
throws IOException
{
// get the *delta* path against the source path
Path rel = source.relativize(current);
String delta = rel != null ? rel.toString() : null;
Path newFolder = delta != null ? target.resolve(delta) : target;
if(log.isTraceEnabled())
log.trace("Copy DIR: $current -> " + newFolder);
// this `copy` creates the new folder, but does not copy the contained files
Files.createDirectory(newFolder);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path current, BasicFileAttributes attr)
throws IOException
{
// get the *delta* path against the source path
Path rel = source.relativize(current);
String delta = rel != null ? rel.toString() : null;
Path newFile = delta != null ? target.resolve(delta) : target;
if( log.isTraceEnabled())
log.trace("Copy file: " + current + " -> "+newFile.toUri());
copyFile(current, newFile, foreign, options);
return FileVisitResult.CONTINUE;
}
};
Files.walkFileTree(source, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE, visitor);
}
/**
* Simple copy for use when source and target are associated with different
* providers
*/
static void copyToForeignTarget(Path source, Path target, CopyOption... options)
throws IOException
{
CopyOptions opts = CopyOptions.parse(options);
LinkOption[] linkOptions = (opts.followLinks) ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
// attributes of source file
BasicFileAttributes attrs = Files.readAttributes(source, BasicFileAttributes.class, linkOptions);
if (attrs.isSymbolicLink())
throw new IOException("Copying of symbolic links not supported");
// delete target if it exists and REPLACE_EXISTING is specified
if (opts.replaceExisting) {
FileHelper.deletePath(target);
}
else if (Files.exists(target))
throw new FileAlreadyExistsException(target.toString());
// create directory or copy file
if (attrs.isDirectory()) {
copyDirectory(source, target);
}
else {
copyFile(source, target, true);
}
}
/**
* Simple move implements as copy+delete for use when source and target are
* associated with different providers
*/
static void moveToForeignTarget(Path source, Path target, CopyOption... options)
throws IOException
{
copyToForeignTarget(source, target, convertMoveToCopyOptions(options));
FileHelper.deletePath(source);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy