diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/MainGenericRunner.scala | 23 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/ObjectRunner.scala | 14 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/io/Jar.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/ClassPath.scala | 14 | ||||
-rwxr-xr-x | test/script-tests/README | 8 | ||||
-rw-r--r-- | test/script-tests/jar-manifest/resources/MANIFEST.MF | 3 | ||||
-rwxr-xr-x | test/script-tests/jar-manifest/run-test | 41 | ||||
-rw-r--r-- | test/script-tests/jar-manifest/run-test.check | 30 | ||||
-rw-r--r-- | test/script-tests/jar-manifest/src/jar-test.scala | 34 |
9 files changed, 162 insertions, 13 deletions
diff --git a/src/compiler/scala/tools/nsc/MainGenericRunner.scala b/src/compiler/scala/tools/nsc/MainGenericRunner.scala index cef13843dc..cc1139f8a7 100644 --- a/src/compiler/scala/tools/nsc/MainGenericRunner.scala +++ b/src/compiler/scala/tools/nsc/MainGenericRunner.scala @@ -7,13 +7,28 @@ package scala.tools.nsc import java.net.URL import scala.tools.util.PathResolver - import io.{ File } import util.{ ClassPath, ScalaClassLoader } import Properties.{ versionString, copyrightString } import interpreter.{ ILoop } import GenericRunnerCommand._ +object JarRunner extends CommonRunner { + def runJar(settings: GenericRunnerSettings, jarPath: String, arguments: Seq[String]): Either[Throwable, Boolean] = { + val jar = new io.Jar(jarPath) + val mainClass = jar.mainClass getOrElse sys.error("Cannot find main class for jar: " + jarPath) + val jarURLs = ClassPath expandManifestPath jarPath + val urls = if (jarURLs.isEmpty) File(jarPath).toURL +: settings.classpathURLs else jarURLs + + if (settings.Ylogcp.value) { + Console.err.println("Running jar with these URLs as the classpath:") + urls foreach println + } + + runAndCatch(urls, mainClass, arguments) + } +} + /** An object that runs Scala code. It has three possible * sources for the code to run: pre-compiled code, a script file, * or interactive entry. @@ -56,11 +71,7 @@ class MainGenericRunner { case AsScript => ScriptRunner.runScriptAndCatch(settings, thingToRun, command.arguments) case AsJar => - ObjectRunner.runAndCatch( - File(thingToRun).toURL +: settings.classpathURLs, - new io.Jar(thingToRun).mainClass getOrElse sys.error("Cannot find main class for jar: " + thingToRun), - command.arguments - ) + JarRunner.runJar(settings, thingToRun, command.arguments) case Error => Right(false) case _ => diff --git a/src/compiler/scala/tools/nsc/ObjectRunner.scala b/src/compiler/scala/tools/nsc/ObjectRunner.scala index 6ff0718de7..110de7aad5 100644 --- a/src/compiler/scala/tools/nsc/ObjectRunner.scala +++ b/src/compiler/scala/tools/nsc/ObjectRunner.scala @@ -11,12 +11,7 @@ import util.ScalaClassLoader import java.lang.reflect.InvocationTargetException import util.Exceptional.unwrap -/** An object that runs another object specified by name. - * - * @author Lex Spoon - * @version 1.1, 2007/7/13 - */ -object ObjectRunner { +trait CommonRunner { /** Check whether a class with the specified name * exists on the specified class path. */ def classExists(urls: List[URL], objectName: String): Boolean = @@ -41,3 +36,10 @@ object ObjectRunner { catch { case e => Left(unwrap(e)) } } } + +/** An object that runs another object specified by name. + * + * @author Lex Spoon + * @version 1.1, 2007/7/13 + */ +object ObjectRunner extends CommonRunner { } diff --git a/src/compiler/scala/tools/nsc/io/Jar.scala b/src/compiler/scala/tools/nsc/io/Jar.scala index ad1598a85d..bbed5a9e20 100644 --- a/src/compiler/scala/tools/nsc/io/Jar.scala +++ b/src/compiler/scala/tools/nsc/io/Jar.scala @@ -40,7 +40,15 @@ class Jar(file: File) extends Iterable[JarEntry] { lazy val jarFile = new JarFile(file.jfile) lazy val manifest = withJarInput(s => Option(s.getManifest)) + def mainClass = manifest map (f => f(Name.MAIN_CLASS)) + /** The manifest-defined classpath String if available. */ + def classPathString: Option[String] = + for (m <- manifest ; cp <- m.attrs get Name.CLASS_PATH) yield cp + def classPathElements: List[String] = classPathString match { + case Some(s) => s split "\\s+" toList + case _ => Nil + } def withJarInput[T](f: JarInputStream => T): T = { val in = new JarInputStream(file.inputStream()) diff --git a/src/compiler/scala/tools/nsc/util/ClassPath.scala b/src/compiler/scala/tools/nsc/util/ClassPath.scala index 484f809e6f..622b4db2a2 100644 --- a/src/compiler/scala/tools/nsc/util/ClassPath.scala +++ b/src/compiler/scala/tools/nsc/util/ClassPath.scala @@ -13,6 +13,7 @@ import io.{ File, Directory, Path, Jar, AbstractFile, ClassAndJarInfo } import scala.tools.util.StringOps.splitWhere import Jar.isJarOrZip import File.pathSeparator +import java.net.MalformedURLException /** <p> * This module provides star expansion of '-classpath' option arguments, behaves the same as @@ -110,11 +111,22 @@ object ClassPath { case dir => dir filter (_.isClassContainer) map (x => new java.io.File(dir.file, x.name) getPath) toList } } + /** Expand manifest jar classpath entries: these are either urls, or paths + * relative to the location of the jar. + */ + def expandManifestPath(jarPath: String): List[URL] = { + val file = File(jarPath) + if (!file.isFile) return Nil + + val baseDir = file.parent + new Jar(file).classPathElements map (elem => + specToURL(elem) getOrElse (baseDir / elem).toURL + ) + } /** A useful name filter. */ def isTraitImplementation(name: String) = name endsWith "$class.class" - import java.net.MalformedURLException def specToURL(spec: String): Option[URL] = try Some(new URL(spec)) catch { case _: MalformedURLException => None } diff --git a/test/script-tests/README b/test/script-tests/README new file mode 100755 index 0000000000..3f5c2ce19c --- /dev/null +++ b/test/script-tests/README @@ -0,0 +1,8 @@ +This is a fresh start for script tests. The fact that windows exists can +no longer be allowed to stand in the way of testing the wide range of +functionality which currently goes completely untested. So I'll just be +putting self-contained script tests in here to run some way that doesn't +depend on all the platform stars aligning all the time. Feel free to +join me. + +-- extempore, Nov 21 2011
\ No newline at end of file diff --git a/test/script-tests/jar-manifest/resources/MANIFEST.MF b/test/script-tests/jar-manifest/resources/MANIFEST.MF new file mode 100644 index 0000000000..93c54c3c6f --- /dev/null +++ b/test/script-tests/jar-manifest/resources/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: bippy.Runner +Class-Path: bippy.jar dingus.jar http://mirrors.ibiblio.org/pub/mirrors/maven2/com/thoughtworks/paranamer/paranamer/2.4/paranamer-2.4.jar diff --git a/test/script-tests/jar-manifest/run-test b/test/script-tests/jar-manifest/run-test new file mode 100755 index 0000000000..2c6d5876b8 --- /dev/null +++ b/test/script-tests/jar-manifest/run-test @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# + +set -e + +paranamerjar="http://mirrors.ibiblio.org/pub/mirrors/maven2/com/thoughtworks/paranamer/paranamer/2.4/paranamer-2.4.jar" +build=$(dirname $0)/../../../build/pack + +if [[ -n "$SCALA_HOME" ]]; then + scala="$SCALA_HOME/bin/scala" +elif [[ -d $build ]]; then + scala=$(cd $build && pwd -P)/bin/scala +else + scala="scala" +fi + +echo "$($scala -version 2>&1)" +scalac="${scala}c" + +[[ -d lib ]] || mkdir lib +[[ -f lib/paranamer-2.4.jar ]] || ( printf >&2 "Grabbing paranamer jar\n\n" && cd lib && wget --quiet "$paranamerjar" ) + +rm -rf target && mkdir target +"$scalac" -d target -cp lib/'*' src/*.scala +cd target + +jar cmf ../resources/MANIFEST.MF bippy.jar bippy +jar cf dingus.jar dingus + +run () { + echo "" + echo "% $@" + "$@" +} + +cat <<EOM +$(run pwd) +$(run jar tf bippy.jar) +$(run jar tf dingus.jar) +$(run $scala $@ bippy.jar) +EOM diff --git a/test/script-tests/jar-manifest/run-test.check b/test/script-tests/jar-manifest/run-test.check new file mode 100644 index 0000000000..ef59a6cbac --- /dev/null +++ b/test/script-tests/jar-manifest/run-test.check @@ -0,0 +1,30 @@ +Scala code runner version 2.10.0.r26038-b20111121102734 -- Copyright 2002-2011, LAMP/EPFL + +% pwd +/scala/trunk/test/script-tests/jar-manifest/target + +% jar tf bippy.jar +META-INF/ +META-INF/MANIFEST.MF +bippy/ +bippy/Runner$$anonfun$main$1.class +bippy/Runner$$anonfun$main$2.class +bippy/Runner$$anonfun$main$3.class +bippy/Runner$.class +bippy/Runner.class + +% jar tf dingus.jar +META-INF/ +META-INF/MANIFEST.MF +dingus/ +dingus/Printable.class + +% /scala/trunk/build/pack/bin/scala bippy.jar +1 "Greetings from dingus.jar!" +2 bippyBingle has parameters: imparametorium, antidisestablish, x +3 bippyBoo has parameters: quuxParameter +4 +5 Urls exposed through the classloader: +6 file:/scala/trunk/test/script-tests/jar-manifest/target/./bippy.jar +7 file:/scala/trunk/test/script-tests/jar-manifest/target/./dingus.jar +8 http://mirrors.ibiblio.org/pub/mirrors/maven2/com/thoughtworks/paranamer/paranamer/2.4/paranamer-2.4.jar diff --git a/test/script-tests/jar-manifest/src/jar-test.scala b/test/script-tests/jar-manifest/src/jar-test.scala new file mode 100644 index 0000000000..80e3aafff0 --- /dev/null +++ b/test/script-tests/jar-manifest/src/jar-test.scala @@ -0,0 +1,34 @@ +import scala.tools.nsc.util.HasClassPath + +package bippy { + object Runner { + var line = 0 + def echo(msgs: Any*) = { + line += 1 + Console.println("%-2s %s".format(line, msgs mkString " ")) + } + + def bippyBoo(quuxParameter: Int) = 5 + def bippyBingle(imparametorium: String, antidisestablish: Int, x: Float) = () + + def main(args: Array[String]): Unit = { + echo(new dingus.Printable) + val namer = new com.thoughtworks.paranamer.BytecodeReadingParanamer + getClass.getMethods filter (_.getName startsWith "bippy") foreach { m => + echo(m.getName, "has parameters:", namer.lookupParameterNames(m).mkString(", ")) + } + echo("") + echo("Urls exposed through the classloader:") + getClass.getClassLoader match { + case x: HasClassPath => x.classPathURLs foreach (x => echo(x)) + case _ => echo("None! Seems unlikely we'd get this far then.") + } + } + } +} + +package dingus { + class Printable { + override def toString = "\"Greetings from dingus.jar!\"" + } +}
\ No newline at end of file |