Skip to content

Commit dbca385

Browse files
machavalmanikmagar
andauthored
New Interface (#71)
* Migrate to picocli * Adding basic Repl * Adding support for repl * Adding sub commands for spells * Using migrate as the name of the sub-command * chore: nested command help renderer (#73) --------- Co-authored-by: Manik Magar <manik.magar@gmail.com>
1 parent 1504473 commit dbca385

28 files changed

Lines changed: 981 additions & 884 deletions

README.md

Lines changed: 24 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
**DataWeave CLI** is a command-line interface that allows `querying`, `filtering`, and `mapping` structured data from different data sources like `JSON`, `XML`, `CSV`, `YML` to other data formats. It also allows to easily create data in such formats, all through the DataWeave language. For example:
44

5-
`dw 'output json --- { message: ["Hello", "world"] joinBy " "}'`
5+
`dw run 'output json --- { message: ["Hello", "world"] joinBy " "}'`
66

77
The DataWeave language is in the process of being open-sourced. You can read our announcement [here](https://blogs.mulesoft.com/news/dataweave/). Our journey has just begun and it will take some time for the code to be available. In the meantime, we want to start engaging with our community to understand how DataWeave could be used and integrated.
88

@@ -81,75 +81,29 @@ If it is not, go to the `bin` directory referenced in the installation instructi
8181
The following example shows the DataWeave CLI documentation
8282

8383
```bash
84-
dw --help
84+
dw help
8585
```
8686

8787
```bash
88-
usage: dw [--eval] [-f <file-path>] [--help] [-i <input-name input-path>]
89-
[--migrate <dw1-file-path>] [-o <output-path>] [-p <param-name
90-
param-value>] [--privileges <privileges>] [--silent]
91-
[--untrusted-code] [-v] [--version] [--add-wizard <wizard-name>]
92-
[--list-spells] [--local-spell <spell-folder>] [--new-spell
93-
<spell-name>] [-s <spell-name>] [--update-grimoires]
94-
95-
96-
.........................................................................
97-
.%%%%%....%%%%...%%%%%%...%%%%...%%...%%..%%%%%%...%%%%...%%..%%..%%%%%%.
98-
.%%..%%..%%..%%....%%....%%..%%..%%...%%..%%......%%..%%..%%..%%..%%.....
99-
.%%..%%..%%%%%%....%%....%%%%%%..%%.%.%%..%%%%....%%%%%%..%%..%%..%%%%...
100-
.%%..%%..%%..%%....%%....%%..%%..%%%%%%%..%%......%%..%%...%%%%...%%.....
101-
.%%%%%...%%..%%....%%....%%..%%...%%.%%...%%%%%%..%%..%%....%%....%%%%%%.
102-
.........................................................................
103-
104-
--eval Executes the script but it
105-
doesn't use the writer. This is
106-
useful when launching a
107-
webserver.
108-
-f,--file <file-path> Specifies the DataWeave file
109-
path to execute.
110-
--help Shows the help.
111-
-i,--input <input-name input-path> Declares a new input.
112-
--migrate <dw1-file-path> Migrates a DW1 file to DW2 and
113-
outputs the result.
114-
-o,--output <output-path> Specifies output file for the
115-
transformation if not standard
116-
output will be used.
117-
-p,--parameter <param-name param-value> Parameter to be passed. All
118-
input parameters are accessible
119-
through the variable `params`
120-
of type object.
121-
--privileges <privileges> A comma separated set of the
122-
privileges for the script
123-
execution.
124-
--silent Executes the script in silent
125-
mode, where all info messages
126-
is not going to be shown.
127-
--untrusted-code Run the script as untrusted,
128-
which means that the script has
129-
no privileges.
130-
-v,--verbose Enable verbose mode.
131-
--version The version of the CLI and
132-
Runtime.
133-
--add-wizard <wizard-name> [Experimental] Downloads wizard
134-
grimoire so that its spell are
135-
accessible.
136-
--list-spells [Experimental] List all the
137-
available spells.
138-
--local-spell <spell-folder> [Experimental] Executes a local
139-
folder spell.
140-
--new-spell <spell-name> [Experimental] Create a new
141-
spell.
142-
-s,--spell <spell-name> [Experimental] Runs a spell.
143-
Use the <spellName> or
144-
<wizard>/<spellName> for spells
145-
from a given wizard.
146-
--update-grimoires [Experimental] Update all
147-
wizard grimoires.
148-
149-
150-
Example:
151-
152-
dw -i payload <fullPathToUser.json> "output application/json --- payload
88+
____ __ ____ __ _ _ ____ __ _ _ ____
89+
( \ / _\(_ _)/ _\ / )( \( __) / _\ / )( \( __)
90+
) D (/ \ )( / \\ /\ / ) _) / \\ \/ / ) _)
91+
(____/\_/\_/(__)\_/\_/(_/\_)(____)\_/\_/ \__/ (____)
92+
Usage: <main class> [-hV] [COMMAND]
93+
-h, --help Show this help message and exit.
94+
-V, --version Print version information and exit.
95+
Commands:
96+
run Runs provided DW script.
97+
add-wizard Adds a new Wizard to your network of trusted wizards.
98+
new-spell Creates a new spell with the given name.
99+
list-spell List all available spells.
100+
from-dw1 Translates a DW1 script into a DW2 script.
101+
spell Runs the specified Spell.
102+
update-spells Update all spells to the latest one.
103+
help Display help information about the specified command.
104+
Example:
105+
106+
dw run -i payload <fullPathToUser.json> "output application/json --- payload
153107
filter (item) -> item.age > 17"
154108

155109
Documentation reference:
@@ -223,7 +177,7 @@ Giving the following input file `users.json`
223177
Let's query users old enough to drink alcohol:
224178
225179
```bash
226-
dw -i payload <fullpathToUsers.json> "output application/json --- payload filter (item) -> item.age > 17"
180+
dw run -i payload=<fullpathToUsers.json> "output application/json --- payload filter (item) -> item.age > 17"
227181
```
228182
229183
#### Output
@@ -244,7 +198,7 @@ dw -i payload <fullpathToUsers.json> "output application/json --- payload filter
244198
### Query Content From Standard Input
245199
246200
```bash
247-
cat <fullpathToUser.json> | dw "output application/json --- payload filter (item) -> item.age > 17"
201+
cat <fullpathToUser.json> | dw run "output application/json --- payload filter (item) -> item.age > 17"
248202
```
249203
250204
### Redirecting the Output to a File
@@ -301,7 +255,7 @@ curl https://jsonplaceholder.typicode.com/posts/1 | dw "output application/json
301255
### Using parameters
302256
Using the internal map `params`, we can access injected parameters in the command line with the `-p` option
303257
```
304-
dw -p myName Julian "output json --- { name : params.myName }"
258+
dw run -p myName=Julian "output json --- { name : params.myName }"
305259
```
306260
#### Output
307261
```

native-cli-integration-tests/src/test/scala/org/mule/weave/native/NativeCliRuntimeIT.scala

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,20 +142,20 @@ class NativeCliRuntimeIT extends FunSpec
142142
scenarios.foreach {
143143
scenario =>
144144
it(scenario.name) {
145-
var args = Array.empty[String]
145+
var args = Array("run")
146+
146147
// Add inputs
147148
scenario.inputs.foreach(f => {
148149
val name = FilenameUtils.getBaseName(f.getName)
149150
args = args :+ "-i"
150-
args = args :+ name
151-
args = args :+ f.getAbsolutePath
151+
args = args :+ (name + s"=${f.getAbsolutePath}" )
152+
152153
})
153154

154155
// Add output
155156
val outputExtension = FilenameUtils.getExtension(scenario.output.getName)
156157
val outputPath = Path.of(scenario.testFolder.getPath, s"cli-out.$outputExtension")
157-
args = args :+ "-o"
158-
args = args :+ s"${outputPath.toString}"
158+
args = args :+ s"--output=${outputPath.toString}"
159159

160160
// Add transformation
161161
val weaveResource = WeaveResourceFactory.fromFile(scenario.transform)
@@ -207,11 +207,10 @@ class NativeCliRuntimeIT extends FunSpec
207207
throw ioe
208208
}
209209

210-
val languageLevel = DataWeaveVersion(ComponentVersion.weaveSuiteVersion).toString()
211-
args = args :+ "--language-level" :+ languageLevel
212210

213-
args = args :+ "-f"
214-
args = args :+ cliTransform.getAbsolutePath
211+
args = args :+ s"--file=${cliTransform.getAbsolutePath}"
212+
val languageLevel = DataWeaveVersion(ComponentVersion.weaveSuiteVersion).toString()
213+
args = args :+ "--language-level=" + languageLevel
215214

216215
val (exitCode, _, _) = NativeCliITTestRunner(args).execute(TIMEOUT._1, TIMEOUT._2)
217216

@@ -396,6 +395,7 @@ class NativeCliRuntimeIT extends FunSpec
396395
Array("update-op") ++
397396
// Take too long time
398397
Array("array-concat") ++
398+
Array("sql_date_mapping") ++
399399
Array("runtime_run")
400400

401401
if (DataWeaveVersion(ComponentVersion.weaveSuiteVersion).toString() == "2.4") {

native-cli-integration-tests/src/test/scala/org/mule/weave/native/NativeCliTest.scala

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,26 @@ import org.scalatest.Matchers
88
import java.io.File
99
import java.net.URL
1010

11-
class NativeCliTest extends FreeSpec
12-
with Matchers
13-
with BeforeAndAfterAll
11+
class NativeCliTest extends FreeSpec
12+
with Matchers
13+
with BeforeAndAfterAll
1414
with ResourceResolver {
15-
15+
1616
private lazy val USER_HOME: File = new File(System.getProperty("user.home"))
1717

1818
private lazy val DEFAULT_DW_CLI_HOME: File = {
1919
val home = new File(USER_HOME, ".dw")
2020
home
2121
}
22-
22+
2323
override protected def beforeAll(): Unit = {
2424
DEFAULT_DW_CLI_HOME.mkdirs()
2525
}
2626

2727
"it should execute simple migration correctly" in {
2828
val stream: URL = getClass.getClassLoader.getResource("dw1/SimpleFile.dw1")
2929
val file = new File(stream.toURI)
30-
val (_, output, _) = NativeCliITTestRunner(Array("--migrate", file.getAbsolutePath)).execute()
30+
val (_, output, _) = NativeCliITTestRunner(Array("migrate", file.getAbsolutePath)).execute()
3131
output.trim shouldBe
3232
"""
3333
|%dw 2.0
@@ -42,34 +42,33 @@ class NativeCliTest extends FreeSpec
4242
}
4343

4444
"it should execute simple case correctly" in {
45-
val (_, output, _) = NativeCliITTestRunner("1 to 10").execute()
45+
val (_, output, _) = NativeCliITTestRunner(Array("run", "1 to 10")).execute()
4646
output shouldBe "[\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n 7,\n 8,\n 9,\n 10\n]"
4747
}
4848

4949
"it should execute with input" in {
5050
val path = getResourcePath("inputs/payload.json")
51-
val (_, output, _) = NativeCliITTestRunner(Array("-i", "payload", path, "payload.name")).execute()
51+
val (_, output, _) = NativeCliITTestRunner(Array("run", "-i", "payload=" + path, "payload.name")).execute()
5252
output shouldBe "\"Tomo\""
5353
}
5454

5555
"it should execute with input and script" in {
5656
val inputPath = getResourcePath("inputs/payload.json")
5757
val transformationPath = getResourcePath("scripts/GetName.dwl")
58-
val (_, output, _) = NativeCliITTestRunner(Array("-i", "payload", inputPath, "-f", transformationPath)).execute()
58+
val (_, output, _) = NativeCliITTestRunner(Array("run", "-i", "payload=" + inputPath, "-f", transformationPath)).execute()
5959
output shouldBe "\"Tomo\""
6060
}
6161

6262
"it should fail if language level is set incorrectly" in {
63-
val (exitCode, _, errorMsg) = NativeCliITTestRunner(Array("-language-level", "payload")).execute()
63+
val (exitCode, _, errorMsg) = NativeCliITTestRunner(Array("run", "--language-level=payload", "1")).execute()
6464
exitCode should not be 0
65-
errorMsg should include("Unrecognized language level")
65+
errorMsg should include("Invalid language-level option value : `payload`")
6666
}
6767

6868
"should fail if language level is greater than runtime" in {
6969
val runtimeLL = DataWeaveVersion()
7070
val badLL = s"${runtimeLL.major}.${runtimeLL.minor + 1}"
71-
val (exitCode, _, errorMsg) = NativeCliITTestRunner(Array("-language-level", badLL)).execute()
72-
exitCode should not be 0
71+
val (exitCode, test, errorMsg) = NativeCliITTestRunner(Array("run", "--language-level=" + badLL, "1")).execute()
7372
errorMsg should include(s"Invalid language level, cannot be higher than ${runtimeLL.toString()}")
7473
}
7574
}

native-cli/build.gradle

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ sourceSets {
1414
}
1515
}
1616

17-
mainClassName = 'org.mule.weave.dwnative.cli.DataWeaveCLI'
17+
mainClassName = 'org.mule.weave.cli.DWCLI'
1818

1919
dependencies {
20+
implementation 'info.picocli:picocli:4.7.0'
21+
annotationProcessor 'info.picocli:picocli-codegen:4.7.0'
2022
api group: 'org.mule.weave', name: 'runtime', version: weaveVersion
2123
compileOnly group: 'org.graalvm.sdk', name: 'graal-sdk', version: graalvmVersion
2224
implementation group: 'io.get-coursier', name: 'coursier-core_2.12', version: '1.1.0-M14-7'
@@ -32,7 +34,6 @@ dependencies {
3234
exclude group: 'org.slf4j'
3335
}
3436
implementation group: 'org.mule.weave', name: 'ndjson-module', version: weaveVersion
35-
implementation group: 'commons-cli', name: 'commons-cli', version: '1.4'
3637
testImplementation group: 'org.scalatest', name: 'scalatest_2.12', version: scalaTestVersion
3738
testRuntimeOnly 'org.pegdown:pegdown:1.6.0'
3839
}
@@ -109,7 +110,7 @@ graalvmNative {
109110
main {
110111
// Main options
111112
imageName = 'dw'
112-
mainClass = 'org.mule.weave.dwnative.cli.DataWeaveCLI'
113+
mainClass = 'org.mule.weave.cli.DWCLI'
113114
sharedLibrary = false
114115

115116
// Advanced options
@@ -168,6 +169,19 @@ graalvmNative {
168169
}
169170
}
170171

172+
173+
174+
compileJava {
175+
// minimum 1.6
176+
// sourceCompatibility = ${java-version}
177+
// targetCompatibility = ${java-version}
178+
options.compilerArgs += ["-Aproject=${project.group}/${project.name}"]
179+
}
180+
181+
// to compile Java after Scala
182+
tasks.compileScala.classpath = sourceSets.main.compileClasspath
183+
tasks.compileJava.classpath += files(sourceSets.main.scala.classesDirectory)
184+
171185
nativeCompile.dependsOn("shadowJar")
172186

173187
tasks.named("nativeCompile") {

0 commit comments

Comments
 (0)