mirror of https://github.com/sbt/sbt.git
resolver keys, javaHome, scalaHome, and change Java source resolution
- rename resolvers to fullResolvers, baseResolvers to resolvers - if set, use javaHome for compilation as well as running - add scalaHome configuration for easily configuring scalaInstance for a local Scala installation - no longer require source roots for Java sources. Instead, resolve ambiguities by package name and then distance to root. Common package suffixes in different directories within the same project are a potential problem.
This commit is contained in:
parent
fc32a31abf
commit
77092b7888
|
|
@ -516,7 +516,7 @@ object Load
|
|||
|
||||
def build(classpath: Seq[File], sources: Seq[File], target: File, compilers: Compilers, log: Logger): (Inputs, inc.Analysis) =
|
||||
{
|
||||
val inputs = Compiler.inputs(classpath, sources, target, Nil, Nil, Nil, Compiler.DefaultMaxErrors)(compilers, log)
|
||||
val inputs = Compiler.inputs(classpath, sources, target, Nil, Nil, Compiler.DefaultMaxErrors)(compilers, log)
|
||||
val analysis = Compiler(inputs, log)
|
||||
(inputs, analysis)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,22 +24,22 @@ object Compiler
|
|||
|
||||
final class Inputs(val compilers: Compilers, val config: Options, val incSetup: IncSetup)
|
||||
final class Options(val classpath: Seq[File], val sources: Seq[File], val classesDirectory: File, val options: Seq[String], val javacOptions: Seq[String], val maxErrors: Int)
|
||||
final class IncSetup(val srcBases: Seq[File], val analysisMap: Map[File, Analysis], val cacheDirectory: File)
|
||||
final class IncSetup(val analysisMap: Map[File, Analysis], val cacheDirectory: File)
|
||||
final class Compilers(val scalac: AnalyzingCompiler, val javac: JavaCompiler)
|
||||
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], outputDirectory: File, options: Seq[String], javacOptions: Seq[String], srcBases: Seq[File], maxErrors: Int)(implicit compilers: Compilers, log: Logger): Inputs =
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], outputDirectory: File, options: Seq[String], javacOptions: Seq[String], maxErrors: Int)(implicit compilers: Compilers, log: Logger): Inputs =
|
||||
{
|
||||
import Path._
|
||||
val classesDirectory = outputDirectory / "classes"
|
||||
val cacheDirectory = outputDirectory / "cache"
|
||||
val augClasspath = classesDirectory.asFile +: classpath
|
||||
inputs(augClasspath, sources, classesDirectory, options, javacOptions, srcBases, Map.empty, cacheDirectory, maxErrors)
|
||||
inputs(augClasspath, sources, classesDirectory, options, javacOptions, Map.empty, cacheDirectory, maxErrors)
|
||||
}
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], srcBases: Seq[File], analysisMap: Map[File, Analysis], cacheDirectory: File, maxErrors: Int)(implicit compilers: Compilers, log: Logger): Inputs =
|
||||
def inputs(classpath: Seq[File], sources: Seq[File], classesDirectory: File, options: Seq[String], javacOptions: Seq[String], analysisMap: Map[File, Analysis], cacheDirectory: File, maxErrors: Int)(implicit compilers: Compilers, log: Logger): Inputs =
|
||||
new Inputs(
|
||||
compilers,
|
||||
new Options(classpath, sources, classesDirectory, options, javacOptions, maxErrors),
|
||||
new IncSetup(srcBases, analysisMap, cacheDirectory)
|
||||
new IncSetup(analysisMap, cacheDirectory)
|
||||
)
|
||||
|
||||
def compilers(implicit app: AppConfiguration, log: Logger): Compilers =
|
||||
|
|
@ -49,14 +49,14 @@ object Compiler
|
|||
}
|
||||
|
||||
def compilers(instance: ScalaInstance)(implicit app: AppConfiguration, log: Logger): Compilers =
|
||||
compilers(instance, ClasspathOptions.auto)
|
||||
compilers(instance, ClasspathOptions.auto, None)
|
||||
|
||||
def compilers(instance: ScalaInstance, javac: (Seq[String], Logger) => Int)(implicit app: AppConfiguration, log: Logger): Compilers =
|
||||
compilers(instance, ClasspathOptions.auto, javac)
|
||||
|
||||
def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions)(implicit app: AppConfiguration, log: Logger): Compilers =
|
||||
def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File])(implicit app: AppConfiguration, log: Logger): Compilers =
|
||||
{
|
||||
val javac = JavaCompiler.directOrFork(cpOptions, instance)( (args: Seq[String], log: Logger) => Process("javac", args) ! log )
|
||||
val javac = directOrFork(instance, cpOptions, javaHome)
|
||||
compilers(instance, cpOptions, javac)
|
||||
}
|
||||
def compilers(instance: ScalaInstance, cpOptions: ClasspathOptions, javac: (Seq[String], Logger) => Int)(implicit app: AppConfiguration, log: Logger): Compilers =
|
||||
|
|
@ -75,6 +75,21 @@ object Compiler
|
|||
val componentManager = new ComponentManager(launcher.globalLock, app.provider.components, log)
|
||||
new AnalyzingCompiler(instance, componentManager, cpOptions, log)
|
||||
}
|
||||
def directOrFork(instance: ScalaInstance, cpOptions: ClasspathOptions, javaHome: Option[File]): JavaCompiler =
|
||||
if(javaHome.isDefined)
|
||||
JavaCompiler.fork(cpOptions, instance)(forkJavac(javaHome))
|
||||
else
|
||||
JavaCompiler.directOrFork(cpOptions, instance)( forkJavac(None) )
|
||||
|
||||
def forkJavac(javaHome: Option[File]): (Seq[String], Logger) => Int =
|
||||
{
|
||||
import Path._
|
||||
val exec = javaHome match { case None => "javac"; case Some(jh) => (jh / "bin" / "javac").absolutePath }
|
||||
(args: Seq[String], log: Logger) => {
|
||||
log.debug("Forking javac: " + exec + " " + args.mkString(" "))
|
||||
Process(exec, args) ! log
|
||||
}
|
||||
}
|
||||
|
||||
def apply(in: Inputs, log: Logger): Analysis =
|
||||
{
|
||||
|
|
@ -83,6 +98,6 @@ object Compiler
|
|||
import in.incSetup._
|
||||
|
||||
val agg = new build.AggressiveCompile(cacheDirectory)
|
||||
agg(scalac, javac, sources, classpath, classesDirectory, srcBases, options, javacOptions, analysisMap, maxErrors)(log)
|
||||
agg(scalac, javac, sources, classpath, classesDirectory, options, javacOptions, analysisMap, maxErrors)(log)
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,8 @@ object Defaults
|
|||
(cp map extractAnalysis).toMap
|
||||
|
||||
def buildCore: Seq[Setting[_]] = inScope(GlobalScope)(Seq(
|
||||
pollInterval :== 1,
|
||||
pollInterval :== 500,
|
||||
scalaHome :== None,
|
||||
javaHome :== None,
|
||||
outputStrategy :== None,
|
||||
fork :== false,
|
||||
|
|
@ -94,9 +95,8 @@ object Defaults
|
|||
sources <<= (sourceDirectories, sourceFilter, defaultExcludes) map { (d,f,excl) => d.descendentsExcept(f,excl).getFiles.toSeq },
|
||||
scalaSource <<= sourceDirectory / "scala",
|
||||
javaSource <<= sourceDirectory / "java",
|
||||
javaSourceRoots <<= toSeq(javaSource),
|
||||
resourceDirectory <<= sourceDirectory / "resources",
|
||||
sourceDirectories <<= (scalaSource, javaSourceRoots) { _ +: _ },
|
||||
sourceDirectories <<= (scalaSource, javaSource) { _ :: _ :: Nil },
|
||||
resourceDirectories <<= toSeq(resourceDirectory),
|
||||
resources <<= (resourceDirectories, defaultExcludes) map { (dirs, excl) => dirs.descendentsExcept("*",excl).getFiles.toSeq }
|
||||
)
|
||||
|
|
@ -110,10 +110,10 @@ object Defaults
|
|||
|
||||
def compileBase = Seq(
|
||||
classpathOptions in GlobalScope :== ClasspathOptions.auto,
|
||||
compilers <<= (scalaInstance, appConfiguration, streams, classpathOptions) map { (si, app, s, co) => Compiler.compilers(si, co)(app, s.log) },
|
||||
compilers <<= (scalaInstance, appConfiguration, streams, classpathOptions, javaHome) map { (si, app, s, co, jh) => Compiler.compilers(si, co, jh)(app, s.log) },
|
||||
javacOptions in GlobalScope :== Nil,
|
||||
scalacOptions in GlobalScope :== Nil,
|
||||
scalaInstance <<= (appConfiguration, scalaVersion){ (app, version) => ScalaInstance(version, app.provider.scalaProvider.launcher) },
|
||||
scalaInstance <<= scalaInstanceSetting,
|
||||
scalaVersion <<= appConfiguration( _.provider.scalaProvider.version),
|
||||
target <<= (target, scalaInstance, crossPaths)( (t,si,cross) => if(cross) t / ("scala-" + si.actualVersion) else t )
|
||||
)
|
||||
|
|
@ -165,6 +165,13 @@ object Defaults
|
|||
override def watchPaths(s: State) = EvaluateTask.evaluateTask(Project structure s, key, s, base) match { case Some(Value(ps)) => ps; case _ => Nil }
|
||||
}
|
||||
}
|
||||
def scalaInstanceSetting = (appConfiguration, scalaVersion, scalaHome){ (app, version, home) =>
|
||||
val launcher = app.provider.scalaProvider.launcher
|
||||
home match {
|
||||
case None => ScalaInstance(version, launcher)
|
||||
case Some(h) => ScalaInstance(h, launcher)
|
||||
}
|
||||
}
|
||||
|
||||
lazy val testTasks = Seq(
|
||||
testLoader <<= (fullClasspath, scalaInstance) map { (cp, si) => TestFramework.createTestLoader(data(cp), si) },
|
||||
|
|
@ -296,12 +303,12 @@ object Defaults
|
|||
|
||||
def compileTask = (compileInputs, streams) map { (i,s) => Compiler(i,s.log) }
|
||||
def compileInputsTask =
|
||||
(dependencyClasspath, sources, javaSourceRoots, compilers, javacOptions, scalacOptions, cacheDirectory, classDirectory, streams) map {
|
||||
(cp, srcs, javaRoots, cs, javacOpts, scalacOpts, cacheDir, classes, s) =>
|
||||
(dependencyClasspath, sources, compilers, javacOptions, scalacOptions, cacheDirectory, classDirectory, streams) map {
|
||||
(cp, srcs, cs, javacOpts, scalacOpts, cacheDir, classes, s) =>
|
||||
val classpath = classes +: data(cp)
|
||||
val analysis = analysisMap(cp)
|
||||
val cache = cacheDir / "compile"
|
||||
Compiler.inputs(classpath, srcs, classes, scalacOpts, javacOpts, javaRoots, analysis, cache, 100)(cs, s.log)
|
||||
Compiler.inputs(classpath, srcs, classes, scalacOpts, javacOpts, analysis, cache, 100)(cs, s.log)
|
||||
}
|
||||
|
||||
def copyResourcesTask =
|
||||
|
|
@ -416,7 +423,7 @@ object Classpaths
|
|||
normalizedName <<= name(StringUtilities.normalize),
|
||||
organization :== normalizedName,
|
||||
classpathFilter in GlobalScope :== "*.jar",
|
||||
resolvers <<= (projectResolver,baseResolvers).map( (pr,rs) => pr +: Resolver.withDefaultResolvers(rs)),
|
||||
fullResolvers <<= (projectResolver,resolvers).map( (pr,rs) => pr +: Resolver.withDefaultResolvers(rs)),
|
||||
offline in GlobalScope :== false,
|
||||
moduleID :== normalizedName,
|
||||
defaultConfiguration in GlobalScope :== Some(Configurations.Compile),
|
||||
|
|
@ -440,12 +447,12 @@ object Classpaths
|
|||
pomArtifact <<= (publishMavenStyle, moduleID)( (mavenStyle, name) => if(mavenStyle) Artifact(name, "pom", "pom") :: Nil else Nil),
|
||||
artifacts <<= (pomArtifact,moduleID)( (pom,name) => Artifact(name) +: pom),
|
||||
projectID <<= (organization,moduleID,version,artifacts){ (org,module,version,as) => ModuleID(org, module, version).cross(true).artifacts(as : _*) },
|
||||
baseResolvers in GlobalScope :== Nil,
|
||||
resolvers in GlobalScope :== Nil,
|
||||
projectDescriptors <<= depMap,
|
||||
retrievePattern :== "[type]/[organisation]/[module]/[artifact](-[revision])(-[classifier]).[ext]",
|
||||
updateConfiguration <<= (retrieveConfiguration, ivyLoggingLevel)((conf,level) => new UpdateConfiguration(conf, level) ),
|
||||
retrieveConfiguration :== None, //Some(new RetrieveConfiguration(managedDependencyPath asFile, retrievePattern, true))
|
||||
ivyConfiguration <<= (resolvers, ivyPaths, otherResolvers, moduleConfigurations, offline, appConfiguration) map { (rs, paths, other, moduleConfs, off, app) =>
|
||||
ivyConfiguration <<= (fullResolvers, ivyPaths, otherResolvers, moduleConfigurations, offline, appConfiguration) map { (rs, paths, other, moduleConfs, off, app) =>
|
||||
// todo: pass logger from streams directly to IvyActions
|
||||
val lock = app.provider.scalaProvider.launcher.globalLock
|
||||
new InlineIvyConfiguration(paths, rs, other, moduleConfs, off, Some(lock), ConsoleLogger())
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ object Keys
|
|||
val sourceManaged = SettingKey[File]("source-managed")
|
||||
val scalaSource = SettingKey[File]("scala-source")
|
||||
val javaSource = SettingKey[File]("java-source")
|
||||
val javaSourceRoots = SettingKey[Seq[File]]("java-source-roots")
|
||||
val resourceDirectory = SettingKey[File]("resource-directory")
|
||||
val sourceDirectories = SettingKey[Seq[File]]("source-directories")
|
||||
val resourceDirectories = SettingKey[Seq[File]]("resource-directories")
|
||||
|
|
@ -70,6 +69,7 @@ object Keys
|
|||
val javacOptions = SettingKey[Seq[String]]("javac-options")
|
||||
val initialCommands = SettingKey[String]("initial-commands")
|
||||
val compileInputs = TaskKey[Compiler.Inputs]("compile-inputs")
|
||||
val scalaHome = SettingKey[Option[File]]("scala-home")
|
||||
val scalaInstance = SettingKey[ScalaInstance]("scala-instance")
|
||||
val scalaVersion = SettingKey[String]("scala-version")
|
||||
val classpathOptions = SettingKey[ClasspathOptions]("classpath-options")
|
||||
|
|
@ -164,9 +164,9 @@ object Keys
|
|||
val moduleID = SettingKey[String]("module-id")
|
||||
val version = SettingKey[String]("version")
|
||||
val projectID = SettingKey[ModuleID]("project-id")
|
||||
val baseResolvers = SettingKey[Seq[Resolver]]("base-resolvers")
|
||||
val resolvers = SettingKey[Seq[Resolver]]("resolvers")
|
||||
val projectResolver = TaskKey[Resolver]("project-resolver")
|
||||
val resolvers = TaskKey[Seq[Resolver]]("resolvers")
|
||||
val fullResolvers = TaskKey[Seq[Resolver]]("full-resolvers")
|
||||
val otherResolvers = SettingKey[Seq[Resolver]]("other-resolvers")
|
||||
val moduleConfigurations = SettingKey[Seq[ModuleConfiguration]]("module-configurations")
|
||||
val retrievePattern = SettingKey[String]("retrieve-pattern")
|
||||
|
|
|
|||
|
|
@ -15,25 +15,25 @@ import inc._
|
|||
import CompileSetup._
|
||||
import sbinary.DefaultProtocol.{ immutableMapFormat, immutableSetFormat, StringFormat }
|
||||
|
||||
final class CompileConfiguration(val sources: Seq[File], val classpath: Seq[File], val javaSrcBases: Seq[File],
|
||||
final class CompileConfiguration(val sources: Seq[File], val classpath: Seq[File],
|
||||
val previousAnalysis: Analysis, val previousSetup: Option[CompileSetup], val currentSetup: CompileSetup, val getAnalysis: File => Option[Analysis],
|
||||
val maxErrors: Int, val compiler: AnalyzingCompiler, val javac: JavaCompiler)
|
||||
|
||||
class AggressiveCompile(cacheDirectory: File)
|
||||
{
|
||||
def apply(compiler: AnalyzingCompiler, javac: JavaCompiler, sources: Seq[File], classpath: Seq[File], outputDirectory: File, javaSrcBases: Seq[File] = Nil, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: Map[File, Analysis] = Map.empty, maxErrors: Int = 100)(implicit log: Logger): Analysis =
|
||||
def apply(compiler: AnalyzingCompiler, javac: JavaCompiler, sources: Seq[File], classpath: Seq[File], outputDirectory: File, options: Seq[String] = Nil, javacOptions: Seq[String] = Nil, analysisMap: Map[File, Analysis] = Map.empty, maxErrors: Int = 100)(implicit log: Logger): Analysis =
|
||||
{
|
||||
val setup = new CompileSetup(outputDirectory, new CompileOptions(options, javacOptions), compiler.scalaInstance.actualVersion, CompileOrder.Mixed)
|
||||
compile1(sources, classpath, javaSrcBases, setup, store, analysisMap, compiler, javac, maxErrors)
|
||||
compile1(sources, classpath, setup, store, analysisMap, compiler, javac, maxErrors)
|
||||
}
|
||||
|
||||
def withBootclasspath(args: CompilerArguments, classpath: Seq[File]): Seq[File] =
|
||||
args.bootClasspath ++ args.finishClasspath(classpath)
|
||||
|
||||
def compile1(sources: Seq[File], classpath: Seq[File], javaSrcBases: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: Map[File, Analysis], compiler: AnalyzingCompiler, javac: JavaCompiler, maxErrors: Int)(implicit log: Logger): Analysis =
|
||||
def compile1(sources: Seq[File], classpath: Seq[File], setup: CompileSetup, store: AnalysisStore, analysis: Map[File, Analysis], compiler: AnalyzingCompiler, javac: JavaCompiler, maxErrors: Int)(implicit log: Logger): Analysis =
|
||||
{
|
||||
val (previousAnalysis, previousSetup) = extract(store.get())
|
||||
val config = new CompileConfiguration(sources, classpath, javaSrcBases, previousAnalysis, previousSetup, setup, analysis.get _, maxErrors, compiler, javac)
|
||||
val config = new CompileConfiguration(sources, classpath, previousAnalysis, previousSetup, setup, analysis.get _, maxErrors, compiler, javac)
|
||||
val (modified, result) = compile2(config)
|
||||
if(modified)
|
||||
store.set(result, setup)
|
||||
|
|
@ -68,7 +68,7 @@ class AggressiveCompile(cacheDirectory: File)
|
|||
import Path._
|
||||
val loader = ClasspathUtilities.toLoader(absClasspath, compiler.scalaInstance.loader)
|
||||
def readAPI(source: File, classes: Seq[Class[_]]) { callback.api(source, ClassToAPI(classes)) }
|
||||
Analyze(outputDirectory, javaSrcs, javaSrcBases, log)(callback, loader, readAPI) {
|
||||
Analyze(outputDirectory, javaSrcs, log)(callback, loader, readAPI) {
|
||||
javac(javaSrcs, absClasspath, outputDirectory, options.javacOptions)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ import java.lang.reflect.Modifier.{STATIC, PUBLIC, ABSTRACT}
|
|||
|
||||
private[sbt] object Analyze
|
||||
{
|
||||
def apply[T](outputDirectory: Path, sources: Seq[Path], roots: Seq[Path], log: Logger)(analysis: xsbti.AnalysisCallback, loader: ClassLoader, readAPI: (File,Seq[Class[_]]) => Unit)(compile: => Unit)
|
||||
def apply[T](outputDirectory: Path, sources: Seq[File], log: Logger)(analysis: xsbti.AnalysisCallback, loader: ClassLoader, readAPI: (File,Seq[Class[_]]) => Unit)(compile: => Unit)
|
||||
{
|
||||
val sourceSet = Set(sources.toSeq : _*)
|
||||
val sourceMap = sources.groupBy(_.getName)
|
||||
val classesFinder = outputDirectory ** GlobFilter("*.class")
|
||||
val existingClasses = classesFinder.get
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ private[sbt] object Analyze
|
|||
path <- Path.relativize(outputDirectory, newClass);
|
||||
classFile = Parser(newClass.asFile);
|
||||
sourceFile <- classFile.sourceFile orElse guessSourceName(newClass.asFile.getName);
|
||||
source <- guessSourcePath(sourceSet, roots, classFile, log))
|
||||
source <- guessSourcePath(sourceMap, classFile, log))
|
||||
{
|
||||
analysis.beginSource(source)
|
||||
analysis.generatedClass(source, path)
|
||||
|
|
@ -102,23 +102,54 @@ private[sbt] object Analyze
|
|||
private final val ClassExt = ".class"
|
||||
private def trimClassExt(name: String) = if(name.endsWith(ClassExt)) name.substring(0, name.length - ClassExt.length) else name
|
||||
private def resolveClassFile(file: File, className: String): File = (file /: (className.replace('.','/') + ClassExt).split("/"))(new File(_, _))
|
||||
private def guessSourcePath(sources: scala.collection.Set[Path], roots: Iterable[Path], classFile: ClassFile, log: Logger) =
|
||||
private def guessSourcePath(sourceNameMap: Map[String, Iterable[File]], classFile: ClassFile, log: Logger) =
|
||||
{
|
||||
val classNameParts = classFile.className.split("""\.""")
|
||||
val lastIndex = classNameParts.length - 1
|
||||
val pkg = classNameParts.take(lastIndex)
|
||||
val simpleClassName = classNameParts(lastIndex)
|
||||
val pkg = classNameParts.init
|
||||
val simpleClassName = classNameParts.last
|
||||
val sourceFileName = classFile.sourceFile.getOrElse(simpleClassName.takeWhile(_ != '$').mkString("", "", ".java"))
|
||||
val relativeSourceFile = (pkg ++ (sourceFileName :: Nil)).mkString("/")
|
||||
val candidates = roots.map(root => Path.fromString(root, relativeSourceFile)).filter(sources.contains).toList
|
||||
val candidates = findSource(sourceNameMap, pkg.toList, sourceFileName)
|
||||
candidates match
|
||||
{
|
||||
case Nil => log.warn("Could not determine source for class " + classFile.className)
|
||||
case head :: Nil => ()
|
||||
case _ =>log.warn("Multiple sources matched for class " + classFile.className + ": " + candidates.mkString(", "))
|
||||
case _ => log.warn("Multiple sources matched for class " + classFile.className + ": " + candidates.mkString(", "))
|
||||
}
|
||||
candidates
|
||||
}
|
||||
private def findSource(sourceNameMap: Map[String, Iterable[File]], pkg: List[String], sourceFileName: String): List[File] =
|
||||
refine( (sourceNameMap get sourceFileName).toList.flatten map { x => (x,x) }, pkg.reverse)
|
||||
|
||||
private def refine(sources: List[(File, File)], pkgRev: List[String]): List[File] =
|
||||
{
|
||||
def make = sources.map(_._1)
|
||||
if(sources.isEmpty || sources.tail.isEmpty)
|
||||
make
|
||||
else
|
||||
pkgRev match
|
||||
{
|
||||
case Nil => shortest(make)
|
||||
case x :: xs =>
|
||||
val retain = sources flatMap { case (src, pre) =>
|
||||
if(pre != null && pre.getName == x)
|
||||
(src, pre.getParentFile) :: Nil
|
||||
else
|
||||
Nil
|
||||
}
|
||||
refine(retain, xs)
|
||||
}
|
||||
}
|
||||
private def shortest(files: List[File]): List[File] =
|
||||
if(files.isEmpty) files
|
||||
else
|
||||
{
|
||||
val fs = files.groupBy(distanceToRoot(0))
|
||||
fs(fs.keys.min)
|
||||
}
|
||||
|
||||
private def distanceToRoot(acc: Int)(file: File): Int =
|
||||
if(file == null) acc else distanceToRoot(acc + 1)(file.getParentFile)
|
||||
|
||||
private def isTopLevel(classFile: ClassFile) = classFile.className.indexOf('$') < 0
|
||||
private lazy val unit = classOf[Unit]
|
||||
private lazy val strArray = List(classOf[Array[String]])
|
||||
|
|
|
|||
Loading…
Reference in New Issue