From db81fa2109f95d121a34c03e3c0faea6f9f9d004 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 30 Dec 2015 06:22:55 -0500 Subject: [PATCH 1/2] Fix bincompat issue introduced in #2268 --- util/io/src/main/scala/sbt/IO.scala | 83 +++++++++++++++++++---------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/util/io/src/main/scala/sbt/IO.scala b/util/io/src/main/scala/sbt/IO.scala index 179faa7e2..45b0b2018 100644 --- a/util/io/src/main/scala/sbt/IO.scala +++ b/util/io/src/main/scala/sbt/IO.scala @@ -35,6 +35,62 @@ object IO { val utf8 = Charset.forName("UTF-8") + /** + * Returns a URL for the directory or jar containing the class file for type `T` (as determined by an implicit Manifest). + * If the location cannot be determined, an error is generated. + * Note that Java standard library classes typically do not have a location associated with them. + */ + @deprecated("Use classfileLocation or classLocationFile", "0.13.10") + def classLocation[T](implicit mf: SManifest[T]): URL = classLocation(mf.runtimeClass) + + /** + * Returns a URL for the directory or jar containing the the class file `cl`. + * If the location cannot be determined, an error is generated. + */ + @deprecated("Use classfileLocation or classLocationFile", "0.13.10") + def classLocation(cl: Class[_]): URL = { + val codeSource = cl.getProtectionDomain.getCodeSource + if (codeSource ne null) { + codeSource.getLocation + } else { + // NB: This assumes that classes without code sources are System classes, and thus located in + // jars. It assumes that `urlAsFile` will truncate to the containing jar file. + val clsfile = s"${cl.getName.replace('.', '/')}.class" + Option(ClassLoader.getSystemClassLoader.getResource(clsfile)) + .flatMap { + urlAsFile + }.getOrElse { + sys.error("No class location for " + cl) + }.toURI.toURL + } + } + + /** + * Returns the directory or jar file containing the the class file for type `T` (as determined by an implicit Manifest). + * If the location cannot be determined, an error is generated. + * Note that Java standard library classes typically do not have a location associated with them. + */ + def classLocationFile[T](implicit mf: SManifest[T]): File = classLocationFile(mf.runtimeClass) + + /** + * Returns the directory or jar file containing the class file `cl`. + * If the location cannot be determined or if it is not a file, an error is generated. + * Note that Java standard library classes typically do not have a location associated with them. + */ + def classLocationFile(cl: Class[_]): File = { + val classURL = + Option(cl.getProtectionDomain.getCodeSource).getOrElse { + sys.error("No class location for " + cl) + }.getLocation + toFile(classURL) + } + + /** + * Returns a URL for the classfile containing the given class file for type `T` (as determined by an implicit Manifest). + * If the location cannot be determined, an error is generated. + */ + def classfileLocation[T](implicit mf: SManifest[T]): URL = classfileLocation(mf.runtimeClass) + /** * Returns a URL for the classfile containing the given class * If the location cannot be determined, an error is generated. @@ -54,33 +110,6 @@ object IO { } } - /** - * Returns the directory or jar file containing the class file `cl`. - * If the location cannot be determined or if it is not a file, an error is generated. - * Note that Java standard library classes typically do not have a location associated with them. - */ - def classLocationFile(cl: Class[_]): File = { - val classURL = - Option(cl.getProtectionDomain.getCodeSource).getOrElse { - sys.error("No class location for " + cl) - }.getLocation - toFile(classURL) - } - - /** - * Returns a URL for the directory or jar containing the class file for type `T` (as determined by an implicit Manifest). - * If the location cannot be determined, an error is generated. - * Note that Java standard library classes typically do not have a location associated with them. - */ - def classfileLocation[T](implicit mf: SManifest[T]): URL = classfileLocation(mf.runtimeClass) - - /** - * Returns the directory or jar file containing the the class file for type `T` (as determined by an implicit Manifest). - * If the location cannot be determined, an error is generated. - * Note that Java standard library classes typically do not have a location associated with them. - */ - def classLocationFile[T](implicit mf: SManifest[T]): File = classLocationFile(mf.runtimeClass) - /** * Constructs a File corresponding to `url`, which must have a scheme of `file`. * This method properly works around an issue with a simple conversion to URI and then to a File. From 068cffa57835530a91f8b798b482ef0a94200b33 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Wed, 30 Dec 2015 07:36:12 -0500 Subject: [PATCH 2/2] Reimplement fallback to system classloader to maintain the 0.13 semantics --- util/io/src/main/scala/sbt/IO.scala | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/util/io/src/main/scala/sbt/IO.scala b/util/io/src/main/scala/sbt/IO.scala index 45b0b2018..92587bb30 100644 --- a/util/io/src/main/scala/sbt/IO.scala +++ b/util/io/src/main/scala/sbt/IO.scala @@ -77,13 +77,22 @@ object IO { * If the location cannot be determined or if it is not a file, an error is generated. * Note that Java standard library classes typically do not have a location associated with them. */ - def classLocationFile(cl: Class[_]): File = { - val classURL = - Option(cl.getProtectionDomain.getCodeSource).getOrElse { - sys.error("No class location for " + cl) - }.getLocation - toFile(classURL) - } + def classLocationFile(cl: Class[_]): File = + Option(cl.getProtectionDomain.getCodeSource) match { + case Some(codeSource) => + val classURL = codeSource.getLocation + toFile(classURL) + case None => + // NB: This assumes that classes without code sources are System classes, and thus located in + // jars. It assumes that `urlAsFile` will truncate to the containing jar file. + val clsfile = s"${cl.getName.replace('.', '/')}.class" + Option(ClassLoader.getSystemClassLoader.getResource(clsfile)) + .flatMap { + urlAsFile + }.getOrElse { + sys.error("No class location for " + cl) + } + } /** * Returns a URL for the classfile containing the given class file for type `T` (as determined by an implicit Manifest). @@ -104,7 +113,7 @@ object IO { sys.error("No class location for " + cl) } } catch { - case e => + case e: Throwable => e.printStackTrace() throw e }