2010-06-23 02:39:20 +08:00
|
|
|
package org.broadinstitute.sting.queue.util
|
|
|
|
|
|
2010-10-05 05:12:07 +08:00
|
|
|
import org.apache.commons.io.FileUtils
|
2010-10-27 03:49:08 +08:00
|
|
|
import java.io.{FileReader, File}
|
|
|
|
|
import org.broadinstitute.sting.utils.exceptions.UserException
|
2010-06-23 02:39:20 +08:00
|
|
|
|
2010-08-10 00:42:48 +08:00
|
|
|
/**
|
|
|
|
|
* A collection of utilities for modifying java.io.
|
|
|
|
|
*/
|
2010-06-23 02:39:20 +08:00
|
|
|
object IOUtils {
|
2010-08-10 00:42:48 +08:00
|
|
|
/** The current directory "." */
|
2010-06-23 02:39:20 +08:00
|
|
|
val CURRENT_DIR = new File(".")
|
|
|
|
|
|
2010-10-16 01:01:36 +08:00
|
|
|
val CURRENT_DIR_ABS = absolute(CURRENT_DIR)
|
|
|
|
|
|
2010-08-10 00:42:48 +08:00
|
|
|
/**
|
|
|
|
|
* Returns the sub path rooted at the parent.
|
|
|
|
|
* If the sub path is already absolute, returns the sub path.
|
|
|
|
|
* If the parent is the current directory, returns the sub path.
|
|
|
|
|
* If the sub bath is the current directory, returns the parent.
|
|
|
|
|
* Else returns new File(parent, subPath)
|
|
|
|
|
* @param parent The parent directory
|
|
|
|
|
* @param path The sub path to append to the parent, if the path is not absolute.
|
|
|
|
|
* @return The absolute path to the file in the parent dir if the path was not absolute, otherwise the original path.
|
|
|
|
|
*/
|
2010-10-16 01:01:36 +08:00
|
|
|
def subDir(parent: File, path: String): File =
|
|
|
|
|
subDir(parent, new File(path))
|
2010-08-10 00:42:48 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the sub path rooted at the parent.
|
|
|
|
|
* If the sub path is already absolute, returns the sub path.
|
|
|
|
|
* If the parent is the current directory, returns the sub path.
|
2010-08-12 05:58:26 +08:00
|
|
|
* If the sub path is the current directory, returns the parent.
|
2010-08-10 00:42:48 +08:00
|
|
|
* Else returns new File(parent, subPath)
|
|
|
|
|
* @param parent The parent directory
|
|
|
|
|
* @param file The sub path to append to the parent, if the path is not absolute.
|
|
|
|
|
* @return The absolute path to the file in the parent dir if the path was not absolute, otherwise the original path.
|
|
|
|
|
*/
|
|
|
|
|
def subDir(parent: File, file: File): File = {
|
2010-08-12 05:58:26 +08:00
|
|
|
val parentAbs = absolute(parent)
|
|
|
|
|
val fileAbs = absolute(file)
|
2010-10-16 01:01:36 +08:00
|
|
|
if (parentAbs == CURRENT_DIR_ABS && fileAbs == CURRENT_DIR_ABS)
|
|
|
|
|
CURRENT_DIR_ABS
|
|
|
|
|
else if (parentAbs == CURRENT_DIR_ABS || file.isAbsolute)
|
2010-08-12 05:58:26 +08:00
|
|
|
fileAbs
|
2010-10-16 01:01:36 +08:00
|
|
|
else if (fileAbs == CURRENT_DIR_ABS)
|
2010-08-12 05:58:26 +08:00
|
|
|
parentAbs
|
2010-06-23 02:39:20 +08:00
|
|
|
else
|
2010-08-12 05:58:26 +08:00
|
|
|
absolute(new File(parentAbs, file.getPath))
|
2010-06-23 02:39:20 +08:00
|
|
|
}
|
|
|
|
|
|
2010-10-27 03:49:08 +08:00
|
|
|
def checkTempDir = {
|
|
|
|
|
val javaTemp = System.getProperty("java.io.tmpdir")
|
|
|
|
|
// Keeps the user from leaving the temp directory as the default, and on Macs from having pluses
|
|
|
|
|
// in the path which can cause problems with the Google Reflections library.
|
|
|
|
|
// see also: http://benjchristensen.com/2009/09/22/mac-osx-10-6-java-java-io-tmpdir/
|
|
|
|
|
if (javaTemp.startsWith("/var/folders/") || (javaTemp == "/tmp") || (javaTemp == "/tmp/"))
|
|
|
|
|
throw new UserException.BadTmpDir("java.io.tmpdir must be explicitly set")
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-10 00:42:48 +08:00
|
|
|
/**
|
2010-10-05 05:12:07 +08:00
|
|
|
* Returns the temp directory as defined by java.
|
|
|
|
|
* @return the temp directory as defined by java.
|
|
|
|
|
*/
|
|
|
|
|
def javaTempDir() = {
|
2010-10-27 03:49:08 +08:00
|
|
|
val tempDir = new File(System.getProperty("java.io.tmpdir"))
|
2010-10-05 05:12:07 +08:00
|
|
|
if (!tempDir.exists && !tempDir.mkdirs)
|
2010-10-27 03:49:08 +08:00
|
|
|
throw new UserException.BadTmpDir("Could not create directory: " + tempDir.getAbsolutePath())
|
2010-10-05 05:12:07 +08:00
|
|
|
absolute(tempDir)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Creates a temp directory with the prefix and optional suffix.
|
2010-08-10 00:42:48 +08:00
|
|
|
* @param prefix Prefix for the directory name.
|
|
|
|
|
* @param suffix Optional suffix for the directory name. Defaults to "".
|
|
|
|
|
* @return The created temporary directory.
|
|
|
|
|
*/
|
|
|
|
|
def tempDir(prefix: String, suffix: String = "") = {
|
2010-10-05 05:12:07 +08:00
|
|
|
val tempDirParent = javaTempDir()
|
2010-08-24 04:38:42 +08:00
|
|
|
if (!tempDirParent.exists && !tempDirParent.mkdirs)
|
2010-10-27 03:49:08 +08:00
|
|
|
throw new UserException.BadTmpDir("Could not create temp directory: " + tempDirParent)
|
2010-08-10 00:42:48 +08:00
|
|
|
val temp = File.createTempFile(prefix + "-", suffix)
|
2010-08-24 04:38:42 +08:00
|
|
|
if (!temp.delete)
|
2010-10-27 03:49:08 +08:00
|
|
|
throw new UserException.BadTmpDir("Could not delete sub file: " + temp.getAbsolutePath())
|
2010-08-24 04:38:42 +08:00
|
|
|
if (!temp.mkdir)
|
2010-10-27 03:49:08 +08:00
|
|
|
throw new UserException.BadTmpDir("Could not create sub directory: " + temp.getAbsolutePath())
|
2010-08-12 05:58:26 +08:00
|
|
|
absolute(temp)
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-05 05:12:07 +08:00
|
|
|
def writeContents(file: File, content: String) = FileUtils.writeStringToFile(file, content)
|
|
|
|
|
|
2010-10-27 03:49:08 +08:00
|
|
|
def writeTempFile(content: String, prefix: String, suffix: String = "", directory: File) = {
|
2010-10-07 02:29:56 +08:00
|
|
|
val tempFile = absolute(File.createTempFile(prefix, suffix, directory))
|
2010-10-05 05:12:07 +08:00
|
|
|
writeContents(tempFile, content)
|
|
|
|
|
tempFile
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-12 05:58:26 +08:00
|
|
|
/**
|
|
|
|
|
* Returns the directory at the number of levels deep.
|
|
|
|
|
* For example 2 levels of /path/to/dir will return /path/to
|
|
|
|
|
* @param dir Directory path.
|
|
|
|
|
* @param level how many levels deep from the root.
|
|
|
|
|
* @return The path to the parent directory that is level-levels deep.
|
|
|
|
|
*/
|
|
|
|
|
def dirLevel(dir: File, level: Int): File = {
|
|
|
|
|
var directories = List.empty[File]
|
|
|
|
|
var parentDir = absolute(dir)
|
|
|
|
|
while (parentDir != null) {
|
|
|
|
|
directories +:= parentDir
|
|
|
|
|
parentDir = parentDir.getParentFile
|
|
|
|
|
}
|
|
|
|
|
if (directories.size <= level)
|
|
|
|
|
directories.last
|
|
|
|
|
else
|
|
|
|
|
directories(level)
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-07 02:29:56 +08:00
|
|
|
/**
|
|
|
|
|
* A mix of getCanonicalFile and getAbsoluteFile that returns the
|
|
|
|
|
* absolute path to the file without deferencing symbolic links.
|
|
|
|
|
* @param file the file.
|
|
|
|
|
* @return the absolute path to the file.
|
|
|
|
|
*/
|
2010-08-12 05:58:26 +08:00
|
|
|
def absolute(file: File) = {
|
|
|
|
|
var fileAbs = file.getAbsoluteFile
|
|
|
|
|
var names = List.empty[String]
|
|
|
|
|
while (fileAbs != null) {
|
|
|
|
|
val name = fileAbs.getName
|
|
|
|
|
fileAbs = fileAbs.getParentFile
|
|
|
|
|
|
|
|
|
|
if (name == ".") {
|
|
|
|
|
/* skip */
|
|
|
|
|
|
|
|
|
|
/* TODO: What do we do for ".."?
|
|
|
|
|
} else if (name == "..") {
|
|
|
|
|
|
|
|
|
|
CentOS tcsh says use getCanonicalFile:
|
|
|
|
|
~ $ mkdir -p test1/test2
|
|
|
|
|
~ $ ln -s test1/test2 test3
|
|
|
|
|
~ $ cd test3/..
|
|
|
|
|
~/test1 $
|
|
|
|
|
|
|
|
|
|
Mac bash says keep going with getAbsoluteFile:
|
|
|
|
|
~ $ mkdir -p test1/test2
|
|
|
|
|
~ $ ln -s test1/test2 test3
|
|
|
|
|
~ $ cd test3/..
|
|
|
|
|
~ $
|
|
|
|
|
|
|
|
|
|
For now, leave it and let the shell figure it out.
|
|
|
|
|
*/
|
|
|
|
|
} else {
|
|
|
|
|
names +:= name
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new File(names.mkString("/", "/", ""))
|
2010-08-10 00:42:48 +08:00
|
|
|
}
|
2010-10-07 02:29:56 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the last lines of the file.
|
|
|
|
|
* NOTE: This is only safe to run on smaller files!
|
|
|
|
|
* @param file File to read.
|
|
|
|
|
* @param count Maximum number of lines to return.
|
|
|
|
|
* @return The last count lines from file.
|
|
|
|
|
*/
|
|
|
|
|
def tail(file: File, count: Int) = {
|
|
|
|
|
var tailLines = List.empty[String]
|
|
|
|
|
var reader = new FileReader(file)
|
|
|
|
|
try {
|
|
|
|
|
val iterator = org.apache.commons.io.IOUtils.lineIterator(reader)
|
|
|
|
|
var lineCount = 0
|
|
|
|
|
while (iterator.hasNext) {
|
|
|
|
|
val line = iterator.nextLine
|
|
|
|
|
lineCount += 1
|
|
|
|
|
if (lineCount > count)
|
|
|
|
|
tailLines = tailLines.tail
|
|
|
|
|
tailLines :+= line
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
org.apache.commons.io.IOUtils.closeQuietly(reader)
|
|
|
|
|
}
|
|
|
|
|
tailLines
|
|
|
|
|
}
|
2010-06-23 02:39:20 +08:00
|
|
|
}
|