diff --git a/examples/cross-rewrite-example/build/build.scala b/examples/cross-rewrite-example/build/build.scala index 6d2ffac5..009108ea 100644 --- a/examples/cross-rewrite-example/build/build.scala +++ b/examples/cross-rewrite-example/build/build.scala @@ -6,12 +6,65 @@ import scalafix.util._ import scalafix.util.TreePatch._ import scalafix.util.TokenPatch._ -class Build(val context: Context) extends BaseBuild{ outer => - override def defaultScalaVersion = "2.11.8" +class TestBuild( val context: Context, mainBuild: BaseBuild ) extends ScalaTest with Scalameta { + override def defaultScalaVersion = mainBuild.scalaVersion + override def projectDirectory = CrossRewrite.mkdirIfNotExists( mainBuild.projectDirectory / "test" ) + override def dependencies = mainBuild +: super.dependencies +} + +class Build(val context: Context) extends BaseBuild with Scalameta with PackageJars { defaultMainBuild => + override def defaultScalaVersion: String = "2.12.1" + override def groupId = "org.cvogt" + override def artifactId = "cbt-examples-cross-rewrite" + override def version = "0.1" + override def scaladoc = None // Scalameta breaks Scaladoc + + override def test: BaseBuild = new TestBuild( context, this ) + + def cross = for{ + ( v, version_rewrites ) <- CrossRewrite.versions + ( label, dep, lib_rewrites ) <- CrossRewrite.libs + } yield { + new Build(context) with Scalafix{ patchedMainBuild => + override def defaultScalaVersion = v + override def artifactId = super.artifactId ~ "-" ~ label + override def projectDirectory = CrossRewrite.mkdirIfNotExists( + defaultMainBuild.target / "rewrites" / label ++ "-" ++ v + ) + override def dependencies = + super.dependencies ++ Resolver(mavenCentral).bind( + // hack because using ScalaDependency in the outer build binds it + // to THAT builds initial scalaVersion, which we are overriding + // here, but we are looping over libs outside of that, so + // the override doesn't affect it + // So we use MavenDependency instead and append the id here. + dep.copy(artifactId = dep.artifactId + "_" + scalaMajorVersion) + ) + override def sources = CrossRewrite.patchesSources( + defaultMainBuild.sources, + projectDirectory / "src", + defaultMainBuild.classpath, + lib_rewrites ++ version_rewrites, + lib + ) + override def test = new TestBuild( context, this ){ + override def sources = CrossRewrite.patchesSources( + defaultMainBuild.test.sources, + projectDirectory / "src", + defaultMainBuild.test.classpath, + lib_rewrites ++ version_rewrites, + lib + ) + } + } + } +} + +object CrossRewrite{ def versions = Seq[(String, Seq[Patch])]( - scalaVersion -> Seq(), - "2.12.1" -> Seq( + "2.12.1" -> Seq(), + "2.11.8" -> Seq( RemoveGlobalImport( importer"scala.concurrent.Future" ), @@ -23,50 +76,50 @@ class Build(val context: Context) extends BaseBuild{ outer => def libs = Seq[(String, MavenDependency, Seq[Patch])]( ( "scalaz", - ScalaDependency( "org.scalaz", "scalaz-core", "7.2.2" ), + MavenDependency( "org.scalaz", "scalaz-core", "7.2.10" ), Seq( + AddGlobalImport(importer"scalaz._"), + Replace(Symbol("_root_.scala.package.Either."), q"\/"), + Replace(Symbol("_root_.scala.util.Right."), q"\/-"), + RemoveGlobalImport(importer"cats.implicits._") ) ), ( "cats", - ScalaDependency( "org.typelevel", "cats", "0.9.0" ), + MavenDependency( "org.typelevel", "cats", "0.9.0" ), Seq( + AddGlobalImport(importer"cats.implicits._") ) ) ) - def cross = versions.flatMap{ case ( v, version_rewrites ) => - libs.map{ - case ( label, dep, lib_rewrites ) => - val d = outer.target / "rewrites" / label ++ "-" ++ v - d.mkdirs - new Build(context) with Scalafix with PackageJars{ - override def groupId = "org.cvogt" - override def artifactId = "cbt-examples-cross-rewrite-" + label - override def version = "0.1" - override def defaultScalaVersion = v - override def dependencies = super.dependencies ++ Resolver( mavenCentral ).bind( dep ) - override def projectDirectory = d - override def scaladoc = None - override def sources = { - val fromTo = lib.autoRelative( outer.sources ).collect{ - case (location, relative) if location.isFile - => location -> projectDirectory / "src" / relative - } + def mkdirIfNotExists( d: File ): File = { + d.mkdirs + d + } - val to = fromTo.map(_._2) - assert( ( to diff to.distinct ).isEmpty ) + def patchesSources( + sources: Seq[File], + destination: File, + semanticDbClassPath: ClassPath, + patches: Seq[Patch], + lib: Lib + ) = { + val fromTo = lib.autoRelative( sources ).collect{ + case (location, relative) if location.isFile + => location -> destination / relative + } - Scalafix.apply(lib).config( - outer.classpath, - files = fromTo, - patches = lib_rewrites ++ version_rewrites, - allowEmpty = true - ).apply + val to = fromTo.map(_._2) + assert( ( to diff to.distinct ).isEmpty ) - to - } - } - } + Scalafix.apply(lib).config( + semanticDbClassPath, + files = fromTo, + patches = patches, + allowEmpty = true + ).apply + + to } -} +} \ No newline at end of file diff --git a/examples/cross-rewrite-example/src/Main.scala b/examples/cross-rewrite-example/src/Main.scala index 27ea3ff1..d052a6d2 100644 --- a/examples/cross-rewrite-example/src/Main.scala +++ b/examples/cross-rewrite-example/src/Main.scala @@ -1 +1,5 @@ -import scala.concurrent.Future +object Main { + def main( args: Array[String] ): Unit = { + Disjunction.intOrString.map( println ) + } +} diff --git a/examples/cross-rewrite-example/src/disjunction.scala b/examples/cross-rewrite-example/src/disjunction.scala new file mode 100644 index 00000000..97686b80 --- /dev/null +++ b/examples/cross-rewrite-example/src/disjunction.scala @@ -0,0 +1,3 @@ +object Disjunction { + val intOrString: Either[Int, String] = Right( "It works!" ) +} diff --git a/examples/cross-rewrite-example/test/disjunction_spec.scala b/examples/cross-rewrite-example/test/disjunction_spec.scala new file mode 100644 index 00000000..58c63fdd --- /dev/null +++ b/examples/cross-rewrite-example/test/disjunction_spec.scala @@ -0,0 +1,9 @@ +import org.scalatest._ + +class Test extends FunSpec with Matchers { + describe( "Disjunction" ) { + it( "should work in all versions" ) { + Disjunction.intOrString shouldBe Right( "It works!" ) + } + } +} diff --git a/stage1/resolver.scala b/stage1/resolver.scala index f4a9b13d..e60260fe 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -86,7 +86,10 @@ trait DependencyImplementation extends Dependency{ java_exe.string +: "-cp" +: classpath.string +: className +: args ) } else { - lib.getMain( classLoader.loadClass( className ) )( args ) + val cl = if( !flatClassLoader ) classLoader else { + new java.net.URLClassLoader(classpath.strings.map(f => new URL("file://" ++ f)).toArray) + } + lib.getMain( cl.loadClass( className ) )( args ) } } @@ -109,30 +112,26 @@ trait DependencyImplementation extends Dependency{ def flatClassLoader: Boolean = false override def classLoader: ClassLoader = taskCache[DependencyImplementation]( "classLoader" ).memoize{ - if( flatClassLoader ){ - new java.net.URLClassLoader(classpath.strings.map(f => new URL("file://" ++ f)).toArray) - } else { - /* - if( concurrencyEnabled ){ - // trigger concurrent building / downloading dependencies - exportClasspathConcurrently - } - */ - lib.classLoaderRecursion( - this, - (this +: transitiveDependencies).collect{ - case d: ArtifactInfo => d - }.groupBy( - d => (d.groupId,d.artifactId) - ).mapValues(_.head) - ) + /* + if( concurrencyEnabled ){ + // trigger concurrent building / downloading dependencies + exportClasspathConcurrently } + */ + lib.classLoaderRecursion( + this, + (this +: transitiveDependencies).collect{ + case d: ArtifactInfo => d + }.groupBy( + d => (d.groupId,d.artifactId) + ).mapValues(_.head) + ) } // FIXME: these probably need to update outdated as well def classpath: ClassPath = exportedClasspath ++ dependencyClasspath def verifyClasspath: Unit = classpath.verify(lib) - def dependencyClasspath: ClassPath = taskCache[DependencyImplementation]( "dependencyClasspath" ).memoize{ + def dependencyClasspath: ClassPath = { ClassPath( transitiveDependencies .flatMap(_.exportedClasspath.files) @@ -369,7 +368,13 @@ case class BoundMavenDependency( cbtLastModified, mavenCache ++ basePath(true) ++ ".pom.dependencies", classLoaderCache.hashMap )( MavenDependency.deserialize )( _.serialize )( MavenDependency.dejavafy )( _.map(_.javafy).toArray ){ (pomXml \ "dependencies" \ "dependency").collect{ - case xml if ( (xml \ "scope").text == "" || (xml \ "scope").text == "compile" ) && (xml \ "optional").text != "true" => + case xml if ( + (xml \ "scope").text == "" + // these are probably not right like this, but should be better than not having them for now + || (xml \ "scope").text == "runtime" + || (xml \ "scope").text == "compile" + || (xml \ "scope").text == "provided" + ) && (xml \ "optional").text != "true" => val artifactId = lookup(xml,_ \ "artifactId").get val groupId = lookup(xml,_ \ "groupId").getOrElse( diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 05e3c41c..a28c8609 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -17,7 +17,7 @@ trait BaseBuild extends BuildInterface with DependencyImplementation with SbtDep // will create new instances given the context, which means operations in the // overrides will happen multiple times and if they are not idempotent stuff likely breaks def context: Context - override lazy val moduleKey: String = "BaseBuild("+target.string+")" + override lazy val moduleKey: String = "BaseBuild("+target.string+","+context.scalaVersion+")" implicit def transientCache: java.util.Map[AnyRef,AnyRef] = context.transientCache object libraries extends libraries( context, scalaVersion, scalaMajorVersion ) diff --git a/stage2/GitDependency.scala b/stage2/GitDependency.scala index 8a4a4413..26d758a0 100644 --- a/stage2/GitDependency.scala +++ b/stage2/GitDependency.scala @@ -22,6 +22,8 @@ object GitDependency{ ++ "(" ++ url ++ subDirectory.map("/" ++ _).getOrElse("") ++ "#" ++ ref ++ ", " ++ subBuild.mkString(", ") + ++ ", " + ++ context.scalaVersion.toString ++ ")" ) diff --git a/stage2/LazyDependency.scala b/stage2/LazyDependency.scala index 2822638c..2cfcd273 100644 --- a/stage2/LazyDependency.scala +++ b/stage2/LazyDependency.scala @@ -5,7 +5,7 @@ class LazyDependency( _dependency: => Dependency )( implicit logger: Logger, tra def dependenciesArray = Array( dependency ) def exportedClasspathArray = Array() override def lastModified = dependency.lastModified - override lazy val moduleKey = show + override lazy val moduleKey = "LazyDependency:" + dependency.moduleKey def show = s"LazyDependency(${dependency.show})" override def toString = show override def equals( other: Any ) = other match {