aboutsummaryrefslogtreecommitdiff
path: root/stage2/plugins/ExportBuildInformation.scala
diff options
context:
space:
mode:
Diffstat (limited to 'stage2/plugins/ExportBuildInformation.scala')
-rw-r--r--stage2/plugins/ExportBuildInformation.scala236
1 files changed, 156 insertions, 80 deletions
diff --git a/stage2/plugins/ExportBuildInformation.scala b/stage2/plugins/ExportBuildInformation.scala
index c5c69ab..37dcc38 100644
--- a/stage2/plugins/ExportBuildInformation.scala
+++ b/stage2/plugins/ExportBuildInformation.scala
@@ -4,14 +4,24 @@ import cbt._
import java.io._
import java.nio.file._
import scala.xml._
-import scala.util._
+import scala.util._
trait ExportBuildInformation { self: BaseBuild =>
- def buildInfoXml: String =
- BuildInformationSerializer.serialize(BuildInformation.Project(self, context.args)).toString
+ def buildInfoXml: String = {
+ val parameters = BuildInformation.Project.ExportParameters(context.args)
+ val xml = BuildInformationSerializer.serialize(BuildInformation.Project(self, parameters))
+ parameters.outputFile match {
+ case None =>
+ xml.toString
+ case Some(file) =>
+ XML.save(file.getPath, xml)
+ s"Saved to ${file.getPath}"
+ }
+ }
}
object BuildInformation {
+
case class Project(
name: String,
root: File,
@@ -27,6 +37,7 @@ object BuildInformation {
root: File,
scalaVersion: String,
sourceDirs: Seq[File],
+ moduleType: ModuleType,
target: File,
binaryDependencies: Seq[BinaryDependency],
moduleDependencies: Seq[ModuleDependency],
@@ -34,7 +45,7 @@ object BuildInformation {
parentBuild: Option[String],
scalacOptions: Seq[String]
)
-
+
case class Library( name: String, jars: Seq[LibraryJar] )
case class BinaryDependency( name: String )
@@ -43,61 +54,76 @@ object BuildInformation {
case class ScalaCompiler( version: String, jars: Seq[File] )
- case class LibraryJar( jar: File, jarType: JarType.JarType )
+ case class LibraryJar( jar: File, jarType: JarType )
+
+ case class JarType( name: String )
+
+ object JarType {
+ object Binary extends JarType( "binary" )
+ object Source extends JarType( "source" )
+ }
+
+ case class ModuleType( name: String )
- object JarType extends Enumeration {
- type JarType = Value
- val Binary = Value("binary")
- val Source = Value("source")
+ object ModuleType {
+ object Default extends ModuleType( "default" )
+ object Extra extends ModuleType( "extra" )
+ object Test extends ModuleType( "test" )
+ object Build extends ModuleType( "build" )
}
object Project {
- def apply(build: BaseBuild, args: Seq[String]): Project = {
- val extraModuleNames: Seq[String] = args.lift(0).map(_.split(":").toSeq).getOrElse(Seq.empty)
- new BuildInformationExporter(build, extraModuleNames).exportBuildInformation
+ def apply(build: BaseBuild, parameters: ExportParameters): Project = {
+ new BuildInformationExporter(build, parameters).exportBuildInformation
}
- class BuildInformationExporter(rootBuild: BaseBuild, extraModuleNames: Seq[String]) {
+ class BuildInformationExporter(rootBuild: BaseBuild, parameters: ExportParameters) {
+ import parameters._
+
def exportBuildInformation: Project = {
- val moduleBuilds = transitiveBuilds(rootBuild)
- val libraries = moduleBuilds
- .flatMap(_.transitiveDependencies)
- .collect { case d: BoundMavenDependency => exportLibrary(d) }
+ val extraModuleBuilds = extraModulePaths
+ .map(f => DirectoryDependency(f)(rootBuild.context).dependency.asInstanceOf[BaseBuild])
+ val builds = transitiveBuilds((rootBuild, ModuleType.Default) +: extraModuleBuilds.map(b => (b, ModuleType.Extra)))
+ val rootModule = exportModule(rootBuild, ModuleType.Default)
+ val modules = builds
+ .map(m => exportModule(m._1, m._2))
.distinct
- val cbtLibraries = convertCbtLibraries
- val rootModule = exportModule(rootBuild)
- val extraModuleBuilds = extraModuleNames
- .map(f => new File(f))
- .filter(f => f.exists && f.isDirectory)
- .map(f => DirectoryDependency(f)(rootBuild.context).dependency.asInstanceOf[BaseBuild])
- .flatMap(transitiveBuilds)
- val modules = (moduleBuilds ++ extraModuleBuilds)
- .map(exportModule)
+ val libraries = builds
+ .map(_._1)
+ .flatMap(_.transitiveDependencies)
+ .collect { case d: BoundMavenDependency => exportLibrary(d) }
.distinct
+ val cbtLibraries = if (needCbtLibs) convertCbtLibraries else Seq.empty[Library]
val scalaCompilers = modules
.map(_.scalaVersion)
- .map(v => ScalaCompiler(v, resolveScalaCompiler(rootBuild, v)))
+ .map(v => ScalaCompiler(v, resolveScalaCompiler(v)))
+ .distinct
Project(
- rootModule.name,
- rootModule.root,
- rootModule,
- modules,
- libraries,
- cbtLibraries,
- scalaCompilers
+ name = rootModule.name,
+ root = rootModule.root,
+ rootModule = rootModule,
+ modules = modules,
+ libraries = libraries,
+ cbtLibraries = cbtLibraries,
+ scalaCompilers = scalaCompilers
)
}
- private def convertCbtLibraries =
- transitiveBuilds(DirectoryDependency(rootBuild.context.cbtHome)(rootBuild.context).dependenciesArray.head.asInstanceOf[BaseBuild])
+
+ private def convertCbtLibraries = {
+ val cbtBuild =
+ DirectoryDependency(rootBuild.context.cbtHome)(rootBuild.context).dependenciesArray.head.asInstanceOf[BaseBuild]
+ transitiveBuilds(Seq((cbtBuild, ModuleType.Default)), skipTests = true)
+ .map(_._1)
.collect {
case d: BoundMavenDependency => d.jar
case d: PackageJars => d.jar.get
}
.map(exportLibrary)
.distinct
+ }
private def collectDependencies(dependencies: Seq[Dependency]): Seq[ModuleDependency] =
dependencies
@@ -107,7 +133,7 @@ object BuildInformation {
}
.flatten
- private def exportModule(build: BaseBuild): Module = {
+ private def exportModule(build: BaseBuild, moduleType: ModuleType): Module = {
val moduleDependencies = collectDependencies(build.dependencies)
val mavenDependencies = build.dependencies
.collect { case d: BoundMavenDependency => BinaryDependency(formatMavenDependency(d.mavenDependency)) }
@@ -130,6 +156,7 @@ object BuildInformation {
scalaVersion = build.scalaVersion,
sourceDirs = sourceDirs,
target = build.target,
+ moduleType = moduleType,
binaryDependencies = mavenDependencies,
moduleDependencies = moduleDependencies,
classpath = classpath,
@@ -153,30 +180,33 @@ object BuildInformation {
.map(_.toFile)
}
- private def collectLazyBuilds(dependency: Dependency): Option[BaseBuild] =
- dependency match {
- case l: LazyDependency =>
- l.dependency match {
- case d: BaseBuild => Some(d)
- case d: LazyDependency => collectLazyBuilds(d.dependency)
- case _ => None
- }
- case d: BaseBuild => Some(d)
- case _ => None
- }
-
-
- private def transitiveBuilds(build: BaseBuild): Seq[BaseBuild] =
- (build +: build.transitiveDependencies)
- .collect {
- case d: BaseBuild => d +: collectParentBuilds(d).flatMap(transitiveBuilds)
- case d: LazyDependency =>
- collectLazyBuilds(d.dependency)
- .toSeq
- .flatMap(transitiveBuilds)
+ // More effectively to call on a all builds at once rather than on one per time
+ private def transitiveBuilds(builds: Seq[(BaseBuild, ModuleType)], skipTests: Boolean = false): Seq[(BaseBuild, ModuleType)] = {
+ def traverse(visitedProd: (Seq[BaseBuild], Seq[ModuleType]), buildProd: (BaseBuild, ModuleType)): (Seq[BaseBuild], Seq[ModuleType]) = {
+ val (visited, moduleTypes) = visitedProd
+ val (build, moduleType) = buildProd
+ if (visited.contains(build))
+ (visited, moduleTypes)
+ else {
+ val testBuildSeq = if (!skipTests) testBuild(build) else Seq.empty
+ (build.transitiveDependencies.map(d => (d, ModuleType.Default)) ++
+ parentBuild(build).map(d => (d, ModuleType.Build)) ++
+ testBuildSeq.map(d => (d, ModuleType.Test))
+ )
+ .collect {
+ case (d: BaseBuild, t) =>
+ (d, t)
+ case (d: LazyDependency, t) if d.dependency.isInstanceOf[BaseBuild] =>
+ (d.dependency.asInstanceOf[BaseBuild], t)
+ }
+ .filterNot(b => visited.contains(b._1))
+ .foldLeft(build +: visited, moduleType +: moduleTypes)(traverse)
}
- .flatten
- .distinct
+ }
+ val (collectedBuilds, collectedTypes) = builds
+ .foldLeft(Seq.empty[BaseBuild], Seq.empty[ModuleType])(traverse)
+ collectedBuilds.zip(collectedTypes)
+ }
private def exportLibrary(dependency: BoundMavenDependency) = {
val name = formatMavenDependency(dependency.mavenDependency)
@@ -190,14 +220,14 @@ object BuildInformation {
implicit val transientCache: java.util.Map[AnyRef, AnyRef] = rootBuild.context.transientCache
implicit val classLoaderCache: ClassLoaderCache = rootBuild.context.classLoaderCache
val sourceJars = jars
- .map { d =>
+ .map { d =>
Try(d.copy(mavenDependency = d.mavenDependency.copy(classifier = Classifier.sources)).jar)
- }
+ }
.flatMap {
case Success(j) => Some(j)
case Failure(e) =>
logger.log("ExportBuildInformation", s"Can not load a $name library sources. Skipping")
- None
+ None
}
.map(LibraryJar(_, JarType.Source))
Library(name, binaryJars ++ sourceJars)
@@ -206,15 +236,22 @@ object BuildInformation {
private def exportLibrary(file: File) =
Library("CBT:" + file.getName.stripSuffix(".jar"), Seq(LibraryJar(file, JarType.Binary)))
- private def collectParentBuilds(build: BaseBuild): Seq[BaseBuild] =
+ private def parentBuild(build: BaseBuild): Seq[BaseBuild] =
build.context.parentBuild
.map(_.asInstanceOf[BaseBuild])
- .map(b => b +: collectParentBuilds(b))
.toSeq
- .flatten
- private def resolveScalaCompiler(build: BaseBuild, scalaVersion: String) =
- build.Resolver(mavenCentral, sonatypeReleases).bindOne(
+ private def testBuild(build: BaseBuild): Seq[BaseBuild] =
+ Try(build.test)
+ .toOption
+ .toSeq
+ .flatMap {
+ case testBuild: BaseBuild => Seq(testBuild)
+ case _ => Seq.empty
+ }
+
+ private def resolveScalaCompiler(scalaVersion: String) =
+ rootBuild.Resolver(mavenCentral, sonatypeReleases).bindOne(
MavenDependency("org.scala-lang", "scala-compiler", scalaVersion)
).classpath.files
@@ -222,8 +259,7 @@ object BuildInformation {
if (source.isDirectory)
source
else
- source.getParentFile //Let's asume that for now
-
+ source.getParentFile //Let's assume that for now
private def formatMavenDependency(dependency: cbt.MavenDependency) =
s"${dependency.groupId}:${dependency.artifactId}:${dependency.version}"
@@ -237,12 +273,30 @@ object BuildInformation {
.stripPrefix("/")
.replace("/", "-")
}
+
+ case class ExportParameters(extraModulePaths: Seq[File], needCbtLibs: Boolean, outputFile: Option[File])
+
+ object ExportParameters {
+ def apply(args: Seq[String]): ExportParameters = {
+ val argumentParser = new ArgumentParser(args)
+ val extraModulePaths = argumentParser.value("extraModules")
+ .map(_.split(":").toSeq)
+ .getOrElse(Seq.empty)
+ .map(p => new File(p))
+ .filter(f => f.exists && f.isDirectory)
+ val needCbtLibs: Boolean = argumentParser.value("needCbtLibs").forall(_.toBoolean)
+ val outputFile = argumentParser.value("outputFile").map(p => new File(p))
+ ExportParameters(extraModulePaths, needCbtLibs, outputFile)
+ }
+ }
+
}
+
}
object BuildInformationSerializer {
def serialize(project: BuildInformation.Project): Node =
- <project name={project.name} root={project.root.toString} rootModule={project.rootModule.name}>
+ <project name={project.name} root={project.root.getPath} rootModule={project.rootModule.name}>
<modules>
{project.modules.map(serialize)}
</modules>
@@ -258,21 +312,21 @@ object BuildInformationSerializer {
</project>
private def serialize(module: BuildInformation.Module): Node =
- <module name={module.name} root={module.root.toString} target={module.target.toString} scalaVersion={module.scalaVersion}>
+ <module name={module.name} root={module.root.getPath} target={module.target.getPath} scalaVersion={module.scalaVersion} type={module.moduleType.name}>
<sourceDirs>
- {module.sourceDirs.map(d => <dir>{d}</dir>)}
+ {module.sourceDirs.map(d => <dir>{d.getPath: String}</dir>)}
</sourceDirs>
<scalacOptions>
- {module.scalacOptions.map(o => <option>{o}</option>)}
+ {module.scalacOptions.map(o => <option>{o: String}</option>)}
</scalacOptions>
<dependencies>
{module.binaryDependencies.map(serialize)}
{module.moduleDependencies.map(serialize)}
</dependencies>
<classpath>
- {module.classpath.map(c => <classpathItem>{c.toString}</classpathItem>)}
+ {module.classpath.map(c => <classpathItem>{c.getPath: String}</classpathItem>)}
</classpath>
- {module.parentBuild.map(p => <parentBuild>{p}</parentBuild>).getOrElse(NodeSeq.Empty)}
+ {module.parentBuild.map(p => <parentBuild>{p: String}</parentBuild>).getOrElse(NodeSeq.Empty)}
</module>
private def serialize(binaryDependency: BuildInformation.BinaryDependency): Node =
@@ -280,14 +334,36 @@ object BuildInformationSerializer {
private def serialize(library: BuildInformation.Library): Node =
<library name={library.name}>
- {library.jars.map(j => <jar type={j.jarType.toString}>{j.jar}</jar>)}
+ {library.jars.map(j => <jar type={j.jarType.name}>{j.jar.getPath: String}</jar>)}
</library>
+ private def serialize(moduleDependency: BuildInformation.ModuleDependency): Node =
+ <moduleDependency>
+ {moduleDependency.name: String}
+ </moduleDependency>
+
private def serialize(compiler: BuildInformation.ScalaCompiler): Node =
<compiler version={compiler.version}>
- {compiler.jars.map(j => <jar>{j}</jar>)}
+ {compiler.jars.map(j => <jar>{j.getPath: String}</jar>)}
</compiler>
+}
- private def serialize(moduleDependency: BuildInformation.ModuleDependency): Node =
- <moduleDependency>{moduleDependency.name}</moduleDependency>
+
+class ArgumentParser(arguments: Seq[String]) {
+ private val argumentsMap = (arguments :+ "")
+ .sliding(2)
+ .map(_.toList)
+ .foldLeft(Map.empty[String, Option[String]]) {
+ case (m, Seq(k: String, v: String)) if k.startsWith("--") && !v.startsWith("--") =>
+ m + (k.stripPrefix("--") -> Some(v))
+ case (m, (k: String) :: _) if k.startsWith("--") =>
+ m + (k.stripPrefix("--") -> None)
+ case (m, _) => m
+ }
+
+ def value(key: String): Option[String] =
+ argumentsMap.get(key.stripPrefix("--")).flatten
+
+ def persists(key: String): Boolean =
+ argumentsMap.isDefinedAt(key)
} \ No newline at end of file