Skip to content
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

WIP - adding example to cross-rewrite #466

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

ShaneDelmore
Copy link

This is not even close to ready, just making a pr to see if I am on the right track.

@CLAassistant
Copy link

CLAassistant commented Mar 28, 2017

CLA assistant check
All committers have signed the CLA.

class Build(val context: Context) extends BaseBuild{ outer =>
override def defaultScalaVersion = "2.11.8"
class Build(val context: Context) extends BaseBuild { outer =>
override def defaultScalaVersion = "2.12.1"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the default because I thought people might like to write code in the latest version and backwards compile.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

override def test: Dependency = {
new BasicBuild(context) with ScalaTest {
override def dependencies = outer +: super.dependencies
override def defaultScalaVersion = "2.12.1"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct that I need to override version for test build (why would I ever want to test on a different version?)
Or should my test be extending my main project somehow to have access to the code in it?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you overwrote defautScalaVersion is class Build, but here you are instantiating class BasicBuild. That's fine, but it doesn't magically pick up on what you overwrote in Build. So if you want this as 2.12.1 you need to provide that info here somehow.

val fromTo = lib.autoRelative(outer.sources).collect {
case (location, relative) if location.isFile =>
location -> projectDirectory / "src" / relative
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scalafmt must have changed all of this slightly. Would you be interested in a pr adding a .scalafmt config to the project?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not completely warmed up to scalafmt yet. I played around with it a bit, but it currently does not allow me to produce code that I find as readable as scalariform. So for now I have settled on Scalariform for CBT and there is a preconfigured plugins.scalariform plugin you can add as a dependency to your BuildBuild, allowing you to mix in Scalariform into your build, which adds a preconfigured task scalariform, which by default is not run on compile, but can be easily added (in which case one has to call scalariform.apply there, because it is lazy).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(had a longer discussion with olaf around the limitations of scalafmt for my personal preferred style a few weeks ago)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. I don't mind using scalariform but I may take a shot at making a .scalafmt.conf that matches your scalariform preferences just to see if I can.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scalafmt does not have any settings which mimic scalariform, they're very different formatters.

object Main {
def main(args: Array[String]): Unit = {
//For 2.11.8 rewrite to case match
Disjunction.intOrString.map(println)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could either rewrite this to a case statement for scalaz 2.11.8 (I don't believe they have an either enrichment for map) or I could change the type to /. Either one would require the semantic mirror which I am not clear is actually available based on @olafurpg comment about ExplicitImplicit being available. I will experiment more once I get tests to pass.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a semantic mirror is available, just not the Scalafix Mirror, which ExplicitImplicit is currently coded against.

@@ -9,7 +9,7 @@ trait ScalaTest extends BaseBuild{
runSuites( suiteNames.map( loadSuite( _, classLoader ) ) )
ExitCode.Success
}
override def dependencies = super.dependencies ++ Resolver( mavenCentral ).bind( ScalaDependency("org.scalatest","scalatest","2.2.4") )
override def dependencies = super.dependencies ++ Resolver( mavenCentral ).bind( ScalaDependency("org.scalatest","scalatest","3.0.1") )
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no 2.x version of Scalatest for scala 2.12 so I bumped to scalatest 3.0.1.

@@ -5,6 +5,6 @@ class Build(val context: Context) extends BaseBuild{
super.dependencies
:+ context.cbtDependency
) ++ Resolver( mavenCentral ).bind(
ScalaDependency("org.scalatest","scalatest","2.2.4")
ScalaDependency("org.scalatest","scalatest","3.0.1")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't looked into this yet but don't like that there are these duplicated strings in multiple files. Maybe I need to create a Dependencies.scala file to share them.

val fromTo = lib.autoRelative(outer.sources).collect {
case (location, relative) if location.isFile =>
location -> projectDirectory / "src" / relative
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(had a longer discussion with olaf around the limitations of scalafmt for my personal preferred style a few weeks ago)

object Main {
def main(args: Array[String]): Unit = {
//For 2.11.8 rewrite to case match
Disjunction.intOrString.map(println)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a semantic mirror is available, just not the Scalafix Mirror, which ExplicitImplicit is currently coded against.

override def defaultScalaVersion = "2.12.1"

override def test: Dependency = {
new BasicBuild(context) with ScalaTest {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to add override def projectDirectory = outer.projectDirectory / "test" here, so it can find your source files. Otherwise it only looks in context.workingDirectory and context.workingDirectory / "src". context.workingDirectory is the default for BaseBuild.projectDirectory and the directory one up from the build.scala file. I'd suggest you look start looking into the source code a little bit. CBT makes that quite easy :).

@cvogt
Copy link
Owner

cvogt commented Mar 31, 2017

the tests check for the existence of a cats AND scalaz crossbuilds, which is why this still fails ;).

@ShaneDelmore
Copy link
Author

Ah, that makes sense. That should be easy enough for me to resolve Saturday.

Replace(Symbol("_root_.Disjunction."), q"Test"),
Rename(q"intOrString", q"xor"),
//And this works again. What is different about import rewrites vs the others?
RemoveGlobalImport(importer"scala.concurrent.Future")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if I am missing something or if there is a bug in scalafix, but import releated rewrites work and others do not. I can't tell what the difference is yet. I looked back through scalafix code and these are all instances of TreePatch. Once the patching works this should be as simple as adding scalaz./, replacing Either with / and Right with /-

//None of these work, why?
Replace(Symbol("_root_.scala.util.Either."), q"\/"),
Replace(Symbol("_root_.Disjunction."), q"Test"),
Rename(q"intOrString", q"xor"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename should probably be called RenameThisInstance (or similar) because it's reference based, I opened scalacenter/scalafix#109 to track that change. To replace call-sites of a specific definition you want to use Replace, which is symbol based.

//This works
AddGlobalImport(importer"scalaz._"),
//None of these work, why?
Replace(Symbol("_root_.scala.util.Either."), q"\/"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried Mirror.database.toString to double check that this symbol matches the symbol you want to rewrite? Otherwise, please open an issue in scalafix and I can take a look at it next week.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type of scala.util.Either is actually scala.package.Either. Printing out the mirror.database helped, thanks @olafurpg

println("printing mirror database messages")
println(ctx.mirror.database)
println("end printing")
assert(ctx.mirror.database.toString.trim != "", "I do not believe the database should be empty here")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@olafurpg The semantic db appears to be empty here even though sources is not. Do you think the semantic db is being constructed incorrectly, or that I should open a scalameta issue on this?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project source files need to be compiled with the scalahost compiler plugin for the database to be built, so the Scalameta plugin needs to be mixed in the root build. The mirror is composed of a classpath (pointing to at least one directory containing semanticdb files) and a sourcepath (pointing to scala source files). In this case, the classpath does not contain any semanticdb files, maybe the Mirror constructor should fail in that case.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do believe fail fast would be better here, but this should be enough to advice to get me back on track. 👍

Mirror(
classpath.string,
files.map(_._1).mkString(File.pathSeparator)
)
}

def context(file: File): ( RewriteCtx[Mirror], RewriteCtx[ScalafixMirror] ) = (
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RewriteCtx[ScalafixMirror] is not necessary here, ScalafixMirror will go away in favor of Mirror.

@@ -6,67 +6,101 @@ import scalafix.util._
import scalafix.util.TreePatch._
import scalafix.util.TokenPatch._

class Build(val context: Context) extends BaseBuild{ outer =>
class Build(val context: Context) extends BaseBuild { outer =>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's missing a with Scalameta here to inject the scalahost compiler plugin, which generates semanticdb files under target/.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doh! Thanks for catching that.

val fromTo = lib.autoRelative(outer.sources).collect {
case (location, relative) if location.isFile =>
location -> projectDirectory / "src" / relative
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scalafmt does not have any settings which mimic scalariform, they're very different formatters.

println("printing mirror database messages")
println(ctx.mirror.database)
println("end printing")
assert(ctx.mirror.database.toString.trim != "", "I do not believe the database should be empty here")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project source files need to be compiled with the scalahost compiler plugin for the database to be built, so the Scalameta plugin needs to be mixed in the root build. The mirror is composed of a classpath (pointing to at least one directory containing semanticdb files) and a sourcepath (pointing to scala source files). In this case, the classpath does not contain any semanticdb files, maybe the Mirror constructor should fail in that case.

//Over time I would hope to build up a community libraryof rewrites so many of the transforms would be pulled from
//a library instead of declared in the build
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore everything below here, I didn't mean to commit it.

@ShaneDelmore
Copy link
Author

I forgot all about this PR. Will try to take a look at it in a few days and see if I can figure out why tests fail.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants