Here you can find the different steps to create your first CLI in Java with the Picocli Framework. The main steps of the project are stored each in a separate git branch chronological named with numbers.
- all the resulted source code will be find in the branch
01-🎉-Init-Project
- init the Quarkus project:
quarkus create cli fr.wilda.picocli:jarvis:0.0.1-SNAPSHOT --no-wrapper
$ quarkus create cli fr.wilda.picocli:jarvis:0.0.1-SNAPSHOT
Looking for the newly published extensions in registry.quarkus.io
-----------
selected extensions:
- io.quarkus:quarkus-picocli
applying codestarts...
📚 java
🔨 maven
📦 quarkus
📝 config-properties
🔧 dockerfiles
🔧 maven-wrapper
🚀 picocli-codestart
-----------
[SUCCESS] ✅ quarkus project has been successfully generated in:
--> /Users/stef/xxx/jarvis
-----------
Navigate into this directory and get started: quarkus dev
- let's see what the command generated:
- a pom.xml with all necessary dependences
- take look to the dependecies section with a reference to the picocli extension
- an example class, GreetingCommand
- take a look to the annotations :
@Command(name = "greeting", mixinStandardHelpOptions = true)
: 'mixinStandardHelpOptions' adds the--help
and--version
options@Parameters(paramLabel = "<name>", defaultValue = "picocli", description = "Your name.")
: parameter to set to the CLI, if empty use thedefaultValue
value. The description parameter will be displayed when calling the--help
option
- take a look to the annotations :
- a set of Dockerfiles in src/main/docker
- an empty application.properties
- a pom.xml with all necessary dependences
- all the resulted source code will be find in the branch
02-📺-Try-the-CLI
- first use the Quarkus dev mode:
quarkus dev
:
$ quarkus dev
__ ____ __ _____ ___ __ ____ ______
--/ __ \/ / / / _ | / _ \/ //_/ / / / __/
-/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2023-10-29 18:46:11,317 INFO [io.quarkus] (Quarkus Main Thread) jarvis 0.0.1-SNAPSHOT on JVM (powered by Quarkus 3.5.0) started in 0.497s.
2023-10-29 18:46:11,319 INFO [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2023-10-29 18:46:11,319 INFO [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, picocli]
Hello picocli, go go commando!
2023-10-29 18:46:11,354 INFO [io.quarkus] (Quarkus Main Thread) jarvis stopped in 0.002s
--
Tests paused
Press [space] to restart, [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
- press
e
to test the CLI as you were in a terminal:
2023-10-29 18:46:11,354 INFO [io.quarkus] (Quarkus Main Thread) jarvis stopped in 0.002s
--
Tests paused
-h
Usage: greeting [-hV] <name>
<name> Your name.
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
2023-07-29 14:54:51,389 INFO [io.quarkus] (Quarkus Main Thread) discover-picocli stopped in 0.000s
--
Tests paused
Press [space] to restart, [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
--
Tests paused
Stéphane
2023-07-29 14:58:33,334 INFO [io.qua.dep.dev.RuntimeUpdatesProcessor] (Aesh InputStream Reader) Live reload total time: 0.097s
Hello Stéphane, go go commando!
2023-10-29 18:51:31,003 INFO [io.quarkus] (Quarkus Main Thread) jarvis stopped in 0.000s
--
Tests paused
Press [space] to restart, [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
- all the resulted source code will be find in the branch
03-🔗-ovhcloud-sdk
- add the rest client reactive client:
quarkus extension add rest-client-reactive-jackson
(see it in the dependencies section in the pom.xml) - add the
jarvis-sdk
dependency in the pom.xml:
<dependency>
<groupId>fr.wilda.jarvis.sdk</groupId>
<artifactId>jarvis-sdk</artifactId>
<version>1.0.0</version>
</dependency>
- create the API Service that is responsible to call the OVHcloud API: OVHcloudAPIService.java
- take a look to the Jakarta annotations:
@RegisterRestClient
: to use it as client to do API call, see application.properties for parameters@Path("/v1")
: root path for the called end-point@ClientHeaderParam(name = "X-Ovh-Consumer", value = "${ovhcloud.consumer}")
,@ClientHeaderParam(name = "X-Ovh-Application", value = "${ovhcloud.application}")
,@ClientHeaderParam(name = "Content-Type", value = "application/json")
: header parameters, see application.properties for dynamic parameters
- add the following dependency in the pom.xml:
<dependency>
<groupId>io.quarkiverse.langchain4j</groupId>
<artifactId>quarkus-langchain4j-mistral-ai</artifactId>
<version>0.10.3</version>
</dependency>
- create the service for calling OVHcloud Mistral AI Endpoint: AIEndpointMistral7bService
- update the application.properties:
quarkus.langchain4j.mistralai.api-key=foo
quarkus.langchain4j.mistralai.chat-model.max-tokens=150
quarkus.langchain4j.mistralai.chat-model.model-name=Mistral-7B-Instruct-v0.2
quarkus.langchain4j.mistralai.log-requests=true
quarkus.langchain4j.mistralai.log-responses=true
QUARKUS_LANGCHAIN4J_MISTRALAI_BASE_URL
with the API URL of Mistral model.
- all the resulted source code will be find in the branch
04-🤖-add-ovhcloud-feature
- create the main entry point for the CLI: JarvisCommand.java
- delete the
GreetingCommand.java
file - test your CLI with the developer mode:
quarkus dev
- all the resulted source code will be find in the branch
05-☁️-add-ovhcloud-command
- create the OVHcloud sub command to access to the REST API: OVHcloudSubCommand.java
- take a look to the annotations:
@Option(names = {"-m", "--me"}, description = "Display the OVHcloud account details.")
,@Option(names = {"-k", "--kube"}, description = "Display your Managed Kubernetes Service created.")
: create boolean options activated when setted@RestClient
: to use the API Service class OVHcloudAPIService@ConfigProperty(name = "ovhcloud.projectId")
: to get the value of the keyovhcloud.projectId
from application.properties file.
- take a look to the annotations:
- update the JarvisCommand.java with the
@TopCommand
annotation and the sub command listsubcommands = {OVHcloudSubCommand.class}
- test the new subcommand:
ovhcloud -m -k
- to use AI Endpoints:
- inject the service in JarvisCommand.java:
@Inject
AIEndpointMistral7bService aiEndpointMistral7bService;
- update the parameter name to become the question to ask:
// Question to ask
@Parameters(paramLabel = "<question>", defaultValue = "Can you explain what are you?", description = "The question to ask to Jarvis.")
private String question;
- update the
call
method:
@Override
public Integer call() throws Exception {
_LOG.info("{}", aiEndpointMistral7bService.askAQuestion(question));
return 0;
}
- all the resulted source code will be find in the branch
06-📦-package
- update the application.properties to have clean outputs:
%prod.quarkus.log.category."fr.wilda".level=INFO
&%prod.quarkus.log.console.format=%m
- launch the build Quarkus command:
quarkus build
- take a look that the application is available in target/quarkus-app folder, espacially the lib folder
- take a look to the generated application:
du -h --max-depth=1
- test the packaged CLI:
java -jar ./target/quarkus-app/quarkus-run.jar Stéphane
,java -jar ./target/quarkus-app/quarkus-run.jar ovhcloud -m -k
- create the jarvis.sh script
- in the src/main/script folder, test the CLI:
./jarvis.sh ovhcloud -m -k
- all the resulted source code will be find in the branch
07-🚀-graalvm
- if needed install GraalVM: https://www.graalvm.org/latest/docs/getting-started/
- set the
GRAALVM_HOME
environment variable:export GRAALVM_HOME=/Library/Java/JavaVirtualMachines/graalvm-jdk-17.0.8+9.1/Contents/Home
⚠️ if your/tmp
is mounted asnoexec
: change thejava.io.tmpdir
to a folder withexec
permission by adding the following property on your build command:-Dquarkus.native.additional-build-args=-Djava.io.tmpdir=$HOME/tmp
or use the experimental building feature:quarkus build --native -Dquarkus.native.container-build=true
⚠️ - build the binary with the command
quarkus build --native
- use the generated CLI:
./target/jarvis-0.0.1-SNAPSHOT-runner ovhcloud -m -k
or use the backuped one:jarvis_bck ovhcloud -m -k
- rename and move the generated CLI:
cp ./target/jarvis-0.0.1-SNAPSHOT-runner ~/bin/jarvis && mv ~/bin/jarvis-0.0.1-SNAPSHOT-runner jarvis
- use the CLI:
jarvis ovhcloud -m