A slim framework to make Scala CLI apps in ZIO.
This project is still in (very) early development, but feel free to give it a try - I'd love to hear any feedback you have. I had been publishing early artifacts to CloudSmith, but I'll be updating to Maven Central soon.
This project was steering towards a focus on Scala Native, however I think I painted myself into a corner with that. Now, this project is going to focus on just the JVM, and Scala 3. It's also going to be very scala-cli focused.
Here is a general overview if of the pieces fit together.
You only need to make an object that extends the UrsulaApp
trait, and provide
a Seq[Command]
, which are your actions you wish to be available in your
app. UrsulaApp
extends ZIOAppDefault
, and wires up everything needed for the
run
method automatically! It parses the arguments passed, and uses that to
pull out the Command
provided, and runs accordingly, passing on the arguments
to it.
There are some built in commands provided, such as the
HelpCommand
and ConfigCommand
, that are also automatically injected. This
means that even if you only have:
object App extends UrsulaApp {
override val commands: Seq[Command] = Seq.empty
}
you already have a functioning cli app that has a help
command that prints all
the available commands accepted (as little as they are so far), as well as a
config
command that will let a user set/get/delete values from the apps config
file (defaulted to $home/.ursula/config.json
)
At this point, you need only implement some Command
s that wrap the
functionality you desire, and add them to the commands: Seq
.
There is a trait Command
to extend, and the essence of this the
implementation of
def action(args: Chunk[String]): ZIO[UrsulaServices, Throwable, ?]
You consolidate all of your ZIO logic you want to run in this method that will
pass in arguments that are Chunk[String]
and returns a
ZIO[UrsulaServices, Throwable, ?]
. Note that the return value is ?
- the
actual result is discarded to .unit
, as Commands
are meant to be a
one-off calls from the main entry point, and generally not composed with
other Command
s.
UrsulaServices
are a collection of built in ZIO services that are available
for you to use (or not at all, if you don't want to!). UrsulaServices
are
bundled in via the UrsulaApp
, so you don't need to provide them with your
logic - you just need to provide all of the other resources to run your won
logic (i.e. you can .provideSome[UrsulaServices](...yourDepsHere))
and not
have to worry about it.
There are a few other items to implement, such as
val trigger: String
val description: String
val usage: String
val examples: Seq[String]
trigger
is the String that should be used at the start of your CLI arguments
to call that particular command. The others are simple informational strings
about your command - and those are automatically used by the built-in help
command to print documentation!
Two other important things to declare are
val flags: Seq[Flag[?]]
val arguments: Seq[Argument[?]]
Flags and Arguments are discussed below, but know that
they are simple traits to extend that help you parse/provide values for the
args
passed in - and they too have some simple Strings to implement that
provide auto documentation for your app. At the end of the day, you can just
parse the args
on your own in your ZIO logic - but usage of the Flag
s
andArguments
should hopefully simplify things for your and your apps users.
- HelpCommand - handles the printing of documentation
- ConfigCommand - manipulates a simple JSON config file
Flags (trait Flag[R]
) are non-positional arguments passed to the command.
Flags can be generally used as either an argument flag, which expects the next
element in the command arguments to be parsed as type R
, or boolean flags
which do not (i.e. present/not present).
The source code is fairly well documented at this point. Some general highlights are that it has things built in to
- parse argument(s) that can then be used in you
Command
- declare conflicts with other flags
- declare requirements of other flags
- provide defaults, of ENV variables to be used
Arguments (trait Argument[R]
) are positional arguments passed to the
command, and are to be parsed to type R
The source code is fairly well documented at this point. Some general highlights are that you can encode the parsing logic.
UrsulaServices
is the sum of all services that are automatically provided in
the R
channel of your commands action
zio. See below for more info on each.
This service allows you to get/set/delete keys from the apps config file. Behind
the scenes, the UrsulaApp
will automatically read the config file at start,
and load it into an in memory Map
. This Map
is what backs this service, and
if the state becomes dirty (i.e. a set
or delete
is used), then after your
Command
logic has run, it will persist the Map
back to disk.
As mentioned above, I'll be moving artifacts to maven central soon, so check back for soon artifacts/versions.
It's always good to have options 😉.
There is an official zio-cli project out there, and I encourage you to check that out too! I feel maybe one large difference is just how apps are structured/built, driven mostly by my motivations outlined above. A lot of my inspiration for this project comes from oclif: Node.JS Open CLI Framework .