aboutsummaryrefslogtreecommitdiff
path: root/stage2/plugins/ExportBuildInformation.scala
blob: 0d33d75c4967192328c46e4e8b8113412392c170 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package cbt

import cbt._
import scala.xml._
import java.io._

trait ExportBuildInformation { self: BaseBuild =>
  lazy val printer = new scala.xml.PrettyPrinter(200, 2)

  def buildInfoXml = 
    printer.format(BuildInformationSerializer.serialize(BuildInformation.Project(self)))
}

object BuildInformation {
  case class Project(
    name: String,
    root: File,
    rootModule: Module,
    modules: Seq[Module],
    libraries: Seq[Library]
  )

  case class Module(
    name: String,
    root: File,
    sources: Seq[File],
    target: File,
    mavenDependencies: Seq[MavenDependency],
    moduleDependencies: Seq[ModuleDependency],
    classpaths: Seq[ClassPathItem],
    parentBuild: Option[String]
  )

  case class Library( name: String, jars: Seq[File] )

  case class MavenDependency( name: String )

  case class ModuleDependency( name: String )

  case class ClassPathItem( path: File )

  object Project {
    def apply(build: BaseBuild) =   
     new BuildInformationExporter(build).exportBuildInformation  

    private class BuildInformationExporter(rootBuild: BaseBuild) {
      def exportBuildInformation(): Project = {
        val rootModule = exportModule(rootBuild)
        val modules = (rootBuild +: rootBuild.transitiveDependencies)
          .collect { case d: BaseBuild => d +: collectParentBuilds(d)}
          .flatten
          .map(exportModule)
          .distinct
        val libraries = rootBuild.transitiveDependencies
          .collect { case d: BoundMavenDependency => exportLibrary(d)}
          .distinct
       
        Project(
          rootModule.name,
          rootModule.root,
          rootModule,
          modules,
          libraries
        )
      }

      private def exportLibrary(mavenDependency: BoundMavenDependency) = 
        Library(fomatMavenDependency(mavenDependency.mavenDependency), mavenDependency.exportedJars)

      private def collectParentBuilds(build: BaseBuild): Seq[BaseBuild] = 
          build.context.parentBuild
            .map(_.asInstanceOf[BaseBuild])
            .map(b => b +: collectParentBuilds(b))
            .toSeq
            .flatten

      private def exportModule(build: BaseBuild): Module = {
        val moduleDependencies = build.dependencies
          .collect { case d: BaseBuild => ModuleDependency(moduleName(d)) }
        val mavenDependencies = build.dependencies
          .collect { case d: BoundMavenDependency => MavenDependency(fomatMavenDependency(d.mavenDependency))}
        val classpaths = build.dependencyClasspath.files
          .filter(_.isFile)
          .map(t => ClassPathItem(t))
        val sources = {
          val s = build.sources
            .filter(s => s.exists && s.isDirectory)
          if (s.isEmpty)
            Seq(build.projectDirectory)
          else
            s
        }
        Module(
          name = moduleName(build),
          root = build.projectDirectory,
          sources = sources,
          target = build.target,
          mavenDependencies = mavenDependencies,
          moduleDependencies = moduleDependencies,
          classpaths = classpaths,
          parentBuild = build.context.parentBuild.map(b => moduleName(b.asInstanceOf[BaseBuild]))
        )
      }

      private def fomatMavenDependency(dependency: cbt.MavenDependency) =
        s"${dependency.groupId}:${dependency.artifactId}:${dependency.version}"

      private def moduleName(build: BaseBuild) = 
          if (rootBuild.projectDirectory == build.projectDirectory)
            rootBuild.projectDirectory.getName
          else
            build.projectDirectory.getPath
              .drop(rootBuild.projectDirectory.getPath.length)
              .stripPrefix("/")
              .replace("/", "-")
    }
  }
}

object BuildInformationSerializer {
  def serialize(project: BuildInformation.Project): Node = 
    <project>
      <name>{project.name}</name>
      <root>{project.root.toString}</root>
      <rootModule>{project.rootModule.name}</rootModule>
      <modules>
        {project.modules.map(serialize)}
      </modules>
      <libraries>
        {project.libraries.map(serialize)}
      </libraries>
    </project>

  private def serialize(module: BuildInformation.Module): Node = 
    <module>
      <name>{module.name}</name>
      <root>{module.root}</root>
      <target>{module.target}</target>      
      <sources>
        {module.sources.map(s => <source>{s}</source>)}
      </sources>
      <mavenDependencies>
        {module.mavenDependencies.map(serialize)}
      </mavenDependencies>
      <moduleDependencies>
        {module.moduleDependencies.map(serialize)}
      </moduleDependencies>
      <classpaths>
        {module.classpaths.map(serialize)}
      </classpaths>
      {module.parentBuild.map(p => <parentBuild>{p}</parentBuild>).getOrElse(NodeSeq.Empty)}
    </module>

  private def serialize(mavenDependency: BuildInformation.MavenDependency): Node = 
    <mavenDependency>{mavenDependency.name}</mavenDependency>

  private def serialize(library: BuildInformation.Library): Node = 
    <library>
      <name>{library.name}</name>
      <jars>
        {library.jars.map(j => <jar>{j}</jar>)}
      </jars>
    </library>

  private def serialize(moduleDependency: BuildInformation.ModuleDependency): Node = 
    <moduleDependency>{moduleDependency.name}</moduleDependency>

  private def serialize(targetLibrary: BuildInformation.ClassPathItem): Node = 
    <classpathItem>{targetLibrary.path.toString}</classpathItem>
}