New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix 13618 - undo windows wildcard classpath globbing #13619
Changes from 3 commits
5455902
275deea
eda3104
bf753c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,17 +105,20 @@ object MainGenericRunner { | |
case "-run" :: fqName :: tail => | ||
process(tail, settings.withExecuteMode(ExecuteMode.Run).withTargetToRun(fqName)) | ||
case ("-cp" | "-classpath" | "--class-path") :: cp :: tail => | ||
val globdir = cp.replaceAll("[\\/][^\\/]*$", "") // slash/backslash agnostic | ||
val (tailargs, cpstr) = if globdir.nonEmpty && classpathSeparator != ";" || cp.contains(classpathSeparator) then | ||
(tail, cp) | ||
val cpEntries = cp.split(classpathSeparator).toList | ||
val singleEntryClasspath: Boolean = cpEntries.nonEmpty && cpEntries.drop(1).isEmpty | ||
val globdir: String = if singleEntryClasspath then cp.replaceAll("[\\\\/][^\\\\/]*$", "") else "" // slash/backslash agnostic | ||
def validGlobbedJar(s: String): Boolean = s.startsWith(globdir) && ((s.toLowerCase.endsWith(".jar") || s.toLowerCase.endsWith(".zip"))) | ||
val (tailargs, newEntries) = if singleEntryClasspath && validGlobbedJar(cpEntries.head) then | ||
// reassemble globbed wildcard classpath | ||
// globdir is wildcard directory for globbed jar files, reconstruct the intended classpath | ||
val cpJars = tail.takeWhile( f => validGlobbedJar(f) ) | ||
val remainingArgs = tail.drop(cpJars.size) | ||
(remainingArgs, cpEntries ++ cpJars) | ||
else | ||
// combine globbed classpath entries into a classpath | ||
val jarfiles = cp :: tail | ||
val cpfiles = jarfiles.takeWhile( f => f.startsWith(globdir) && ((f.toLowerCase.endsWith(".jar") || f.endsWith(".zip"))) ) | ||
val tailargs = jarfiles.drop(cpfiles.size) | ||
(tailargs, cpfiles.mkString(classpathSeparator)) | ||
|
||
process(tailargs, settings.copy(classPath = settings.classPath ++ cpstr.split(classpathSeparator).filter(_.nonEmpty))) | ||
(tail, cpEntries) | ||
|
||
process(tailargs, settings.copy(classPath = settings.classPath ++ newEntries.filter(_.nonEmpty))) | ||
|
||
case ("-version" | "--version") :: _ => | ||
settings.copy( | ||
|
@@ -204,16 +207,15 @@ object MainGenericRunner { | |
val targetScript = Paths.get(settings.targetScript).toFile | ||
val targetJar = settings.targetScript.replaceAll("[.][^\\/]*$", "")+".jar" | ||
val precompiledJar = Paths.get(targetJar).toFile | ||
def mainClass = Jar(targetJar).mainClass.getOrElse("") // throws exception if file not found | ||
val jarIsValid = precompiledJar.isFile && mainClass.nonEmpty && precompiledJar.lastModified >= targetScript.lastModified | ||
val mainClass = if !precompiledJar.isFile then "" else Jar(targetJar).mainClass.getOrElse("") | ||
val jarIsValid = mainClass.nonEmpty && precompiledJar.lastModified >= targetScript.lastModified | ||
if jarIsValid then | ||
// precompiledJar exists, is newer than targetScript, and manifest defines a mainClass | ||
sys.props("script.path") = targetScript.toPath.toAbsolutePath.normalize.toString | ||
val scalaClasspath = ClasspathFromClassloader(Thread.currentThread().getContextClassLoader).split(classpathSeparator) | ||
val newClasspath = (settings.classPath.flatMap(_.split(classpathSeparator).filter(_.nonEmpty)) ++ removeCompiler(scalaClasspath) :+ ".").map(File(_).toURI.toURL) | ||
val mc = mainClass | ||
if mc.nonEmpty then | ||
ObjectRunner.runAndCatch(newClasspath :+ File(targetJar).toURI.toURL, mc, settings.scriptArgs) | ||
if mainClass.nonEmpty then | ||
ObjectRunner.runAndCatch(newClasspath :+ File(targetJar).toURI.toURL, mainClass, settings.scriptArgs) | ||
else | ||
Some(IllegalArgumentException(s"No main class defined in manifest in jar: $precompiledJar")) | ||
else | ||
|
@@ -241,4 +243,22 @@ object MainGenericRunner { | |
e.foreach(_.printStackTrace()) | ||
!isFailure | ||
} | ||
|
||
def display(settings: Settings)= Seq( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't it dead code? I guess it's for debugging purposes, maybe we could add some flag for displaying this debug, or let's remove it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about an environment variable, maybe something like this: lazy val debug = Option(System.getenv("RUNNER_DEBUG")) != None
[...]
if debug then printf("settings: %s\n", display(settings)) I also don't mind removing it, I can always add it back temporarily, if needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can remove it. |
||
s"verbose: ${settings.verbose}", | ||
s"classPath: ${settings.classPath.mkString("\n ","\n ","")}", | ||
s"executeMode: ${settings.executeMode}", | ||
s"exitCode: ${settings.exitCode}", | ||
s"javaArgs: ${settings.javaArgs}", | ||
s"scalaArgs: ${settings.scalaArgs}", | ||
s"residualArgs: ${settings.residualArgs}", | ||
s"possibleEntryPaths: ${settings.possibleEntryPaths}", | ||
s"scriptArgs: ${settings.scriptArgs}", | ||
s"targetScript: ${settings.targetScript}", | ||
s"targetToRun: ${settings.targetToRun}", | ||
s"save: ${settings.save}", | ||
s"modeShouldBePossibleRun: ${settings.modeShouldBePossibleRun}", | ||
s"modeShouldBeRun: ${settings.modeShouldBeRun}", | ||
s"compiler: ${settings.compiler}", | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!bin/scala -classpath 'dist/target/pack/lib/*' | ||
|
||
// won't compile unless the hashbang line sets classpath | ||
import org.jline.terminal.Terminal | ||
|
||
def main(args: Array[String]) = | ||
val cp = sys.props("java.class.path") | ||
printf("unglobbed classpath: %s\n", cp) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't just
cpEntries.size == 1
enough?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be okay, although a wildcard classpath directory could have thousands of jar files, so
size
could be expensive.Should I change it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can leave it done your way if you feel that it is better.