Skip to content

Instantly share code, notes, and snippets.

@omnisis
Created January 26, 2015 06:08
Show Gist options
  • Save omnisis/1252de6ea9f054cd84ae to your computer and use it in GitHub Desktop.
Save omnisis/1252de6ea9f054cd84ae to your computer and use it in GitHub Desktop.
Example Scallop CommandHandler
package com.nextinstruction.scalacommands
object Commands extends App {
import org.rogach.scallop._
import org.rogach.scallop.exceptions._
class ToolConf(toolArgs: Seq[String]) extends ScallopConf(toolArgs) {
//version("\nv0.0.1 (c) Not Implemented Industries, LLC.")
banner("""
|usage: git [--version] [--help] [-C <path>] [-c name=value]
| [--exec-path=[<path>]] [--html-path] [--man-path] [--info-path]
| [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]
| [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
| <command> [<args>]
|""".stripMargin)
footer("\n'git help -a and 'git help -g' lists available subcommands.\n")
// git/hadoop-style where subcommands show only a short descr on the main help page
shortSubcommandsHelp(true)
// true options
val version = opt[Boolean](hidden=true)
val execPath = opt[String](hidden=true)
val htmlPath = opt[String](hidden=true)
val manPath = opt[String](hidden=true)
val Add = new Subcommand("add") {
descr("Add file contents to the index")
banner("\nusage: git add [OPTIONS] <pathspec>\n")
val dryRun = opt[Boolean](short='n',argName="--dry-run",
descr="Don't actually add the file(s), just show if they exist and/or will be ignored.\n")
val verbose = opt[Boolean](short='v',descr="Be verbose.")
val interactive = opt[Boolean](short='i',descr="Add modified contents in the working tree interactively " +
"to the index. Optional path arguments may be supplied to limit operation to a subset of the working " +
"""tree. See "Interactive Mode" for details."""+"\n")
val patch = opt[Boolean](
descr="Interactively choose hunks of patch between the index and the work tree and add them" +
"to the index. This gives the user a chance to review the difference before adding " +
"modified contents to the index.\n"
)
val edit = opt[Boolean]()
val force = opt[Boolean]()
val update = opt[Boolean]()
val intentToAdd = opt[Boolean]()
val pathSpec = trailArg[String](required=true,
name="<pathspec>",
descr="Files to add content from. Fileglobs (e.g. *.c) can be given...")
}
val Branch = new Subcommand("branch") {
descr("List, create, or delete branches")
val verbose = opt[Boolean]()
val quiet = opt[Boolean]()
val track = opt[Boolean]()
val upstream = opt[String]()
val unsetUpstream = opt[Boolean]()
val color = opt[String]()
val remotes = opt[List[String]]()
val contains = opt[String]()
val abbrev = opt[Int]()
}
val Checkout = new Subcommand("checkout") {
descr("Checkout a branch or delete paths to the working tree")
}
val Log = new Subcommand("log") {
descr("Show commit logs")
}
}
// Generic Tool Interface for stitching configs and command handlers ...
class Tool[C <: ScallopConf](conf: C) {
type Handler = (C) => Unit
var subcmdHandlers = Map[ScallopConf, Handler]()
var primaryHandler : Option[Handler] = None
def registerSubcmdHandler(subcmd: ScallopConf, handler: Handler) : Unit = {
subcmdHandlers += (subcmd -> handler)
}
def registerPrimaryHandler(handler: Handler) : Unit = {
primaryHandler = Some(handler)
}
def run() : Unit = {
conf.subcommand match {
case None =>
case Some(cmd) =>
println(s"You ran a subcmd: ${cmd}")
if(subcmdHandlers.keySet.contains(cmd)) {
subcmdHandlers(cmd).apply(conf)
} else {
println(s"No Handler registered for ${cmd.printedName}!")
}
}
}
}
// Example complex tool with nested configs and subcmd handlers
val toolConf = new ToolConf(args.toSeq)
val myTool = new Tool(toolConf)
myTool.registerSubcmdHandler(toolConf.Add, (c: ToolConf) => { println("running add command") })
myTool.registerSubcmdHandler(toolConf.Branch, (c: ToolConf) => { println("running branch command") })
myTool.run()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment