Pass options down to subcommands
In the git example you have
final case class Remote(verbose: Boolean) extends Subcommand
object Remote {
sealed trait RemoteSubcommand extends Subcommand
final case class Add(name: String, url: String) extends RemoteSubcommand
final case class Remove(name: String) extends RemoteSubcommand
}
which suggests that the intention is that the verbose arg is applied to all the subcommands. However there doesn't seem to be a way to actually do this.
sbt:root> examplesJVM / runMain zio.cli.examples.GitExample remote -v remove hello
[info] running zio.cli.examples.GitExample remote -v remove hello
Executing `git remote remove hello`
Is this actually the intention or am I misreading it? Is there a way to achieve this?
The hierarchy of commands doesn't describe very accurately the intended situation, so there is no way to do that with that example because the verbose flag is discarded in line 58 of the example. You can change this depending on your needs. For example, this catches the verbose flag.
object GitExample extends ZIOCliDefault {
import java.nio.file.Path
sealed trait Subcommand extends Product with Serializable
object Subcommand {
final case class Add(modified: Boolean, directory: JPath) extends Subcommand
final case class Remote(verbose: Boolean, subcommand: Option[Remote.RemoteSubcommand]) extends Subcommand
object Remote {
sealed trait RemoteSubcommand
// final case class Root(Version: Boolean) extends RemoteSubcommand
final case class Add(name: String, url: String) extends RemoteSubcommand
final case class Remove(name: String) extends RemoteSubcommand
}
}
val modifiedFlag: Options[Boolean] = Options.boolean("m")
val addHelp: HelpDoc = HelpDoc.p("Add subcommand description")
val add =
Command("add", modifiedFlag, Args.directory("directory")).withHelp(addHelp).map { case (modified, directory) =>
Subcommand.Add(modified, directory)
}
val verboseFlag: Options[Boolean] = Options.boolean("verbose").alias("v")
val configPath: Options[Path] = Options.directory("c", Exists.Yes)
val remoteAdd = {
val remoteAddHelp: HelpDoc = HelpDoc.p("Add remote subcommand description")
Command("add", Options.text("name") ++ Options.text("url")).withHelp(remoteAddHelp).map { case (name, url) =>
Subcommand.Remote.Add(name, url)
}
}
val remoteRemove = {
val remoteRemoveHelp: HelpDoc = HelpDoc.p("Remove remote subcommand description")
Command("remove", Args.text("name")).withHelp(remoteRemoveHelp).map(Subcommand.Remote.Remove)
}
val remoteHelp: HelpDoc = HelpDoc.p("Remote subcommand description")
val remote =
// val gitRemote = Command("remote", verboseFlag).withHelp(remoteHelp).map(Subcommand.Remote(_))
// val gitRemoteAdd = Command("remote").withHelp(remoteHelp).subcommands(remoteAdd)
// val gitRemoteRemove = Command("remote").withHelp(remoteHelp).subcommands(remoteRemove)
// gitRemote | gitRemoteAdd | gitRemoteRemove
Command("remote", verboseFlag)
.withHelp(remoteHelp)
.map(Subcommand.Remote(_, None))
.subcommands(remoteAdd, remoteRemove)
.map {
case (Subcommand.Remote(verbose, None), remoteSubcommand) => Subcommand.Remote(verbose, Some(remoteSubcommand))
}
val git: Command[Subcommand] =
Command("git", Options.none, Args.none).subcommands(add, remote)
val cliApp = CliApp.make(
name = "Git Version Control",
version = "0.9.2",
summary = text("a client for the git dvcs protocol"),
command = git
) {
case Subcommand.Add(modified, directory) =>
printLine(s"Executing `git add $directory` with modified flag set to $modified")
case Subcommand.Remote(false, Some(Subcommand.Remote.Add(name, url))) =>
printLine(s"Executing `git remote add $name $url`")
case Subcommand.Remote(false, Some(Subcommand.Remote.Remove(name))) =>
printLine(s"Executing `git remote remove $name`")
case Subcommand.Remote(true, _) =>
printLine(s"Executing `git remote` with verbose flag set to true")
}
}
Works great, thanks!
I don't think it's a good approach to use Option[A] then later fill in values. This seems like a repetitive for most CLIs.
There should be a function like subcommands that passes down the result of the command.
@hearnadam Are you referring to CliApp.run? The problem is that some commands like help do not return an A value. If not, would you mind expanding? Maybe it's better in a new issue if it's unrelated to this one.