From 3df15ef7c9c5a48516c06cf7b598acf298d8b8c0 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 14 Jun 2017 17:34:08 +0300 Subject: Export build information (#511) * ExportBuildInformation plugin * Add targetLibraries * Add ExportBuildInformation to the BaseBuild trait * Add target, library jars * fixing mixed tabs and spaces * fixing indentation --- examples/export-build-information/Main.scala | 6 + .../export-build-information/build/build.scala | 3 + .../build/build/build.scala | 9 ++ stage2/BasicBuild.scala | 2 +- stage2/plugins/ExportBuildInformation.scala | 170 +++++++++++++++++++++ 5 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 examples/export-build-information/Main.scala create mode 100644 examples/export-build-information/build/build.scala create mode 100644 examples/export-build-information/build/build/build.scala create mode 100644 stage2/plugins/ExportBuildInformation.scala diff --git a/examples/export-build-information/Main.scala b/examples/export-build-information/Main.scala new file mode 100644 index 0000000..586aa1d --- /dev/null +++ b/examples/export-build-information/Main.scala @@ -0,0 +1,6 @@ +package export_build_information +object Main{ + def main( args: Array[String] ): Unit = { + println( Console.GREEN ++ "Hello World" ++ Console.RESET ) + } +} diff --git a/examples/export-build-information/build/build.scala b/examples/export-build-information/build/build.scala new file mode 100644 index 0000000..23b3f2d --- /dev/null +++ b/examples/export-build-information/build/build.scala @@ -0,0 +1,3 @@ +import cbt._ + +class Build(val context: Context) extends BaseBuild diff --git a/examples/export-build-information/build/build/build.scala b/examples/export-build-information/build/build/build.scala new file mode 100644 index 0000000..c7d5d82 --- /dev/null +++ b/examples/export-build-information/build/build/build.scala @@ -0,0 +1,9 @@ +import cbt._ + +class Build(val context: Context) extends BuildBuild { + override def dependencies = + super.dependencies ++ + Resolver(mavenCentral, sonatypeReleases).bind( + ScalaDependency( "org.scala-lang.modules", "scala-xml", "1.0.6" ) + ) +} diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 05e3c41..0bdbad7 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -5,7 +5,7 @@ import java.net._ import java.nio.file._ class BasicBuild(final val context: Context) extends BaseBuild -trait BaseBuild extends BuildInterface with DependencyImplementation with SbtDependencyDsl{ +trait BaseBuild extends BuildInterface with DependencyImplementation with SbtDependencyDsl with ExportBuildInformation{ override def equals(other: Any) = { other match { case b: BaseBuild => projectDirectory === b.projectDirectory diff --git a/stage2/plugins/ExportBuildInformation.scala b/stage2/plugins/ExportBuildInformation.scala new file mode 100644 index 0000000..0d33d75 --- /dev/null +++ b/stage2/plugins/ExportBuildInformation.scala @@ -0,0 +1,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.root.toString} + {project.rootModule.name} + + {project.modules.map(serialize)} + + + {project.libraries.map(serialize)} + + + + private def serialize(module: BuildInformation.Module): Node = + + {module.name} + {module.root} + {module.target} + + {module.sources.map(s => {s})} + + + {module.mavenDependencies.map(serialize)} + + + {module.moduleDependencies.map(serialize)} + + + {module.classpaths.map(serialize)} + + {module.parentBuild.map(p => {p}).getOrElse(NodeSeq.Empty)} + + + private def serialize(mavenDependency: BuildInformation.MavenDependency): Node = + {mavenDependency.name} + + private def serialize(library: BuildInformation.Library): Node = + + {library.name} + + {library.jars.map(j => {j})} + + + + private def serialize(moduleDependency: BuildInformation.ModuleDependency): Node = + {moduleDependency.name} + + private def serialize(targetLibrary: BuildInformation.ClassPathItem): Node = + {targetLibrary.path.toString} +} -- cgit v1.2.3