diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/plugins/Plugin.scala | 91 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/plugins/Plugins.scala | 146 | ||||
-rw-r--r-- | src/library/scala/io/File.scala | 2 |
4 files changed, 100 insertions, 149 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 02d65d7e05..56b8253fa7 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -623,18 +623,12 @@ class Global(var settings: Settings, var reporter: Reporter) extends SymbolTable buildCompilerFromPhasesSet() // PhaseAssembly.scala } - /* Simple option value to hold the compiler phase chain */ - private var phasesCache: Option[List[SubComponent]] = None + /* The phase descriptor list */ + lazy val phaseDescriptors: List[SubComponent] = computePhaseDescriptors /* The set of phase objects that is the basis for the compiler phase chain */ protected val phasesSet : HashSet[SubComponent] = new HashSet[SubComponent] - /** A accessor for the phase descriptor list (List of SubComponents), Only calculate the list once */ - def phaseDescriptors = { - if (phasesCache.isEmpty) phasesCache = Some(computePhaseDescriptors) - phasesCache.get - } - /** A description of the phases that will run */ def phaseDescriptions: String = { new Run // force some initialization diff --git a/src/compiler/scala/tools/nsc/plugins/Plugin.scala b/src/compiler/scala/tools/nsc/plugins/Plugin.scala index 3013199c36..a7b686e750 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugin.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugin.scala @@ -7,7 +7,7 @@ package scala.tools.nsc package plugins -import java.io.File +import scala.io.{ File, Path } import java.net.URLClassLoader import java.util.jar.JarFile import java.util.zip.ZipException @@ -63,39 +63,44 @@ abstract class Plugin { * @author Lex Spoon * @version 1.0, 2007-5-21 */ -object Plugin { +object Plugin +{ + private val PluginXML = "scalac-plugin.xml" + /** Create a class loader with the specified file plus * the loader that loaded the Scala compiler. */ - private def loaderFor(jarfiles: Seq[File]): ClassLoader = { + private def loaderFor(jarfiles: Seq[Path]): ClassLoader = { val compilerLoader = classOf[Plugin].getClassLoader - val jarurls = jarfiles.map(_.toURL).toArray - new URLClassLoader(jarurls, compilerLoader) + val jarurls = jarfiles map (_.toURL) + + new URLClassLoader(jarurls.toArray, compilerLoader) } /** Try to load a plugin description from the specified * file, returning None if it does not work. */ - private def loadDescription(jarfile: File): Option[PluginDescription] = { - if (!jarfile.exists) return None + private def loadDescription(jarfile: Path): Option[PluginDescription] = + // XXX Return to this once we have some ARM support + if (!jarfile.exists) None + else try { + val jar = new JarFile(jarfile.jfile) - try { - val jar = new JarFile(jarfile) try { - val ent = jar.getEntry("scalac-plugin.xml") - if (ent == null) return None - - val inBytes = jar.getInputStream(ent) - val packXML = XML.load(inBytes) - inBytes.close() - - PluginDescription.fromXML(packXML) - } finally { - jar.close() + (jar getEntry PluginXML) match { + case null => None + case entry => + val in = jar getInputStream entry + val packXML = XML load in + in.close() + + PluginDescription fromXML packXML + } } - } catch { + finally jar.close() + } + catch { case _: ZipException => None } - } type AnyClass = Class[_] @@ -103,16 +108,13 @@ object Plugin { * if the jar file has no plugin in it or if the plugin * is badly formed. */ - def loadFrom(jarfile: File, loader: ClassLoader): Option[AnyClass] = { + def loadFrom(jarfile: Path, loader: ClassLoader): Option[AnyClass] = { val pluginInfo = loadDescription(jarfile).get - try { - Some(loader.loadClass(pluginInfo.classname)) - } catch { - case _:ClassNotFoundException => - println("Warning: class not found for plugin in " + jarfile + - " (" + pluginInfo.classname + ")") - None + try Some(loader loadClass pluginInfo.classname) catch { + case _: ClassNotFoundException => + println("Warning: class not found for plugin in %s (%s)".format(jarfile, pluginInfo.classname)) + None } } @@ -121,35 +123,28 @@ object Plugin { * directories specified. Skips all plugins in <code>ignoring</code>. * A single classloader is created and used to load all of them. */ - def loadAllFrom(jars: List[File], - dirs: List[File], - ignoring: List[String]): List[AnyClass] = + def loadAllFrom( + jars: List[Path], + dirs: List[Path], + ignoring: List[String]): List[AnyClass] = { - val alljars = new ListBuffer[File] - - alljars ++= jars - - for { + val alljars = jars ::: (for { dir <- dirs if dir.isDirectory - entries = dir.listFiles - if entries ne null - entry <- entries.toList.sort(_.getName <= _.getName) - if entry.toString.toLowerCase endsWith ".jar" + entry <- dir.toDirectory.files.toList sortWith (_.name <= _.name) + if entry.name.toLowerCase endsWith ".jar" pdesc <- loadDescription(entry) if !(ignoring contains pdesc.name) - } alljars += entry + } yield entry) - val loader = loaderFor(alljars.toList) - alljars.toList.map(f => loadFrom(f,loader)).flatMap(x => x) + val loader = loaderFor(alljars) + alljars map (loadFrom(_, loader)) flatten } /** Instantiate a plugin class, given the class and * the compiler it is to be used in. */ def instantiate(clazz: AnyClass, global: Global): Plugin = { - //println("instantiating "+clazz) - //println(clazz.getDeclaredConstructors) - val constructor = clazz.getConstructor(classOf[Global]) - constructor.newInstance(global).asInstanceOf[Plugin] + val constructor = clazz getConstructor classOf[Global] + (constructor newInstance global).asInstanceOf[Plugin] } } diff --git a/src/compiler/scala/tools/nsc/plugins/Plugins.scala b/src/compiler/scala/tools/nsc/plugins/Plugins.scala index 1163ae5a6a..a67218ee01 100644 --- a/src/compiler/scala/tools/nsc/plugins/Plugins.scala +++ b/src/compiler/scala/tools/nsc/plugins/Plugins.scala @@ -8,7 +8,7 @@ package scala.tools.nsc package plugins -import java.io.File +import scala.io.{ File, Path } /** Support for run-time loading of compiler plugins. * @@ -16,7 +16,9 @@ import java.io.File * @version 1.1, 2009/1/2 * Updated 2009/1/2 by Anders Bach Nielsen: Added features to implement SIP 00002 */ -trait Plugins { self: Global => +trait Plugins +{ + self: Global => /** Load a rough list of the plugins. For speed, it * does not instantiate a compiler run. Therefore it cannot @@ -24,24 +26,17 @@ trait Plugins { self: Global => * filtered from the final list of plugins. */ protected def loadRoughPluginsList(): List[Plugin] = { - val jars = settings.plugin.value.map(new File(_)) - val dirs = - for (name <- settings.pluginsDir.value.split(File.pathSeparator).toList) - yield new File(name) + val jars = settings.plugin.value map Path.apply + val dirs = (settings.pluginsDir.value split File.pathSeparator).toList map Path.apply + val classes = Plugin.loadAllFrom(jars, dirs, settings.disable.value) + + classes foreach (c => Plugin.instantiate(c, this)) for (plugClass <- Plugin.loadAllFrom(jars, dirs, settings.disable.value)) yield Plugin.instantiate(plugClass, this) } - private var roughPluginsListCache: Option[List[Plugin]] = None - - protected def roughPluginsList: List[Plugin] = - roughPluginsListCache match { - case Some(list) => list - case None => - roughPluginsListCache = Some(loadRoughPluginsList) - roughPluginsListCache.get - } + protected lazy val roughPluginsList: List[Plugin] = loadRoughPluginsList /** Load all available plugins. Skips plugins that * either have the same name as another one, or which @@ -54,105 +49,70 @@ trait Plugins { self: Global => plugNames: Set[String], phaseNames: Set[String]): List[Plugin] = { - plugins match { - case Nil => Nil - case plug :: rest => - val plugPhaseNames = Set.empty ++ plug.components.map(_.phaseName) - def withoutPlug = pick(rest, plugNames, plugPhaseNames) - def withPlug = - (plug :: - pick(rest, - plugNames+plug.name, - phaseNames++plugPhaseNames)) - - if (plugNames.contains(plug.name)) { - if (settings.verbose.value) - inform("[skipping a repeated plugin: " + plug.name + "]") - withoutPlug - } else if (settings.disable.value contains(plug.name)) { - if (settings.verbose.value) - inform("[disabling plugin: " + plug.name + "]") - withoutPlug - } else { - val commonPhases = phaseNames.intersect(plugPhaseNames) - if (!commonPhases.isEmpty) { - if (settings.verbose.value) - inform("[skipping plugin " + plug.name + - "because it repeats phase names: " + - commonPhases.mkString(", ") + "]") - withoutPlug - } else { - if (settings.verbose.value) - inform("[loaded plugin " + plug.name + "]") - withPlug - } - } + if (plugins.isEmpty) return Nil // early return + + val plug :: tail = plugins + val plugPhaseNames = Set(plug.components map (_.phaseName): _*) + def withoutPlug = pick(tail, plugNames, plugPhaseNames) + def withPlug = plug :: pick(tail, plugNames + plug.name, phaseNames ++ plugPhaseNames) + lazy val commonPhases = phaseNames intersect plugPhaseNames + + def note(msg: String): Unit = if (settings.verbose.value) inform(msg format plug.name) + def fail(msg: String) = { note(msg) ; withoutPlug } + + if (plugNames contains plug.name) + fail("[skipping a repeated plugin: %s]") + else if (settings.disable.value contains plug.name) + fail("[disabling plugin: %s]") + else if (!commonPhases.isEmpty) + fail("[skipping plugin %s because it repeats phase names: " + (commonPhases mkString ", ") + "]") + else { + note("[loaded plugin %s]") + withPlug } } - val plugs = - pick(roughPluginsList, - Set.empty, - Set.empty ++ phasesSet.map(_.phaseName)) + val plugs = pick(roughPluginsList, Set(), phasesSet map (_.phaseName) toSet) - for (req <- settings.require.value; if !plugs.exists(p => p.name==req)) + /** Verify requirements are present. */ + for (req <- settings.require.value ; if !(plugs exists (_.name == req))) error("Missing required plugin: " + req) + /** Process plugin options. */ + def namec(plug: Plugin) = plug.name + ":" + def optList(xs: List[String], p: Plugin) = xs filter (_ startsWith namec(p)) + def doOpts(p: Plugin): List[String] = + optList(settings.pluginOptions.value, p) map (_ stripPrefix namec(p)) - for (plug <- plugs) { - val nameColon = plug.name + ":" - val opts = for { - raw <- settings.pluginOptions.value - if raw.startsWith(nameColon) - } yield raw.substring(nameColon.length) - + for (p <- plugs) { + val opts = doOpts(p) if (!opts.isEmpty) - plug.processOptions(opts, error) + p.processOptions(opts, error) } - for { - opt <- settings.pluginOptions.value - if !plugs.exists(p => opt.startsWith(p.name + ":")) - } error("bad option: -P:" + opt) + /** Verify no non-existent plugin given with -P */ + for (opt <- settings.pluginOptions.value ; if plugs forall (p => optList(List(opt), p).isEmpty)) + error("bad option: -P:" + opt) plugs } - private var pluginsCache: Option[List[Plugin]] = None - - def plugins: List[Plugin] = { - if (pluginsCache.isEmpty) - pluginsCache = Some(loadPlugins) - pluginsCache.get - } + lazy val plugins: List[Plugin] = loadPlugins /** A description of all the plugins that are loaded */ - def pluginDescriptions: String = { - val messages = - for (plugin <- roughPluginsList) - yield plugin.name + " - " + plugin.description - messages.mkString("\n") - } + def pluginDescriptions: String = + roughPluginsList map (x => "%s - %s".format(x.name, x.description)) mkString "\n" /** * Extract all phases supplied by plugins and add them to the phasesSet. * @see phasesSet */ - protected def computePluginPhases() { - val plugPhases = plugins.flatMap(_.components) - for (pPhase <- plugPhases) { - phasesSet += pPhase - } - } + protected def computePluginPhases(): Unit = + phasesSet ++= (plugins flatMap (_.components)) /** Summary of the options for all loaded plugins */ - def pluginOptionsHelp: String = { - val buf = new StringBuffer - for (plug <- roughPluginsList; help <- plug.optionsHelp) { - buf append ("Options for plugin " + plug.name + ":\n") - buf append help - buf append "\n" - } - buf.toString - } + def pluginOptionsHelp: String = + (for (plug <- roughPluginsList ; help <- plug.optionsHelp) yield { + "Options for plugin %s:\n%s\n".format(plug.name, help) + }) mkString } diff --git a/src/library/scala/io/File.scala b/src/library/scala/io/File.scala index b4131d7e57..74a66492ec 100644 --- a/src/library/scala/io/File.scala +++ b/src/library/scala/io/File.scala @@ -18,6 +18,8 @@ import collection.Traversable object File { + def pathSeparator = JFile.pathSeparator + def apply(path: Path)(implicit codec: Codec = null) = if (codec != null) new File(path.jfile)(codec) else path.toFile |