Skip to content

Instantly share code, notes, and snippets.

@jvican
Created June 26, 2019 18:04
Show Gist options
  • Save jvican/a178335b07e866f113373571f77fd47b to your computer and use it in GitHub Desktop.
Save jvican/a178335b07e866f113373571f77fd47b to your computer and use it in GitHub Desktop.

Revisions

  1. jvican created this gist Jun 26, 2019.
    83 changes: 83 additions & 0 deletions Cli.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,83 @@
    package sailgun.caseapp

    import _root_.caseapp.core.Parser
    import _root_.caseapp.core.Messages
    import _root_.caseapp.core.WithHelp

    import java.io.PrintStream
    import java.io.InputStream
    import sailgun.protocol.Defaults
    import sailgun.protocol.Streams
    import sailgun.logging.SailgunLogger
    import java.util.concurrent.atomic.AtomicBoolean
    import sailgun.TcpClient

    /**
    * An implementation of a CLI via case-app.
    *
    * Unfortunately, GraalVM Native Image doesn't correctly generate a native
    * image because of parsing errors and warnings generated by the use of macros
    * in case-app via Shapeless. For that reason, this class is left here but it's
    * not used by default, preferring a CLI implementation that requires no macros
    * and works with GraalVM Native Image.
    */
    abstract class Cli(in: InputStream, out: PrintStream, err: PrintStream) {
    private implicit val cliParamsParser: Parser[CliParams] = Parser.generic
    private implicit val messagesParams =
    Messages.messages[CliParams].copy(appName = "nailgun", progName = "nailgun")
    private implicit val messagesParamsHelp = messagesParams.withHelp

    def exit(code: Int): Unit
    def run(args: Array[String]): Unit = {
    def errorAndExit(msg: String): Unit = { err.println(msg); exit(1) }
    cliParamsParser.withHelp.detailedParse(args) match {
    case Left(a) => errorAndExit(a)
    case Right((WithHelp(usage, help, result), remainingArgs, extraArgs)) =>
    if (usage) out.println(messagesParams.usageMessage)
    if (help)
    out.println("Type `--nailgun-help` to print help of nailgun CLI.")
    result match {
    case Left(parserError) => errorAndExit(parserError)
    case Right(params) =>
    if (params.nailgunShowVersion)
    out.println(s"Nailgun v${Defaults.Version}")
    if (params.nailgunHelp) {
    out.println(messagesParams.helpMessage)
    exit(0)
    } else {
    remainingArgs.headOption match {
    case None => errorAndExit("Missing nailgun command to server!")
    case Some(cmd) =>
    // Reconstruct arguments to pass them to the server correctly
    val cmdArgs = {
    val remaining0 = remainingArgs.tail
    if (extraArgs.isEmpty) remaining0
    else remaining0 ++ List("--") ++ extraArgs
    }

    val streams = Streams(in, out, err)
    val client = TcpClient(params.nailgunServer, params.nailgunPort)
    val logger = new SailgunLogger("log", out, isVerbose = params.verbose)
    val code = client.run(
    cmd,
    cmdArgs.toArray,
    Defaults.cwd,
    Defaults.env,
    streams,
    logger,
    new AtomicBoolean(false)
    )

    logger.debug(s"Return code is $code")
    exit(code)
    }
    }
    }
    }
    }
    }

    object Cli extends Cli(System.in, System.out, System.err) {
    def main(args: Array[String]): Unit = run(args)
    override def exit(code: Int) = System.exit(code)
    }
    13 changes: 13 additions & 0 deletions CliParams.scala
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    package sailgun.caseapp

    import _root_.caseapp.{ExtraName, HelpMessage}
    import sailgun.protocol.Defaults

    final case class CliParams(
    nailgunServer: String = Defaults.Host,
    nailgunPort: Int = Defaults.Port,
    nailgunHelp: Boolean = false,
    verbose: Boolean = false,
    @ExtraName("--nailgun-showversion")
    nailgunShowVersion: Boolean = false
    )