mirror of https://github.com/sbt/sbt.git
88 lines
2.6 KiB
Scala
88 lines
2.6 KiB
Scala
/* sbt -- Simple Build Tool
|
|
* Copyright 2010 Mark Harrah
|
|
*/
|
|
package sbt
|
|
package inc
|
|
|
|
import java.io.File
|
|
import java.util.zip.ZipFile
|
|
import Function.const
|
|
|
|
object Locate
|
|
{
|
|
/** Right(src) provides the value for the found class
|
|
* Left(true) means that the class was found, but it had no associated value
|
|
* Left(false) means that the class was not found */
|
|
def value[S](classpath: Seq[File], get: File => String => Option[S]): String => Either[Boolean, S] =
|
|
{
|
|
val gets = classpath.toStream.map(getValue(get))
|
|
className => find(className, gets)
|
|
}
|
|
|
|
def find[S](name: String, gets: Stream[String => Either[Boolean, S]]): Either[Boolean, S] =
|
|
if(gets.isEmpty)
|
|
Left(false)
|
|
else
|
|
gets.head(name) match
|
|
{
|
|
case Left(false) => find(name, gets.tail)
|
|
case x => x
|
|
}
|
|
|
|
/** Returns a function that searches the provided class path for
|
|
* a class name and returns the entry that defines that class.*/
|
|
def entry(classpath: Seq[File]): String => Option[File] =
|
|
{
|
|
val entries = classpath.toStream.map { entry => (entry, definesClass(entry)) }
|
|
className => entries collect { case (entry, defines) if defines(className) => entry } headOption;
|
|
}
|
|
def resolve(f: File, className: String): File = if(f.isDirectory) classFile(f, className) else f
|
|
|
|
def getValue[S](get: File => String => Option[S])(entry: File): String => Either[Boolean, S] =
|
|
{
|
|
val defClass = definesClass(entry)
|
|
val getF = get(entry)
|
|
className => if(defClass(className)) getF(className).toRight(true) else Left(false)
|
|
}
|
|
|
|
def definesClass(entry: File): String => Boolean =
|
|
if(entry.isDirectory)
|
|
directoryDefinesClass(entry)
|
|
else if(entry.exists)
|
|
jarDefinesClass(entry)
|
|
else
|
|
const(false)
|
|
|
|
def jarDefinesClass(entry: File): String => Boolean =
|
|
{
|
|
import collection.JavaConversions._
|
|
val jar = new ZipFile(entry, ZipFile.OPEN_READ)
|
|
val entries = try { jar.entries.map(e => toClassName(e.getName)).toSet } finally { jar.close() }
|
|
entries.contains _
|
|
}
|
|
|
|
def toClassName(entry: String): String =
|
|
entry.stripSuffix(ClassExt).replace('/', '.')
|
|
|
|
val ClassExt = ".class"
|
|
|
|
def directoryDefinesClass(entry: File): String => Boolean =
|
|
className => classFile(entry, className).isFile
|
|
|
|
def classFile(baseDir: File, className: String): File =
|
|
{
|
|
val (pkg, name) = components(className)
|
|
val dir = subDirectory(baseDir, pkg)
|
|
new File(dir, name + ClassExt)
|
|
}
|
|
|
|
def subDirectory(base: File, parts: Seq[String]): File =
|
|
(base /: parts) ( (b, p) => new File(b,p) )
|
|
|
|
def components(className: String): (Seq[String], String) =
|
|
{
|
|
assume(!className.isEmpty)
|
|
val parts = className.split("\\.")
|
|
if(parts.length == 1) (Nil, parts(0)) else (parts.init, parts.last)
|
|
}
|
|
} |