diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a040c85 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +language: scala +sudo: false + +jdk: + - oraclejdk8 + +scala: + - 2.11.8 + +script: sbt ++$TRAVIS_SCALA_VERSION clean test + +cache: + directories: + - $HOME/.ivy2/cache + - $HOME/.sbt/boot/ + - $HOME/.zinc + +after_success: sbt ++$TRAVIS_SCALA_VERSION travis-report + +before_cache: + # Tricks to avoid unnecessary cache updates + - find $HOME/.ivy2 -name "ivydata-*.properties" -delete + - find $HOME/.sbt -name "*.lock" -delete diff --git a/build.sbt b/build.sbt index bc3c641..9b7950f 100644 --- a/build.sbt +++ b/build.sbt @@ -1,9 +1,9 @@ name := "args4s" -version := "1.1.0" +version := "1.2.0-SNAPSHOT" + deps += libs.value('args4j) +providedDeps += libs.value('hadoop) + // Scala 2.11 version seems to work fine for other Scala binary versions. noCrossPublishing - -// Omit default test deps -testDeps := Seq() diff --git a/project/plugins.sbt b/project/plugins.sbt index 218cd66..a228e91 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1 +1 @@ -addSbtPlugin("org.hammerlab" % "sbt-parent" % "1.5.2") +addSbtPlugin("org.hammerlab" % "sbt-parent" % "1.7.1") diff --git a/src/main/scala/org/hammerlab/args4s/Handler.scala b/src/main/scala/org/hammerlab/args4s/Handler.scala new file mode 100644 index 0000000..14f1b0a --- /dev/null +++ b/src/main/scala/org/hammerlab/args4s/Handler.scala @@ -0,0 +1,18 @@ +package org.hammerlab.args4s + +import org.kohsuke.args4j.{ CmdLineParser, OptionDef } +import org.kohsuke.args4j.spi.{ OptionHandler ⇒ Args4JOptionHandler, Parameters, Setter } + +class Handler[T](parser: CmdLineParser, + option: OptionDef, + setter: Setter[T], + defaultMetaVariable: String, + fn: String ⇒ T) + extends Args4JOptionHandler[T](parser, option, setter) { + override def getDefaultMetaVariable: String = defaultMetaVariable + + override def parseArguments(params: Parameters): Int = { + setter.addValue(fn(params.getParameter(0))) + 1 + } +} diff --git a/src/main/scala/org/hammerlab/args4s/IntOptionHandler.scala b/src/main/scala/org/hammerlab/args4s/IntOptionHandler.scala index 9c15f5d..6f6572c 100644 --- a/src/main/scala/org/hammerlab/args4s/IntOptionHandler.scala +++ b/src/main/scala/org/hammerlab/args4s/IntOptionHandler.scala @@ -1,18 +1,18 @@ package org.hammerlab.args4s -import org.kohsuke.args4j.{CmdLineParser, OptionDef} -import org.kohsuke.args4j.spi.{OptionHandler, Parameters, Setter} +import org.kohsuke.args4j.spi.Setter +import org.kohsuke.args4j.{ CmdLineParser, OptionDef } /** * Args4J option handler that populates an [[Option[Int]]]. */ -class IntOptionHandler(parser: CmdLineParser, option: OptionDef, setter: Setter[Option[Int]]) - extends OptionHandler[Option[Int]](parser, option, setter) { - - override def getDefaultMetaVariable: String = "path" - - override def parseArguments(params: Parameters): Int = { - setter.addValue(Some(params.getParameter(0).toInt)) - 1 - } -} +class IntOptionHandler(parser: CmdLineParser, + option: OptionDef, + setter: Setter[Option[Int]]) + extends OptionHandler[Int]( + parser, + option, + setter, + "INT", + _.toInt + ) diff --git a/src/main/scala/org/hammerlab/args4s/OptionHandler.scala b/src/main/scala/org/hammerlab/args4s/OptionHandler.scala new file mode 100644 index 0000000..a9c99b7 --- /dev/null +++ b/src/main/scala/org/hammerlab/args4s/OptionHandler.scala @@ -0,0 +1,17 @@ +package org.hammerlab.args4s + +import org.kohsuke.args4j.spi.Setter +import org.kohsuke.args4j.{ CmdLineParser, OptionDef } + +class OptionHandler[T](parser: CmdLineParser, + option: OptionDef, + setter: Setter[Option[T]], + defaultMetaVariable: String, + fn: String ⇒ T) + extends Handler[Option[T]]( + parser, + option, + setter, + defaultMetaVariable, + s ⇒ Some(fn(s)) + ) diff --git a/src/main/scala/org/hammerlab/args4s/PathHandler.scala b/src/main/scala/org/hammerlab/args4s/PathHandler.scala new file mode 100644 index 0000000..533131d --- /dev/null +++ b/src/main/scala/org/hammerlab/args4s/PathHandler.scala @@ -0,0 +1,16 @@ +package org.hammerlab.args4s + +import org.apache.hadoop.fs.Path +import org.kohsuke.args4j.spi.Setter +import org.kohsuke.args4j.{ CmdLineParser, OptionDef } + +class PathHandler(parser: CmdLineParser, + option: OptionDef, + setter: Setter[Path]) + extends Handler[Path]( + parser, + option, + setter, + "PATH", + new Path(_) + ) diff --git a/src/main/scala/org/hammerlab/args4s/PathOptionHandler.scala b/src/main/scala/org/hammerlab/args4s/PathOptionHandler.scala new file mode 100644 index 0000000..ec9c0c6 --- /dev/null +++ b/src/main/scala/org/hammerlab/args4s/PathOptionHandler.scala @@ -0,0 +1,16 @@ +package org.hammerlab.args4s + +import org.apache.hadoop.fs.Path +import org.kohsuke.args4j.spi.Setter +import org.kohsuke.args4j.{ CmdLineParser, OptionDef } + +class PathOptionHandler(parser: CmdLineParser, + option: OptionDef, + setter: Setter[Option[Path]]) + extends OptionHandler[Path]( + parser, + option, + setter, + "PATH", + new Path(_) + ) diff --git a/src/main/scala/org/hammerlab/args4s/StringOptionHandler.scala b/src/main/scala/org/hammerlab/args4s/StringOptionHandler.scala index 789562c..93cf8fb 100644 --- a/src/main/scala/org/hammerlab/args4s/StringOptionHandler.scala +++ b/src/main/scala/org/hammerlab/args4s/StringOptionHandler.scala @@ -1,21 +1,18 @@ package org.hammerlab.args4s -import org.kohsuke.args4j.spi.{OptionHandler, Parameters, Setter} -import org.kohsuke.args4j.{CmdLineParser, OptionDef, OptionHandlerRegistry} +import org.kohsuke.args4j.spi.Setter +import org.kohsuke.args4j.{ CmdLineParser, OptionDef } /** * Args4J option handler that populates an [[Option[String]]]. */ -class StringOptionHandler(parser: CmdLineParser, option: OptionDef, setter: Setter[Option[String]]) - extends OptionHandler[Option[String]](parser, option, setter) { - override def getDefaultMetaVariable: String = "path" - - override def parseArguments(params: Parameters): Int = { - setter.addValue(Some(params.getParameter(0))) - 1 - } -} - -object StringOptionHandler { - OptionHandlerRegistry.getRegistry.registerHandler(classOf[Option[String]], classOf[StringOptionHandler]) -} +class StringOptionHandler(parser: CmdLineParser, + option: OptionDef, + setter: Setter[Option[String]]) + extends OptionHandler[String]( + parser, + option, + setter, + "VAL", + s ⇒ s + ) diff --git a/src/main/scala/org/hammerlab/args4s/StringsOptionHandler.scala b/src/main/scala/org/hammerlab/args4s/StringsOptionHandler.scala new file mode 100644 index 0000000..6e37910 --- /dev/null +++ b/src/main/scala/org/hammerlab/args4s/StringsOptionHandler.scala @@ -0,0 +1,23 @@ +package org.hammerlab.args4s + +import org.kohsuke.args4j.{ CmdLineParser, OptionDef } +import org.kohsuke.args4j.spi.{ Parameters, Setter } +import org.kohsuke.args4j + +/** + * Handler for parsing a comma-delimited list of strings. + */ +class StringsOptionHandler(parser: CmdLineParser, + option: OptionDef, + setter: Setter[String]) + extends args4j.spi.OptionHandler[String]( + parser, + option, + setter + ) { + override def getDefaultMetaVariable: String = "STRING[]" + override def parseArguments(params: Parameters): Int = { + params.getParameter(0).split(",").foreach(setter.addValue) + 1 + } +} diff --git a/src/test/scala/org/hammerlab/args4s/ArgsTest.scala b/src/test/scala/org/hammerlab/args4s/ArgsTest.scala new file mode 100644 index 0000000..b7e6b04 --- /dev/null +++ b/src/test/scala/org/hammerlab/args4s/ArgsTest.scala @@ -0,0 +1,93 @@ +package org.hammerlab.args4s + +import java.io.ByteArrayOutputStream + +import org.apache.hadoop.fs.Path +import org.hammerlab.test.Suite +import org.kohsuke.args4j +import org.kohsuke.args4j.CmdLineParser + +import scala.collection.JavaConversions._ + +class Args { + @args4j.Option( + name = "--str", + handler = classOf[StringOptionHandler], + usage = "An optional string" + ) + var strOpt: Option[String] = None + + @args4j.Option( + name = "--int", + handler = classOf[IntOptionHandler], + usage = "An int" + ) + var intOpt: Option[String] = None + + @args4j.Option( + name = "--path", + handler = classOf[PathHandler], + usage = "A path" + ) + var path: Path = _ + + @args4j.Option( + name = "--path-opt", + handler = classOf[PathOptionHandler], + usage = "An optional path" + ) + var pathOpt: Option[Path] = None + + @args4j.Option( + name = "--strings", + handler = classOf[StringsOptionHandler], + usage = "Some strings" + ) + var strings: Array[String] = Array() + + @args4j.Argument( + metaVar = "", + multiValued = true, + handler = classOf[PathHandler], + usage = "Path arguments" + ) + var paths: Array[Path] = Array() +} + +class ArgsTest + extends Suite { + test("parse") { + val args = new Args + val parser = new CmdLineParser(args) + + val ss = new ByteArrayOutputStream + parser.printUsage(ss) + ss.toString("UTF-8") should be( + """ : Path arguments + | --int INT : An int (default: None) + | --path PATH : A path + | --path-opt PATH : An optional path (default: None) + | --str VAL : An optional string (default: None) + | --strings STRING[] : Some strings + |""" + .stripMargin('|') + ) + + parser.parseArgument( + Seq( + "--str", "abc", + "--path", "http://a/b/c", + "--path-opt", "dd/ee/ff", + "--strings", "aaa,bbb,ccc", + "gg/hh/ii", "ftp://jj/kk" + ) + ) + + args.strOpt should be(Some("abc")) + args.intOpt should be(None) + args.path should be(new Path("http://a/b/c")) + args.pathOpt should be(Some(new Path("dd/ee/ff"))) + args.strings should be(Array("aaa", "bbb", "ccc")) + args.paths should be(Array(new Path("gg/hh/ii"), new Path("ftp://jj/kk"))) + } +}