diff --git a/.codeclimate.yml b/.codeclimate.yml index 30e6503..5c04020 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -1,3 +1,9 @@ +--- engines: scalastyle: enabled: true + config: + config: src/main/resources/scalastyle_project.xml +exclude_paths: +- "**/src/test/" +- "**/target/" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..30eed9a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +target +.idea + diff --git a/Dockerfile b/Dockerfile index 7d52cc5..3b70212 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,19 @@ -FROM java +FROM openjdk:alpine -RUN apt-get update -RUN apt-get install -y ruby ruby-nokogiri +LABEL maintainer "Ivan Luzyanin " +LABEL maintainer "Jeff Sippel " -RUN adduser --uid 9000 --disabled-password --quiet --gecos "" app -USER app +RUN apk update && apk upgrade -WORKDIR /home/app +RUN addgroup -g 9000 -S code && \ + adduser -S -G code app +USER app -COPY scalastyle_config.xml /home/app/ -COPY scalastyle_2.11-0.6.0-batch.jar /home/app/ +COPY codeclimate-scalastyle-assembly-0.1.0.jar /usr/src/app/engine-core.jar +COPY src/main/resources/docker /usr/src/app +COPY src/main/resources/docker/engine.json / -COPY . /home/app +WORKDIR /code +VOLUME /code -CMD ["/home/app/bin/scalastyle"] +CMD ["/usr/src/app/bin/scalastyle"] diff --git a/README.md b/README.md index 58c0425..f83558a 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,15 @@ `scalastyle` is a configurable style linter for Scala code. +### Building +1. Install [sbt](http://www.scala-sbt.org/) +2. Run `sbt docker` + + +### Building release docker image +1. Run `sbt assembly && cp target/scala-2.12/codeclimate-scalastyle-assembly-.jar ./`. + This will create assembled jar with all dependencies. +2. Run `docker build -t codeclimate/codeclimate-scalastyle .` ### Installation diff --git a/bin/scalastyle b/bin/scalastyle deleted file mode 100755 index 79ad95b..0000000 --- a/bin/scalastyle +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env ruby -$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), "../lib"))) - -require 'cc/engine/scalastyle' - -if File.exists?("/config.json") - engine_config = JSON.parse(File.read("/config.json")) -else - engine_config = "{}" -end - -CC::Engine::ScalaStyle.new( - directory: "/code", engine_config: engine_config, io: STDOUT -).run diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..b1299e1 --- /dev/null +++ b/build.sbt @@ -0,0 +1,78 @@ +name := "codeclimate-scalastyle" +organization in ThisBuild := "codeclimate" +version in ThisBuild := "0.1.0" +scalaVersion in ThisBuild := "2.12.4" + +concurrentRestrictions in Global += Tags.limit(Tags.Test, 1) +parallelExecution in Global := false + +lazy val `engine-core` = project settings ( + libraryDependencies ++= Seq( + "org.scalastyle" %% "scalastyle" % "1.0.0", + "io.circe" %% "circe-parser" % "0.8.0", + "io.circe" %% "circe-generic" % "0.8.0", + "com.github.scopt" %% "scopt" % "3.7.0", + "org.scalactic" %% "scalactic" % "3.0.4", + "org.scalatest" %% "scalatest" % "3.0.4" % "test" + ) +) + +lazy val `codeclimate-scalastyle` = project in file(".") dependsOn `engine-core` + +resolvers in ThisBuild ++= Seq( + Resolver.sonatypeRepo("snapshots"), + Resolver.sonatypeRepo("releases") +) + +enablePlugins(sbtdocker.DockerPlugin) + +imageNames in docker := Seq( + // Sets the latest tag + ImageName(s"codeclimate/${name.value}:latest"), + + // Sets a name with a tag that contains the project version + ImageName( + namespace = Some("codeclimate"), + repository = name.value, + tag = Some(version.value) + ) +) + +dockerfile in docker := { + val dockerFiles = { + val resources = (unmanagedResources in Runtime).value + val dockerFilesDir = resources.find(_.getPath.endsWith("/docker")).get + resources.filter(_.getPath.contains("/docker/")).map { r => + (dockerFilesDir.toURI.relativize(r.toURI).getPath, r) + }.toMap + } + + new Dockerfile { + from("openjdk:alpine") + + // add all dependencies to docker image instead of assembly (layers the dependencies instead of huge assembly) + val dependencies = { + ((dependencyClasspath in Runtime) in `engine-core`).value + }.map(_.data).toSet + ((packageBin in Compile) in `engine-core`).value + + maintainer("Jeff Sippel", "jsippel@acorns.com") + maintainer("Ivan Luzyanin", "ivan@acorns.com") + + add(dependencies.toSeq, "/usr/src/app/dependencies/") + add(((packageBin in Compile) in `engine-core`).value, "/usr/src/app/engine-core.jar") + add(dockerFiles("scalastyle_config.xml"), "/usr/src/app/") + add(dockerFiles("engine.json"), "/") + add(dockerFiles("bin/scalastyle"), "/usr/src/app/bin/") + + runRaw("apk update && apk upgrade") + + runRaw("addgroup -g 9000 -S code && adduser -S -G code app") + + user("app") + + workDir("/code") + volume("/code") + + cmd("/usr/src/app/bin/scalastyle") + } +} \ No newline at end of file diff --git a/codeclimate-scalastyle-assembly-0.1.0.jar b/codeclimate-scalastyle-assembly-0.1.0.jar new file mode 100644 index 0000000..5b5b2ab Binary files /dev/null and b/codeclimate-scalastyle-assembly-0.1.0.jar differ diff --git a/engine-core/src/main/scala/org/codeclimate/scalastyle/CodeClimateEngine.scala b/engine-core/src/main/scala/org/codeclimate/scalastyle/CodeClimateEngine.scala new file mode 100644 index 0000000..d721f96 --- /dev/null +++ b/engine-core/src/main/scala/org/codeclimate/scalastyle/CodeClimateEngine.scala @@ -0,0 +1,48 @@ +package org.codeclimate.scalastyle + +import java.io.File +import java.nio.charset.Charset +import java.nio.file.Files + +import io.circe.parser.parse +import org.scalastyle._ + +import scala.collection.JavaConverters._ +import scala.util.Try + +object CodeClimateEngine extends App { + case class ProgramArgs(config_file_path: String, workspace_path: String) + + val argsParser = new scopt.OptionParser[ProgramArgs]("scopt") { + opt[String]("config_file_path").action { case (path, conf) => + conf.copy(config_file_path = path) + } + + opt[String]("workspace_path").action { case (path, conf) => + conf.copy(workspace_path = path) + } + } + + val defaultStyleConfigurationPath = "/usr/src/app/scalastyle_config.xml" + + argsParser.parse(args, ProgramArgs("/config.json", "/code")) match { + case Some(programArgs) => + val configFile = new File(programArgs.config_file_path) + val configJson = Try { + Files.readAllLines(configFile.toPath, Charset.defaultCharset()).asScala.toSeq.mkString("\n") + }.toEither + + val providedConfig = configJson.right.flatMap(parse).right + .map(config => config.hcursor) + + val includePaths = providedConfig.right.flatMap(_.downField("include_paths").as[Seq[String]]).toOption.getOrElse(Seq.empty) + val configPath = providedConfig.right.flatMap(_.downField("config").downField("config").as[String]).toOption.getOrElse(defaultStyleConfigurationPath) + + val config = ScalastyleCodeClimateConfiguration(configPath, includePaths, Seq.empty) + + val ccPrinter = new CodeClimateIssuePrinter(programArgs.workspace_path, Console.out) + + ScalaStyleRunner.runCheckstyle(programArgs.workspace_path, config) foreach ccPrinter.printIssue + case None => // it will print the error + } +} diff --git a/engine-core/src/main/scala/org/codeclimate/scalastyle/CodeClimateIssuePrinter.scala b/engine-core/src/main/scala/org/codeclimate/scalastyle/CodeClimateIssuePrinter.scala new file mode 100644 index 0000000..2468b21 --- /dev/null +++ b/engine-core/src/main/scala/org/codeclimate/scalastyle/CodeClimateIssuePrinter.scala @@ -0,0 +1,44 @@ +package org.codeclimate.scalastyle + +import java.io.{File, PrintStream} + +import com.typesafe.config.ConfigFactory +import io.circe.Printer +import io.circe.generic.auto._ +import io.circe.syntax._ +import org.scalastyle.{FileSpec, Message, MessageHelper, StyleError} + +import scala.collection.JavaConverters._ + +class CodeClimateIssuePrinter(workspacePath: String, ps: PrintStream) { + private val basePath = new File(workspacePath).toPath + private val printer = Printer.noSpaces.copy(dropNullKeys = true) + + private val messageHelper = new MessageHelper(ConfigFactory.load()) + + def printIssue[T <: FileSpec](msg: Message[T]): Unit = msg match { + case se: StyleError[FileSpec] => + val errPosition = Position(se.lineNumber.getOrElse(0), se.column.getOrElse(0)) + val filePath = Option(se.fileSpec.name) + .map(pathname => basePath.relativize(new File(pathname).toPath)) + .map(_.toString) + .getOrElse(se.fileSpec.name) + + val location = Location(path = filePath, positions = LinePosition( + errPosition, errPosition + )) + val msg: String = se.customMessage.orElse { + Some(messageHelper.message(se.key, se.args)) + }.getOrElse("Error message not provided") + val issue = Issue(location = location, + description = String.format(msg, se.args.asJava), + check_name = Some(se.clazz.getName), + categories = Seq("Style"), + severity = Some("major") + ) + val jsonStr = printer.pretty(issue.asJson) + ps.print(jsonStr) + ps.print("\0") + case _ => // ignore + } +} diff --git a/engine-core/src/main/scala/org/codeclimate/scalastyle/ScalaStyleRunner.scala b/engine-core/src/main/scala/org/codeclimate/scalastyle/ScalaStyleRunner.scala new file mode 100644 index 0000000..81a8934 --- /dev/null +++ b/engine-core/src/main/scala/org/codeclimate/scalastyle/ScalaStyleRunner.scala @@ -0,0 +1,22 @@ +package org.codeclimate.scalastyle + +import java.io.File + +import org.scalastyle._ + +/** + * Computes files and run ScalastyleChecker against them. + */ +private object ScalaStyleRunner { + def runCheckstyle(workspacePath: String, ccConfig: ScalastyleCodeClimateConfiguration): Seq[Message[FileSpec]] = { + val paths = if (ccConfig.include_paths.isEmpty) { + Seq(workspacePath) + } else { + ccConfig.include_paths.map(include => s"$workspacePath/$include") + } + val files = Directory.getFiles(None, paths.map(new File(_)), excludedFiles = ccConfig.exclude_paths) + + val scalastyleConfig = ScalastyleConfiguration.readFromXml(ccConfig.config) + new ScalastyleChecker(None).checkFiles(scalastyleConfig, files) + } +} diff --git a/engine-core/src/main/scala/org/codeclimate/scalastyle/package.scala b/engine-core/src/main/scala/org/codeclimate/scalastyle/package.scala new file mode 100644 index 0000000..468ebcc --- /dev/null +++ b/engine-core/src/main/scala/org/codeclimate/scalastyle/package.scala @@ -0,0 +1,20 @@ +package org.codeclimate + +package object scalastyle { + private[this] val DEFAULT_REMEDIAION_POINTS = 50000 + + case class ScalastyleCodeClimateConfiguration( + config: String, + include_paths: Seq[String] = Seq.empty, + exclude_paths: Seq[String] = Seq.empty + ) + + sealed trait IssueSchema extends Product with Serializable + case class Position(line: Int, column: Int) extends IssueSchema + case class LinePosition(begin: Position, end: Position) extends IssueSchema + case class Location(path: String, positions: LinePosition) extends IssueSchema + case class Issue(location: Location, description: String, check_name: Option[String] = None, + severity: Option[String] = None, remediation_points: Option[Int] = Some(DEFAULT_REMEDIAION_POINTS), + fingerprint: Option[String] = None, `type`: String = "issue", categories: Seq[String] = Seq.empty + ) extends IssueSchema +} diff --git a/engine-core/src/test/resources/apackage/TestFile.scala b/engine-core/src/test/resources/apackage/TestFile.scala new file mode 100644 index 0000000..55b6f29 --- /dev/null +++ b/engine-core/src/test/resources/apackage/TestFile.scala @@ -0,0 +1,12 @@ +package apackage + +class TestFile { + val MyVariable = "" + + def foobar(s: String) = { + var a = 1 + lazy var b = a + a = 2 + b + } +} \ No newline at end of file diff --git a/engine-core/src/test/resources/apackage/TestFileToIgnore.scala b/engine-core/src/test/resources/apackage/TestFileToIgnore.scala new file mode 100644 index 0000000..2d42fbf --- /dev/null +++ b/engine-core/src/test/resources/apackage/TestFileToIgnore.scala @@ -0,0 +1,5 @@ +package apackage + +class TestFileToIgnore { + val pi = Some(3.14) +} // it should at least report missing new line \ No newline at end of file diff --git a/scalastyle_config.xml b/engine-core/src/test/resources/scalastyle_config.xml similarity index 87% rename from scalastyle_config.xml rename to engine-core/src/test/resources/scalastyle_config.xml index eb3c2a7..05adab1 100755 --- a/scalastyle_config.xml +++ b/engine-core/src/test/resources/scalastyle_config.xml @@ -1,30 +1,11 @@ Scalastyle standard configuration - - + + - - - - - @@ -139,4 +120,4 @@ - \ No newline at end of file + diff --git a/engine-core/src/test/scala/org/codeclimate/scalastyle/CodeClimateRunnerTest.scala b/engine-core/src/test/scala/org/codeclimate/scalastyle/CodeClimateRunnerTest.scala new file mode 100644 index 0000000..ed2ab45 --- /dev/null +++ b/engine-core/src/test/scala/org/codeclimate/scalastyle/CodeClimateRunnerTest.scala @@ -0,0 +1,41 @@ +package org.codeclimate.scalastyle + +import org.scalastyle.StyleError +import org.scalatest.Matchers + +class CodeClimateRunnerTest extends org.scalatest.FreeSpec with Matchers { + val workspacePath = "engine-core" + + val codeClimateConfiguration = ScalastyleCodeClimateConfiguration( + config = "engine-core/src/test/resources/scalastyle_config.xml", + include_paths = Seq("src/test/resources") + ) + + "CodeClimateEngine" - { + "should call sclacheck and produce style errors for both files in apackage" in { + val msgs = ScalaStyleRunner.runCheckstyle(workspacePath, codeClimateConfiguration) + + msgs should not be empty + + val styleErrors = msgs.flatMap { + case se: StyleError[_] => Seq(se) + case _ => Seq.empty + } + + styleErrors should have size 3 // pre-computed number of issues + } + + "should ignore files specified in `exclude_paths`" in { + val msgs = ScalaStyleRunner.runCheckstyle(workspacePath, codeClimateConfiguration.copy( + exclude_paths = Seq("TestFileToIgnore")) + ) + + val files = msgs.flatMap { + case se: StyleError[_] => Seq(se.fileSpec.name) + case _ => Seq.empty + } + + files filter(_.contains("TestFileToIgnore")) shouldBe empty + } + } +} diff --git a/lib/cc/engine/scalastyle.rb b/lib/cc/engine/scalastyle.rb deleted file mode 100644 index 5ac84d2..0000000 --- a/lib/cc/engine/scalastyle.rb +++ /dev/null @@ -1,86 +0,0 @@ -require 'nokogiri' -require 'json' - -module CC - module Engine - class ScalaStyle - def initialize(directory: , io: , engine_config: ) - @directory = directory - @engine_config = engine_config - @io = io - end - - def run - exec_scalastyle_with_options - - Dir.chdir(@directory) do - next unless results - results.xpath('//file').each do |file| - path = file['name'].sub("/home/app/", "") - file.xpath('//error').each do |lint| - issue = { - type: "issue", - check_name: lint["source"], - description: lint["message"], - categories: ["Style"], - remediation_points: 50_000, - location: { - path: path, - positions: { - begin: { - line: lint["line"].to_i, - column: lint["column"].to_i - }, - end: { - line: lint["line"].to_i, - column: lint["column"].to_i - } - } - } - } - - puts("#{issue.to_json}\0") - end - end - end - end - - private - - def project_files - Dir.glob("**/*scala") - end - - def analysis_files - exclusions = @engine_config['exclude_paths'] || [] - project_files.reject { |f| exclusions.include?(f) }.join(" ") - end - - def scalastyle_jar - '/home/app/scalastyle_2.11-0.6.0-batch.jar' - end - - def scalastyle_config - @engine_config['config'] || '/home/app/scalastyle_config.xml' - end - - def results_xml_file_path - "/home/app/results.xml" - end - - def exec_scalastyle_with_options - `java -jar #{scalastyle_jar} \ - -c #{scalastyle_config} \ - --xmlOutput #{results_xml_file_path} \ - #{analysis_files}` - end - - def results - if File.exists?(results_xml_file_path) - @results ||= Nokogiri::XML(File.read(results_xml_file_path)) - end - end - - end - end -end diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..c091b86 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=0.13.16 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..60b5ba9 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1,4 @@ +logLevel := Level.Warn + +addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.5.0") +addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.3") diff --git a/scalastyle_2.11-0.6.0-batch.jar b/scalastyle_2.11-0.6.0-batch.jar deleted file mode 100755 index 30086de..0000000 Binary files a/scalastyle_2.11-0.6.0-batch.jar and /dev/null differ diff --git a/src/main/resources/docker/bin/scalastyle b/src/main/resources/docker/bin/scalastyle new file mode 100755 index 0000000..1f0221b --- /dev/null +++ b/src/main/resources/docker/bin/scalastyle @@ -0,0 +1,3 @@ +#!/bin/sh + +exec java -cp ".:/usr/src/app/engine-core.jar:/usr/src/app/dependencies/*" org.codeclimate.scalastyle.CodeClimateEngine "$@" diff --git a/src/main/resources/docker/engine.json b/src/main/resources/docker/engine.json new file mode 100644 index 0000000..b775edf --- /dev/null +++ b/src/main/resources/docker/engine.json @@ -0,0 +1,11 @@ +{ + "name": "scalastyle", + "description": "Run scalastyle checks", + "maintainer": { + "name": "Jeff Sippel", + "email": "jsippel@acorns.com" + }, + "languages" : ["Scala"], + "version": "0.1.0", + "spec_version": "0.3.1" +} diff --git a/src/main/resources/docker/scalastyle_config.xml b/src/main/resources/docker/scalastyle_config.xml new file mode 100755 index 0000000..05adab1 --- /dev/null +++ b/src/main/resources/docker/scalastyle_config.xml @@ -0,0 +1,123 @@ + + Scalastyle standard configuration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/scalastyle_project.xml b/src/main/resources/scalastyle_project.xml new file mode 100755 index 0000000..29d865f --- /dev/null +++ b/src/main/resources/scalastyle_project.xml @@ -0,0 +1,123 @@ + + Scalastyle standard configuration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/KafkaProject.scala b/test/KafkaProject.scala deleted file mode 100644 index cd406c1..0000000 --- a/test/KafkaProject.scala +++ /dev/null @@ -1,251 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import sbt._ -import scala.xml.{Node, Elem} -import scala.xml.transform.{RewriteRule, RuleTransformer} - -class KafkaProject(info: ProjectInfo) extends ParentProject(info) with IdeaProject { - override def managedStyle = ManagedStyle.Maven - val publishTo = "Maven Repo" at "http://maven/content/repositories/repository.snapshots" - Credentials(Path.userHome / ".m2" / ".credentials", log) - - lazy val core = project("core", "core-kafka", new CoreKafkaProject(_)) - lazy val examples = project("examples", "java-examples", new KafkaExamplesProject(_), core) - lazy val contrib = project("contrib", "contrib", new ContribProject(_)) - lazy val perf = project("perf", "perf", new KafkaPerfProject(_)) - - lazy val releaseZipTask = core.packageDistTask - - val releaseZipDescription = "Compiles every sub project, runs unit tests, creates a deployable release zip file with dependencies, config, and scripts." - lazy val releaseZip = releaseZipTask dependsOn(core.corePackageAction, core.test, examples.examplesPackageAction, - contrib.producerPackageAction, contrib.consumerPackageAction) describedAs releaseZipDescription - - val runRatDescription = "Runs Apache rat on Kafka" - lazy val runRatTask = task { - Runtime.getRuntime().exec("bin/run-rat.sh") - None - } describedAs runRatDescription - - val rat = "org.apache.rat" % "apache-rat" % "0.8" - - class CoreKafkaProject(info: ProjectInfo) extends DefaultProject(info) - with IdeaProject with CoreDependencies with TestDependencies with CompressionDependencies { - val corePackageAction = packageAllAction - - //The issue is going from log4j 1.2.14 to 1.2.15, the developers added some features which required - // some dependencies on various sun and javax packages. - override def ivyXML = - - - - - - - - - - - - - override def organization = "org.apache" - override def filterScalaJars = false - - // build the executable jar's classpath. - // (why is it necessary to explicitly remove the target/{classes,resources} paths? hm.) - def dependentJars = { - val jars = - publicClasspath +++ mainDependencies.scalaJars --- mainCompilePath --- mainResourcesOutputPath - if (jars.get.find { jar => jar.name.startsWith("scala-library-") }.isDefined) { - // workaround bug in sbt: if the compiler is explicitly included, don't include 2 versions - // of the library. - jars --- jars.filter { jar => - jar.absolutePath.contains("/boot/") && jar.name == "scala-library.jar" - } - } else { - jars - } - } - - def dependentJarNames = dependentJars.getFiles.map(_.getName).filter(_.endsWith(".jar")) - override def manifestClassPath = Some(dependentJarNames.map { "libs/" + _ }.mkString(" ")) - - def distName = (artifactID + "-" + projectVersion.value) - def distPath = "dist" / distName ## - - def configPath = "config" ## - def configOutputPath = distPath / "config" - - def binPath = "bin" ## - def binOutputPath = distPath / "bin" - - def distZipName = { - "%s-%s.zip".format(artifactID, projectVersion.value) - } - - lazy val packageDistTask = task { - distPath.asFile.mkdirs() - (distPath / "libs").asFile.mkdirs() - binOutputPath.asFile.mkdirs() - configOutputPath.asFile.mkdirs() - - FileUtilities.copyFlat(List(jarPath), distPath, log).left.toOption orElse - FileUtilities.copyFlat(dependentJars.get, distPath / "libs", log).left.toOption orElse - FileUtilities.copy((configPath ***).get, configOutputPath, log).left.toOption orElse - FileUtilities.copy((binPath ***).get, binOutputPath, log).left.toOption orElse - FileUtilities.zip((("dist" / distName) ##).get, "dist" / distZipName, true, log) - None - } - - val PackageDistDescription = "Creates a deployable zip file with dependencies, config, and scripts." - lazy val packageDist = packageDistTask dependsOn(`package`, `test`) describedAs PackageDistDescription - - val cleanDist = cleanTask("dist" ##) describedAs("Erase any packaged distributions.") - override def cleanAction = super.cleanAction dependsOn(cleanDist) - - override def javaCompileOptions = super.javaCompileOptions ++ - List(JavaCompileOption("-source"), JavaCompileOption("1.5")) - - override def packageAction = super.packageAction dependsOn (testCompileAction, packageTestAction) - - } - - class KafkaPerfProject(info: ProjectInfo) extends DefaultProject(info) - with IdeaProject - with CoreDependencies { - val perfPackageAction = packageAllAction - val dependsOnCore = core - - //The issue is going from log4j 1.2.14 to 1.2.15, the developers added some features which required - // some dependencies on various sun and javax packages. - override def ivyXML = - - - - - - - - - override def artifactID = "kafka-perf" - override def filterScalaJars = false - override def javaCompileOptions = super.javaCompileOptions ++ - List(JavaCompileOption("-Xlint:unchecked")) - } - - class KafkaExamplesProject(info: ProjectInfo) extends DefaultProject(info) - with IdeaProject - with CoreDependencies { - val examplesPackageAction = packageAllAction - val dependsOnCore = core - //The issue is going from log4j 1.2.14 to 1.2.15, the developers added some features which required - // some dependencies on various sun and javax packages. - override def ivyXML = - - - - - - - - - override def artifactID = "kafka-java-examples" - override def filterScalaJars = false - override def javaCompileOptions = super.javaCompileOptions ++ - List(JavaCompileOption("-Xlint:unchecked")) - } - - class ContribProject(info: ProjectInfo) extends ParentProject(info) with IdeaProject { - lazy val hadoopProducer = project("hadoop-producer", "hadoop producer", - new HadoopProducerProject(_), core) - lazy val hadoopConsumer = project("hadoop-consumer", "hadoop consumer", - new HadoopConsumerProject(_), core) - - val producerPackageAction = hadoopProducer.producerPackageAction - val consumerPackageAction = hadoopConsumer.consumerPackageAction - - class HadoopProducerProject(info: ProjectInfo) extends DefaultProject(info) - with IdeaProject - with CoreDependencies with HadoopDependencies { - val producerPackageAction = packageAllAction - override def ivyXML = - - - - - - - - - - - - - - - - } - - class HadoopConsumerProject(info: ProjectInfo) extends DefaultProject(info) - with IdeaProject - with CoreDependencies { - val consumerPackageAction = packageAllAction - override def ivyXML = - - - - - - - - - - - - - - - - - val jodaTime = "joda-time" % "joda-time" % "1.6" - } - } - - trait TestDependencies { - val easymock = "org.easymock" % "easymock" % "3.0" % "test" - val junit = "junit" % "junit" % "4.1" % "test" - val scalaTest = "org.scalatest" % "scalatest" % "1.2" % "test" - } - - trait CoreDependencies { - val log4j = "log4j" % "log4j" % "1.2.15" - val jopt = "net.sf.jopt-simple" % "jopt-simple" % "3.2" - val slf4jSimple = "org.slf4j" % "slf4j-simple" % "1.6.4" - } - - trait HadoopDependencies { - val avro = "org.apache.avro" % "avro" % "1.4.0" - val commonsLogging = "commons-logging" % "commons-logging" % "1.0.4" - val jacksonCore = "org.codehaus.jackson" % "jackson-core-asl" % "1.5.5" - val jacksonMapper = "org.codehaus.jackson" % "jackson-mapper-asl" % "1.5.5" - val hadoop = "org.apache.hadoop" % "hadoop-core" % "0.20.2" - } - - trait CompressionDependencies { - val snappy = "org.xerial.snappy" % "snappy-java" % "1.0.4.1" - } -}