aboutsummaryrefslogtreecommitdiff
path: root/stage2/BuildBuild.scala
blob: 9d3458d1436371282d4c690719f9c4db368a1c39 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package cbt
import java.nio.file._
import java.io.File

class ConcreteBuildBuild(val context: Context) extends BuildBuild
class ConcreteBuildBuildWithoutEssentials(val context: Context) extends BuildBuildWithoutEssentials
trait BuildBuild extends BuildBuildWithoutEssentials{
  override def dependencies =
    super.dependencies :+ plugins.essentials
}
class plugins(implicit context: Context){
  // TODO: move this out of the OO
  private def plugin(dir: String) = DirectoryDependency(
    context.copy(
      workingDirectory = context.cbtHome / "plugins" / dir
    )
  )
  final lazy val essentials = plugin( "essentials" )
  final lazy val googleJavaFormat = plugin( "google-java-format" )
  final lazy val proguard = plugin( "proguard" )
  final lazy val sbtLayout = plugin( "sbt_layout" )
  final lazy val scalafmt = plugin( "scalafmt" )
  final lazy val scalaJs   = plugin( "scalajs" )
  final lazy val scalariform = plugin( "scalariform" )
  final lazy val scalaTest = plugin( "scalatest" )
  final lazy val sonatypeRelease = plugin( "sonatype-release" )
  final lazy val uberJar = plugin( "uber-jar" )
  final lazy val wartremover = plugin( "wartremover" )
}
trait BuildBuildWithoutEssentials extends BaseBuild{
  object plugins extends plugins

  assert(
    projectDirectory.getName === lib.buildDirectoryName,
    s"You can't extend ${lib.buildBuildClassName} in: " + projectDirectory + "/" + lib.buildDirectoryName
  )

  protected final val managedContext = context.copy(
    workingDirectory = managedBuildDirectory,
    parentBuild=Some(this)
  )

  override def dependencies =
    super.dependencies :+ context.cbtDependency

  def managedBuildDirectory: java.io.File = lib.realpath( projectDirectory.parent )
  def managedBuild = taskCache[BuildBuildWithoutEssentials]("managedBuild").memoize{
    val managedBuildFile = projectDirectory++("/"++lib.buildFileName)
    logger.composition("Loading build at " ++ managedBuildDirectory.toString)
    val build = (
      if( !managedBuildFile.exists ){
        throw new Exception(
          s"No file ${lib.buildFileName} (lower case) found in " ++ projectDirectory.getPath
        )
      } else {
        val contents = new String(Files.readAllBytes(managedBuildFile.toPath))
        val cbtUrl = ("cbt:"++GitDependency.GitUrl.regex++"#[a-z0-9A-Z]+").r
        cbtUrl
          .findFirstIn(contents)
          .flatMap{
            url =>
            val Array(base,hash) = url.drop(4).split("#")
            if(context.cbtHome.string.contains(hash))
              None
            else Some{
              // Note: cbt can't use an old version of itself for building,
              // otherwise we'd have to recursively build all versions since
              // the beginning. Instead CBT always needs to build the pure Java
              // Launcher in the checkout with itself and then run it via reflection.
              val build = GitDependency(base, hash, Some("nailgun_launcher")).asInstanceOf[BaseBuild]
              val ctx = managedContext.copy( cbtHome = build.projectDirectory.getParentFile )
              build.classLoader
                .loadClass( "cbt.NailgunLauncher" )
                .getMethod( "getBuild", classOf[AnyRef] )
                .invoke( null, ctx )
            }
          }.getOrElse{
            val buildClasses =
              lib.iterateClasses( compileTarget, classLoader, false )
                .filter(_.getSimpleName == lib.buildClassName)
                .filter(classOf[BaseBuild] isAssignableFrom _)
            if( buildClasses.size == 0 ){
              throw new Exception(
                s"You need to define a class ${lib.buildClassName} extending an appropriate super class in\n"
                + (projectDirectory / lib.buildFileName) ++ "\nbut none found."
              )
            } else if( buildClasses.size > 1 ){
              throw new Exception(
                s"You need to define exactly one class ${lib.buildClassName} extending an appropriate build super class, but multiple found in " + projectDirectory + ":\n" + buildClasses.mkString("\n")
              )
            } else {
              val buildClass = buildClasses.head
              if( !buildClass.getConstructors.exists(_.getParameterTypes.toList == List(classOf[Context])) ){
                throw new Exception(
                  s"Expected class ${lib.buildClassName}(val context: Context), but found different constructor in\n"
                  + projectDirectory ++ "\n"
                  + buildClass ++ "(" ++ buildClass.getConstructors.map(_.getParameterTypes.mkString(", ")).mkString("; ") + ")" )
              }
              buildClass.getConstructors.head.newInstance(managedContext)
            }
          }
      }
    )
    try{
      build.asInstanceOf[BuildInterface]
    } catch {
      case e: ClassCastException if e.getMessage.contains(s"${lib.buildClassName} cannot be cast to cbt.BuildInterface") =>
        throw new Exception(s"Your ${lib.buildClassName} class needs to extend BaseBuild in: "+projectDirectory, e)
    }
  }
  override def triggerLoopFiles = super.triggerLoopFiles ++ managedBuild.triggerLoopFiles
  @deprecated("use finalbuild(File)","")
  override def finalBuild: BuildInterface = finalBuild( context.cwd )
  override def finalBuild( current: File ): BuildInterface = {
    val p = projectDirectory.getCanonicalFile
    val c = current.getCanonicalFile
    if( c == p ) this else managedBuild.finalBuild( current )
  }
}

trait CbtInternal extends BuildBuild{
  protected object cbtInternal{
    def shared = DirectoryDependency(context.cbtHome / "/internal/plugins/shared")
    def library = DirectoryDependency(context.cbtHome / "/internal/plugins/library")
  }
}