diff --git a/plugin/src/main/scala-2.10/coursier/SbtScalaJarsRepository.scala b/plugin/src/main/scala-2.10/coursier/SbtScalaJarsRepository.scala new file mode 100644 index 000000000..08f504539 --- /dev/null +++ b/plugin/src/main/scala-2.10/coursier/SbtScalaJarsRepository.scala @@ -0,0 +1,114 @@ +package coursier + +import java.io.File + +import coursier.core.Publication + +import scalaz.{ EitherT, Monad } +import scalaz.Scalaz.ToEitherOps + +object SbtScalaJarsRepository { + + // Will break in 2.11, where scala-parser-combinators_2.11 and scala-xml_2.11, with different + // org and versions, are thrown into the mix. + // To handle these well, we would need to fetch actual infos about the scala-* dependencies + // from actual repos, and use that from SbtScalaJarsRepository. + + val looseDependencies = Map( + "scala-compiler" -> Set( + "scala-library", + "scala-reflect" + ), + "scala-reflect" -> Set( + "scala-library" + ) + ) + +} + +case class SbtScalaJarsRepository( + scalaOrg: String, + scalaVersion: String, + jars: Seq[File] +) extends Repository { repo => + + val foundNames = jars.collect { + case jar if jar.getName.endsWith(".jar") => + jar.getName.stripSuffix(".jar") + }.toSet + + val dependencies = SbtScalaJarsRepository.looseDependencies + .filterKeys(foundNames) + .mapValues(_.filter(foundNames)) + + val artifacts = jars.collect { + case jar if jar.getName.endsWith(".jar") => + val name = jar.getName.stripSuffix(".jar") + val mod = Module(scalaOrg, name) + + val proj = Project( + mod, + scalaVersion, + dependencies.getOrElse(name, Set.empty[String]).toVector.map { depName => + val dep = Dependency(Module(scalaOrg, depName), scalaVersion) + "compile" -> dep + }, + MavenRepository.defaultConfigurations, + None, + Nil, + Nil, + Nil, + None, + None, + None, + Seq("compile" -> Publication(name, "jar", "jar", "")), + Info("", "", Nil, Nil, None) + ) + + (mod, scalaVersion) -> ((proj, jar)) + }.toMap + + val source: Artifact.Source = new Artifact.Source { + def artifacts( + dependency: Dependency, + project: Project, + overrideClassifiers: Option[Seq[String]] + ) = + if (overrideClassifiers.isEmpty) + repo.artifacts.get(project.moduleVersion) match { + case Some((_, f)) => + Seq( + Artifact( + f.toURI.toString, + Map.empty, + Map.empty, + Attributes("jar", ""), + changing = true, + None + ) + ) + case None => + Nil + } + else + Nil + } + + def find[F[_]]( + module: Module, + version: String, + fetch: Fetch.Content[F] + )(implicit + F: Monad[F] + ): EitherT[F, String, (Artifact.Source, Project)] = { + + val res = artifacts.get((module, version)) match { + case None => + s"not found in internal SBT scala JARs: $module:$version".left + case Some((p, _)) => + (source, p).right + } + + EitherT(F.point(res)) + } +} diff --git a/plugin/src/main/scala-2.10/coursier/Tasks.scala b/plugin/src/main/scala-2.10/coursier/Tasks.scala index c27313efe..f5052524d 100644 --- a/plugin/src/main/scala-2.10/coursier/Tasks.scala +++ b/plugin/src/main/scala-2.10/coursier/Tasks.scala @@ -429,6 +429,17 @@ object Tasks { val interProjectRepo = InterProjectRepository(interProjectDependencies) + val internalSbtScalaProvider = appConfiguration.value.provider.scalaProvider + val internalSbtScalaJarsRepo = SbtScalaJarsRepository( + so, // this seems plain wrong - this assumes that the scala org of the project is the same + // as the one that started SBT. This will scrap the scala org specific JARs by the ones + // that booted SBT, even if the latter come from the standard org.scala-lang org. + // But SBT itself does it this way, and not doing so may make two different versions + // of the scala JARs land in the classpath... + internalSbtScalaProvider.version(), + internalSbtScalaProvider.jars() + ) + val ivyHome = sys.props.getOrElse( "ivy.home", new File(sys.props("user.home")).toURI.getPath + ".ivy2" @@ -509,7 +520,7 @@ object Tasks { } } - val internalRepositories = Seq(globalPluginsRepo, interProjectRepo) + val internalRepositories = Seq(globalPluginsRepo, interProjectRepo, internalSbtScalaJarsRepo) val repositories = internalRepositories ++ diff --git a/plugin/src/sbt-test/sbt-coursier/scala-jars/build.sbt b/plugin/src/sbt-test/sbt-coursier/scala-jars/build.sbt new file mode 100644 index 000000000..998a4a95b --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/scala-jars/build.sbt @@ -0,0 +1,8 @@ +scalaVersion := appConfiguration.value.provider.scalaProvider.version + +coursierCachePolicies := { + if (sys.props("os.name").startsWith("Windows")) + coursierCachePolicies.value + else + Seq(coursier.CachePolicy.ForceDownload) +} diff --git a/plugin/src/sbt-test/sbt-coursier/scala-jars/project/plugins.sbt b/plugin/src/sbt-test/sbt-coursier/scala-jars/project/plugins.sbt new file mode 100644 index 000000000..152225a9e --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/scala-jars/project/plugins.sbt @@ -0,0 +1,11 @@ +{ + val pluginVersion = sys.props.getOrElse( + "plugin.version", + throw new RuntimeException( + """|The system property 'plugin.version' is not defined. + |Specify this property using the scriptedLaunchOpts -D.""".stripMargin + ) + ) + + addSbtPlugin("io.get-coursier" % "sbt-coursier" % pluginVersion) +} diff --git a/plugin/src/sbt-test/sbt-coursier/scala-jars/src/main/scala/Main.scala b/plugin/src/sbt-test/sbt-coursier/scala-jars/src/main/scala/Main.scala new file mode 100644 index 000000000..6d3e69d54 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/scala-jars/src/main/scala/Main.scala @@ -0,0 +1,43 @@ +import java.io.File +import java.nio.file.Files + +object Main extends App { + + val cp = new collection.mutable.ArrayBuffer[File] + + def buildCp(loader: ClassLoader): Unit = + if (loader != null) { + loader match { + case u: java.net.URLClassLoader => + cp ++= u.getURLs + .map(_.toURI) + .map(new File(_)) + case _ => + } + + buildCp(loader.getParent) + } + + buildCp(Thread.currentThread().getContextClassLoader) + + val sbtBase = new File(sys.props.getOrElse( + "sbt.global.base", + sys.props("user.home") + "/.sbt" + )) + val prefix = new File(sbtBase, "boot").getAbsolutePath + + def fromBootAndUnique(name: String): Unit = { + val jars = cp.filter(_.getName.startsWith(name)).distinct + assert(jars.length == 1, s"Found 0 or multiple JARs for $name: $jars") + + val Seq(jar) = jars + + assert(jar.getAbsolutePath.startsWith(prefix), s"JAR for $name ($jar) not under $prefix") + } + + fromBootAndUnique("scala-library") + fromBootAndUnique("scala-reflect") + fromBootAndUnique("scala-compiler") + + Files.write(new File("output").toPath, "OK".getBytes("UTF-8")) +} diff --git a/plugin/src/sbt-test/sbt-coursier/scala-jars/test b/plugin/src/sbt-test/sbt-coursier/scala-jars/test new file mode 100644 index 000000000..2182f57b0 --- /dev/null +++ b/plugin/src/sbt-test/sbt-coursier/scala-jars/test @@ -0,0 +1,3 @@ +$ delete output +> run +$ exists output