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

dynamic re-configuration #62

Closed
cvogt opened this issue Mar 8, 2016 · 6 comments · Fixed by #300
Closed

dynamic re-configuration #62

cvogt opened this issue Mar 8, 2016 · 6 comments · Fixed by #300
Milestone

Comments

@cvogt
Copy link
Owner

cvogt commented Mar 8, 2016

There are multiple use cases for re-configuring a build at runtime. E.g. appending "-SNAPSHOT" to the version number when deploying a snapshot. Or changing the scalaVersion for cross-builds. It is not obvious how to do this, because CBT builds are classes where things are hard wired after instantiation if members are final. More concretely, this isn't possible:

class Build ... {
  def publishSnapshot{
    this.version = this.version + "-SNAPSHOT"
    publish
  }
}

Candidate solutions are

  1. exposing selected fields like the through the constructor and providing via cli mechanism that fills them in (easy to implement, easy to work with, limited to hard coded use cases)

  2. mutable members (easy to implement, tricky to work with, probably not a good idea)

  3. providing users with a general purpose runtime mixins mechanism (hard to implement, easy to work with). Could look like this

    class BasicBuild(...){
      def publishSnapshot: Unit = {
        val reconfiguredBuild = this.mixin(
          new BasicBuild{
            override def version = super.version+-SNAPSHOT”
          }
        ): reconfiguredBuild
        b.publish
      }
    }
  4. Hard-coding something like 3, but specific to CBT (slightly less hard to implement, easy to work with, less universal). It would look at what's given and generate a trait that overrides exactly those fields. E.g. if a version is given via the command line, CBT would create build objects like this

    class DynamicOverrides{
      override def version = super.version+-SNAPSHOT”
    }
    new Build(...) with DynamicOverrides

    Or if the user needs to override things, there could be an api to do so:

    val reconfiguredBuild = this.replace( version = this.version+"-SNAPSHOT" )

    or

    val reconfiguredBuild = (this.version = this.version+"-SNAPSHOT")

    or

    val reconfiguredBuild = this.version.set(this.version+"-SNAPSHOT")

    All of these would need to be magical of course, turning the given expression into the right hand side of a def of a mixed in trait.

  5. On the Typelevel front people are considering creating an alternative frontend (which CBT supports), that is not based on inheritance, but a state monad instead. Would be interesting to see how that would look like and how it would differ from SBT's state monad

@cvogt
Copy link
Owner Author

cvogt commented Apr 8, 2016

so for now I added hard coded solutions for version numbers. We can pick this up again later to make it more general.

d915335

@cvogt cvogt added this to the 1.1 milestone Apr 8, 2016
@cvogt
Copy link
Owner Author

cvogt commented May 12, 2016

another way of doing it would be proxies. as @nafg wrote in gitter:

looks like autoproxy was redone with macros: https://github.com/thecoda/autoproxy
here's another one: https://github.com/adamw/scala-macro-aop
related blog: http://www.warski.org/blog/2013/09/automatic-generation-of-delegate-methods-with-macro-annotations/

@cvogt
Copy link
Owner Author

cvogt commented Jun 24, 2016

@nafg this is similar to the context stuff you proposed actually I think.

@cvogt
Copy link
Owner Author

cvogt commented Jul 20, 2016

(side-not this may be similar to what some mocking libraries do, in that we replace implementations dynamically. We could do that at runtime via byte-code re-writing, or runtime scala code-generation or static code generation)

@cvogt cvogt mentioned this issue Nov 8, 2016
@cvogt
Copy link
Owner Author

cvogt commented Nov 8, 2016

So the PR above uses twitter Eval to pull it off. Was surprisingly simple to do and performances is acceptable. Slowing down nailgun supported calls from 0.1 to 0.4-0.5 seconds on my machine.

@cvogt
Copy link
Owner Author

cvogt commented Nov 10, 2016

So happy I found an elegant solution to this. Small implementation. Full flexibility, abstraction, compositionally for cbt users. And even much more performant than I expected, eventhough there is probably room for more, in particular caching generated code and not recompiling it. Maybe just dumping it into a generated cbt build depending on the hand-written build would solve this.

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 a pull request may close this issue.

1 participant