scoptを使用してコマンドラインパラメータを解析する

9578 ワード

https://github.com/scopt/scopt
簡単なscalaコマンドラインオプション解析
scoptは小さなコマンドラインオプション解析ライブラリです.
Sonatype
libraryDependencies += "com.github.scopt" %% "scopt" % "X.Y.Z"

上のMaven Central badgeの表示
使用方法
scoptは、immutableとmutableの2つの解析方法を提供します.いずれの場合も、まず構成を表すcase classが必要です.
import java.io.File
case class Config(foo: Int = -1, out: File = new File("."), xyz: Boolean = false,
  libName: String = "", maxCount: Int = -1, verbose: Boolean = false, debug: Boolean = false,
  mode: String = "", files: Seq[File] = Seq(), keepalive: Boolean = false,
  jars: Seq[File] = Seq(), kwargs: Map[String,String] = Map())

可変の解析スタイルでは、config構成オブジェクトがパラメータとしてactionコールバックに渡されます.一方、可変解析スタイルでは、構成オブジェクトを変更する必要があります.
ふへんかいせき
次に、scopt.OptionParser[Config]を作成する方法の例を示します.各種ビルダー方法の詳細については、Scaladoc APIを参照してください.
val parser = new scopt.OptionParser[Config]("scopt") {
  head("scopt", "3.x")

  opt[Int]('f', "foo").action( (x, c) =>
    c.copy(foo = x) ).text("foo is an integer property")

  opt[File]('o', "out").required().valueName("").
    action( (x, c) => c.copy(out = x) ).
    text("out is a required file property")

  opt[(String, Int)]("max").action({
      case ((k, v), c) => c.copy(libName = k, maxCount = v) }).
    validate( x =>
      if (x._2 > 0) success
      else failure("Value  must be >0") ).
    keyValueName("", "").
    text("maximum count for ")

  opt[Seq[File]]('j', "jars").valueName(",...").action( (x,c) =>
    c.copy(jars = x) ).text("jars to include")

  opt[Map[String,String]]("kwargs").valueName("k1=v1,k2=v2...").action( (x, c) =>
    c.copy(kwargs = x) ).text("other arguments")

  opt[Unit]("verbose").action( (_, c) =>
    c.copy(verbose = true) ).text("verbose is a flag")

  opt[Unit]("debug").hidden().action( (_, c) =>
    c.copy(debug = true) ).text("this option is hidden in the usage text")

  help("help").text("prints this usage text")

  arg[File]("...").unbounded().optional().action( (x, c) =>
    c.copy(files = c.files :+ x) ).text("optional unbounded args")

  note("some notes.".newline)

  cmd("update").action( (_, c) => c.copy(mode = "update") ).
    text("update is a command.").
    children(
      opt[Unit]("not-keepalive").abbr("nk").action( (_, c) =>
        c.copy(keepalive = false) ).text("disable keepalive"),
      opt[Boolean]("xyz").action( (x, c) =>
        c.copy(xyz = x) ).text("xyz is a boolean property"),
      opt[Unit]("debug-update").hidden().action( (_, c) =>
        c.copy(debug = true) ).text("this option is hidden in the usage text"),
      checkConfig( c =>
        if (c.keepalive && c.xyz) failure("xyz cannot keep alive")
        else success )
    )
}

// parser.parse returns Option[C]
parser.parse(args, Config()) match {
  case Some(config) =>
    // do stuff

  case None =>
    // arguments are bad, error message will have been displayed
}

次の使用法テキストを生成します.
scopt 3.x
Usage: scopt [update] [options] [...]

  -f, --foo         foo is an integer property
  -o, --out          out is a required file property
  --max:=    maximum count for 
  -j, --jars ,...
                           jars to include
  --kwargs k1=v1,k2=v2...  other arguments
  --verbose                verbose is a flag
  --help                   prints this usage text
  ...                optional unbounded args
some notes.

Command: update [options]
update is a command.
  -nk, --not-keepalive     disable keepalive
  --xyz             xyz is a boolean property

