summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/classpath/DirectoryFlatClassPath.scala
blob: 81d2f7320f979d2860741e7be6510d452a19112d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * Copyright (c) 2014 Contributor. All rights reserved.
 */
package scala.tools.nsc.classpath

import java.io.File
import java.io.FileFilter
import java.net.URL
import scala.reflect.io.AbstractFile
import scala.reflect.io.PlainFile
import scala.tools.nsc.util.ClassRepresentation
import FileUtils._

/**
 * A trait allowing to look for classpath entries of given type in directories.
 * It provides common logic for classes handling class and source files.
 * It makes use of the fact that in the case of nested directories it's easy to find a file
 * when we have a name of a package.
 */
trait DirectoryFileLookup[FileEntryType <: ClassRepClassPathEntry] extends FlatClassPath {
  val dir: File
  assert(dir != null, "Directory file in DirectoryFileLookup cannot be null")

  override def asURLs: Seq[URL] = Seq(dir.toURI.toURL)
  override def asClassPathStrings: Seq[String] = Seq(dir.getPath)

  import FlatClassPath.RootPackage
  private def getDirectory(forPackage: String): Option[File] = {
    if (forPackage == RootPackage) {
      Some(dir)
    } else {
      val packageDirName = FileUtils.dirPath(forPackage)
      val packageDir = new File(dir, packageDirName)
      if (packageDir.exists && packageDir.isDirectory) {
        Some(packageDir)
      } else None
    }
  }

  override private[nsc] def packages(inPackage: String): Seq[PackageEntry] = {
    val dirForPackage = getDirectory(inPackage)
    val nestedDirs: Array[File] = dirForPackage match {
      case None => Array.empty
      case Some(directory) => directory.listFiles(DirectoryFileLookup.packageDirectoryFileFilter)
    }
    val prefix = PackageNameUtils.packagePrefix(inPackage)
    val entries = nestedDirs map { file =>
      PackageEntryImpl(prefix + file.getName)
    }
    entries
  }

  protected def files(inPackage: String): Seq[FileEntryType] = {
    val dirForPackage = getDirectory(inPackage)
    val files: Array[File] = dirForPackage match {
      case None => Array.empty
      case Some(directory) => directory.listFiles(fileFilter)
    }
    val entries = files map { file =>
      val wrappedFile = new scala.reflect.io.File(file)
      createFileEntry(new PlainFile(wrappedFile))
    }
    entries
  }

  override private[nsc] def list(inPackage: String): FlatClassPathEntries = {
    val dirForPackage = getDirectory(inPackage)
    val files: Array[File] = dirForPackage match {
      case None => Array.empty
      case Some(directory) => directory.listFiles()
    }
    val packagePrefix = PackageNameUtils.packagePrefix(inPackage)
    val packageBuf = collection.mutable.ArrayBuffer.empty[PackageEntry]
    val fileBuf = collection.mutable.ArrayBuffer.empty[FileEntryType]
    for (file <- files) {
      if (file.isPackage) {
        val pkgEntry = PackageEntryImpl(packagePrefix + file.getName)
        packageBuf += pkgEntry
      } else if (fileFilter.accept(file)) {
        val wrappedFile = new scala.reflect.io.File(file)
        val abstractFile = new PlainFile(wrappedFile)
        fileBuf += createFileEntry(abstractFile)
      }
    }
    FlatClassPathEntries(packageBuf, fileBuf)
  }

  protected def createFileEntry(file: AbstractFile): FileEntryType
  protected def fileFilter: FileFilter
}

object DirectoryFileLookup {

  private[classpath] object packageDirectoryFileFilter extends FileFilter {
    override def accept(pathname: File): Boolean = pathname.isPackage
  }
}

case class DirectoryFlatClassPath(dir: File)
  extends DirectoryFileLookup[ClassFileEntryImpl]
  with NoSourcePaths {

  override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = findClassFile(className) map ClassFileEntryImpl

  override def findClassFile(className: String): Option[AbstractFile] = {
    val relativePath = FileUtils.dirPath(className)
    val classFile = new File(s"$dir/$relativePath.class")
    if (classFile.exists) {
      val wrappedClassFile = new scala.reflect.io.File(classFile)
      val abstractClassFile = new PlainFile(wrappedClassFile)
      Some(abstractClassFile)
    } else None
  }

  override protected def createFileEntry(file: AbstractFile): ClassFileEntryImpl = ClassFileEntryImpl(file)
  override protected def fileFilter: FileFilter = DirectoryFlatClassPath.classFileFilter

  override private[nsc] def classes(inPackage: String): Seq[ClassFileEntry] = files(inPackage)
}

object DirectoryFlatClassPath {

  private val classFileFilter = new FileFilter {
    override def accept(pathname: File): Boolean = pathname.isClass
  }
}

case class DirectoryFlatSourcePath(dir: File)
  extends DirectoryFileLookup[SourceFileEntryImpl]
  with NoClassPaths {

  override def asSourcePathString: String = asClassPathString

  override protected def createFileEntry(file: AbstractFile): SourceFileEntryImpl = SourceFileEntryImpl(file)
  override protected def fileFilter: FileFilter = DirectoryFlatSourcePath.sourceFileFilter

  override def findClass(className: String): Option[ClassRepresentation[AbstractFile]] = {
    findSourceFile(className) map SourceFileEntryImpl
  }

  private def findSourceFile(className: String): Option[AbstractFile] = {
    val relativePath = FileUtils.dirPath(className)
    val sourceFile = Stream("scala", "java")
      .map(ext => new File(s"$dir/$relativePath.$ext"))
      .collectFirst { case file if file.exists() => file }

    sourceFile.map { file =>
      val wrappedSourceFile = new scala.reflect.io.File(file)
      val abstractSourceFile = new PlainFile(wrappedSourceFile)
      abstractSourceFile
    }
  }

  override private[nsc] def sources(inPackage: String): Seq[SourceFileEntry] = files(inPackage)
}

object DirectoryFlatSourcePath {

  private val sourceFileFilter = new FileFilter {
    override def accept(pathname: File): Boolean = endsScalaOrJava(pathname.getName)
  }
}