Complex Objects Passed Via Task Runners throw Stringification Error

Description

When attempting to pass a complex object to params using the `command` function an attempt is made to parse each param as a string. When invoking via task runner, these may be complex objects, such as the case of passing mappings for `docbox generate`.

The following:


command( 'docbox generate' )
.params(
"source" = "models",
"mapping" = "models",
"mappings" = {
"/cbelasticsearch" : "#variables.projectBuildDir#/test-harness/modules/cbelasticsearch",
"/logstash" : "#variables.projectBuildDir#"
},
"strategy-projectTitle" = "#arguments.projectName# v#arguments.version#",
"strategy-outputDir" = arguments.outputDir
)
.run();

Produces the error:

Generating API Docs, please wait...
ERROR (5.1.1+00191)
Can't cast Complex Object Type Struct to String
Use Built-In-Function "serialize(Struct):String" to create a String from Struct
/system/util/Parser.cfc: line 265
263: */
264: string function escapeArg( argValue ) {
265: arguments.argValue = replace( arguments.argValue, '\', "
", "all" );
266: arguments.argValue = replace( arguments.argValue, '"', '\"', 'all' );
267: arguments.argValue = replace( arguments.argValue, "'", "\'", "all" );
called from /system/util/CommandDSL.cfc: line 119
called from /system/util/CommandDSL.cfc: line 188
called from /system/util/CommandDSL.cfc: line 236
called from /home/travis/build/coldbox-modules/logstash/build/Build.cfc: line 195
called from /home/travis/build/coldbox-modules/logstash/build/Build.cfc: line 75
called from /system/modules_app/task-commands/models/TaskService.cfc: line 80
called from /system/modules_app/task-commands/commands/task/run.cfc: line 68
called from /system/services/CommandService.cfc: line 347
called from /system/services/CommandService.cfc: line 158
called from /system/Shell.cfc: line 768
called from /system/Bootstrap.cfm: line 119

I'm attempting to find a workaround and will comment when I find one.

Activity

Show:
Jon Clausen
7 days ago

Update: Passing the mappings value in as the string, as documented in the Generator component does not work because the argument is strong typed on the function.

Brad Wood
7 days ago
Edited

CommandBox is a CLI and command parameters can only be strings. The issue is you’re trying to pass the parameters wrong. When passing mappings, it looks like this (from the command help):

Note there are two params-- one for each mapping. Each called:

  • mappings:v1.models

  • mappings:v2.models

CommandBox turns those params into a struct on the back-end. So the proper version of your command would be something along the lines of:

Jon Clausen
7 days ago

Great. That gives me a workaround. I do think it would be handy if params could be passed in as complex objects - to match the method signature of the function, rather than having to figure out the correct shorthand. Even the CLI help for that method lists mappings as “(A struct provided by the dynamic parameters facility of CommandBox that defines one or more mappings.)” I tried to see if I could get it to work with CommandService, but it threw additional errors down the line, when I added a simple value test and tried to pass it through directly.

Jon Clausen
7 days ago

Actually, the above does not work if you pass in more that one mappings: param as the the second one overwrites the first. When I remove the /logstash mapping, the /cbelasticsearch mapping exists, but it is overwritten if both are there.

Brad Wood
7 days ago

Passing the mappings value in as the string, as documented in the Generator component does not work because the argument is strong typed on the function.

The documentation on the behind-the-scenes Dockbox CFCs is mostly irrelevant here. The docbox command is a CLI command which operates as a black box, wrapping the docbox libraries. The inputs to the command follow the protocols of a CLI, not a component.

Great. That gives me a workaround.

To be clear, it is not a workaround. It is the correct and documented method of calling the docbox generate CLI command with mappings.

I do think it would be handy if params could be passed in as complex objects - to match the method signature of the function, rather than having to figure out the correct shorthand.

Like I explained above, CLI command params can only accept strings. When you use the Command DSL to run the docbox generate command, you are not directly calling the docbox CFCs. You are executing a CLI command. The Command DSL in your task runner is nothing more than a convenience wrapper that builds up a command string just like you would type in your terminal. That command string is passed into the parsing logic in CommandBox for processing just as though you had typed it. There cannot be a struct there. Now, perhaps as an enhancement request, the Command DSL could be re-imagined to skip the parsing entirely, but that would be a rewrite and a breaking change for several reasons.

rather than having to figure out the correct shorthand.

CommandBox’s dynamic parameters are documented here:

https://commandbox.ortusbooks.com/developing-for-commandbox/commands/using-parameters/dynamic-parameters

and the command help has an example of what it looks like. I’m unclear where the confusion is.

Actually, the above does not work if you pass in more that one mappings: param as the the second one overwrites the first.

No, it works just fine. I don’t know what you’re current sample code looks like since you didn’t share it, but I just double checked and I have no issue with it. When I run this CLI command:

The generate command correctly receives the following struct:

And when I create a test task runner with the following code:

Running that task (which is the exact Command DSL I provided in my first reply) correctly results in this mappings struct

If you’re having issues, I’d recommend we close this ticket and take this up in Slack so I can see what you’ve got going on .

Assignee

Unassigned

Reporter

Jon Clausen

Labels

None

Affects versions

Fix versions

None

Priority

Major
Configure