Options(オプション)
コマンドラインオプションは、opt[A]('f', "foo")またはopt[A]("foo")を使用して定義され、Aは任意のタイプであり、Read typeclassのインスタンスである.
  • Unitを通常マーク--fooまたは-f
  • とする.
  • IntLongDoubleStringBigIntBigDecimaljava.io.Filejava.net.URIjava.net.InetAddressおよび--foo 80は、--foo:80またはBooleanのような値を受信する.
  • --foo true受信--foo:1またはjava.util.Calendarのような値
  • .
  • --foo 2018-07-16受信scala.concurrent.duration.Durationという値
  • .
  • --foo 30s受信(String, Int)という値
  • .
  • --foo:k=1のようなtypes対児受信-f k=1またはSeq[File]のようなキー値対児
  • .
  • --jars foo.jar,bar.jarは、Map[String, String]のようなカンマ分割文字列値
  • を受信する.
  • --kwargs key1=val1,key2=val2受信Readのようなカンマ分割pairs文字列値
  • これは、役割ドメインにおいてopt[Unit]のインスタンスを定義することによって拡張することができる.たとえば、
    object WeekDays extends Enumeration {
      type WeekDays = Value
      val Mon, Tue, Wed, Thur, Fri, Sat, Sun = Value
    }
    implicit val weekDaysRead: scopt.Read[WeekDays.Value] =
      scopt.Read.reads(WeekDays withName _)
    

    デフォルトでは、これらのオプションはオプションです.
    Short options
    一般的なマーク(-fb)に対して短いオプションは、--foo --barにグループ化されてoptを表すことができる.abbr("ab")は単一の文字のみを受信しますが、help("help")を使用し、文字列も使用できます.
    opt[Unit]("no-keepalive").abbr("nk").action( (x, c) => c.copy(keepalive = false) )
    

    Help, Version, and Notes
    事前定義actionには、version("version")help("help")という特殊なオプションがあり、それぞれ使用方法テキストとタイトルテキストを印刷します.showUsageOnErrorを定義すると、解析器は、usageテキスト全体を印刷するのではなく、失敗したときに短いエラーメッセージを印刷します.この動作は、次のように書き換えることによって変更できます.
    override def showUsageOnError = true
    
    note("...")は、所与の文字列をusageテキストに追加するために使用される.
    Arguments
    コマンドラインパラメータはarg[A]("")で定義.オプションと同様ですが、--または-を含まない値を受信します.デフォルトでは、パラメータは単一の値を受け入れ、必要です.
    arg[String]("...")
    

    Occurrence
    各opt/argは、出現情報minOccursおよびmaxOccursを有する.minOccursはopt/argが少なくとも出現しなければならない回数を指定し、maxOccursはopt/argが最も多く出現する可能性のある回数を指定する.
    opt/argのメソッドを使用して、出現回数を設定できます.
    opt[String]('o', "out").required()
    opt[String]('o', "out").required().withFallback(() => "default value")
    opt[String]('o', "out").minOccurs(1) // same as above
    arg[String]("").optional()
    arg[String]("").minOccurs(0) // same as above
    arg[String]("...").optional().unbounded()
    arg[String]("...").minOccurs(0).maxOccurs(1024) // same as above
    

    一例
    package allinone
    
    import com.typesafe.config.ConfigFactory
    import org.apache.spark.sql.SparkSession
    import scopt.OptionParser
    
    object SparkFilesArgs extends App  {
      case class Params(conf: String = "application.conf") //    application.conf       
      val parser = new OptionParser[Params]("SparkFilesArgs") {
    
        opt[String]('c', "conf")
          .text("config.resource for telematics")
          .action((x, c) => c.copy(conf = x))
    
        help("help").text("prints this usage text")
      }
    
      //        
      parser.parse(args, Params()) match {
        case Some(params) => println(params)
        case _ => sys.exit(1)
      }
    
      //       ,    
      val spark = SparkSession.builder()
        .appName(this.getClass.getName)
        .master("local[3]")
        .getOrCreate()
    
      spark.sparkContext.setLogLevel("WARN")
    
      val df  = spark.read.csv("/Users/ohmycloud/opt/apache-hive-1.2.2-bin/examples/files/csv.txt")
      df.show()
    
      ConfigFactory.invalidateCaches() //       
      lazy val config = ConfigFactory.load()
      println(config.origin())
      lazy val sparkConf = config.getConfig("spark")
      lazy val sparkMaster = sparkConf.getString("master")
      lazy val checkPath = sparkConf.getString("checkpoint.path")
      println(sparkMaster, checkPath)
      spark.stop()
    }
    

    送信方法
  • spark-submit直接提出
  • spark-submit --class allinone.SparkFilesArgs  --driver-memory 2g    --driver-cores 2    --executor-memory 2g    --executor-cores 2    --num-executors 2 --files /Users/ohmycloud/work/cihon/resources/application.pp.env.conf  target/allinone-1.0-SNAPSHOT-shaded.jar --conf hahaha
    

    印刷されます.
    Params(hahaha)
    

    この長いコマンドをshellに書くと(spark-submit.sh):
    spark-submit --class $1  --driver-memory 2g    --driver-cores 2    --executor-memory 2g    --executor-cores 2    --num-executors 2 --files /Users/ohmycloud/work/cihon/resources/application.pp.env.conf  target/allinone-1.0-SNAPSHOT-shaded.jar --conf $2
    

    では、呼び出し方法は次のとおりです.
    spark-submit.sh  allinone.SparkFilesArgs hahaha