Question

This is related to Groovy execute external RTC command with quotes in the command. The quotes I am putting around the list of components is being interpreted by the shell as being part of the command itself.

This is the command that should run (and does if run directly on the command line):

scm workspace add-components test-workspace -s test-stream "test1" "test 2" -r url

The issue seems to come from "test1" "test2"

This is passed into the command method as an ArrayList and then converted into a String:

void addComponents(String repository, String name, String flowTarget, ArrayList components) {
    String compStr = components.toString().replace("[", "'").replace("]", "'").replace(", ", "' '")
    println compStr
    String cmd = "scm workspace add-components ${name} -s ${flowTarget} ${compStr} -r ${repository}"
    println cmd

    def proc = ["scm", "workspace","add-components", "${name}","-s", "${flowTarget}","${compStr}","-r", "${repository}"].execute()

    //def proc = cmd.execute()
    proc.waitFor()

    getReturnMsg(proc)
}

I've tried both the straight string as well as putting the commands into an array and passing that to execute.

Unmatched component ""test1" "test 2""

From the error it looks like instead of looking for component test1 it is looking for "test1 test2" all together.

Based on this it seems like I need to separate out "test1" and "test 2" into separate elements in the array like this:

def proc = ["scm", "workspace", "add-components","Jenkins_${name}_${workspaceId}_Workspace","-s",flowTarget,"test1","test 2","-r",repository].execute()

And in fact if I hard code the components list into the command array like this it does work.

The problem is that the component list is variable in length depending on the project. Is there a way to construct a variable length command array like this? The list of components is coming from a JSON file with a structure like the following:

{
    "project": [
        {
            "name": "Project1",
            "components": [
                "component1",
                "component 2",
                "component 3"
            ]
        },
        {
            "name": "Project2",
            "components": [
                "component1",
                "component 4",
                "component 5",
                "component6"
            ]
        }
    ]
}
Was it helpful?

Solution 2

The solution to this is to add each component (stored in a separate list) to the command list individually instead of grouped together as one string:

def components = ["test1", "test 2"]

def cmd = ["scm", "workspace", "flowtarget", "test-workspace", "test-stream", "-r", url, "-C"]

for (component in components) {
    cmd.add(component)
}

def proc = cmd.execute()
proc.waitFor()

OTHER TIPS

Groovy's String#execute() and Java's Runtime#exec(String) use a simple new java.util.StringTokenizer() to split arguments. There is no shell involved, and so the rules for splitting are different (and more primitive). It's safer to pass a list/array, in which case the splitting is explicit, and the arguments will be passed as-is to the process. This means that you'll need to make sure that the arguments don't contain any characters (such as quotes) that aren't supposed to be passed to the process.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top