An error equivalent for process.text? - groovy

You can get the entire output stream by using .text:
def process = "ls -l".execute()
println "Found text ${process.text}"
Is there a concise equivalent to get the error stream?

You can use waitForProcessOutput which takes two Appendables (docs here)
def process = "ls -l".execute()
def (output, error) = new StringWriter().with { o -> // For the output
new StringWriter().with { e -> // For the error stream
process.waitForProcessOutput( o, e )
[ o, e ]*.toString() // Return them both
}
}
// And print them out...
println "OUT: $output"
println "ERR: $error"

Based on tim_yates answer, I tried it on Jenkins and found this issue with multiple assignment: https://issues.jenkins-ci.org/browse/JENKINS-45575
So this works and it is also concise:
def process = "ls -l".execute()
def output = new StringWriter(), error = new StringWriter()
process.waitForProcessOutput(output, error)
println "exit value=${process.exitValue()}"
println "OUT: $output"
println "ERR: $error"

Related

storing standard output into list groovy

I cannot manage to store the standard output from a shell command into a list using the following code. It seems to store each character as a list element instead of the entire string produced on each line.
def implementedBranchName = []
def getImplementedBranches() {
def cmd = "/usr/bin/tool search status Pending"
Process process = cmd.execute()
def output= process .in.text;
implementedBranchName = output.each{ println it }
def size = implementedBranchName.size()
for ( int i = 0; i < size; i++) {
println(implementedBranchName[i])
}
}
Current Output:
F
O
O
B
A
R
Desired Output:
FOO
BAR
You could just change
implementedBranchName = output.each{ println it }
To:
implementedBranchName = output.split()
There is also "eachLine" in Groovy.
def getImplementedBranches() {
def cmd = "/usr/bin/tool search status Pending"
Process process = cmd.execute()
process.in.eachLine { line ->
println(line)
}
}

Groovy: Detecting when being passed arrays

The function f in the following code simply attempts to print out it's arguments and how many it receives. However, it expands array parameters (but not arraylists) as illustrated on the line f(x) // 3. Is there anyway to get f not to expand array parameters, or alternatively at the very least detect that it has happened, and perhaps correct for it. The reason for this is because my "real" f function isn't as trivial and instead passes it's parameters to a given function g, which often isn't a variable parameter function which instead expects an array directly as an argument, and the expansion by f mucks that up.
def f = {
Object... args ->
print "There are: ";
print args.size();
println " arguments and they are: ";
args.each { println it };
println "DONE"
}
def x = new int[2];
x[0] = 1;
x[1] = 2;
f(1,2); // 1
f([1,2]); // 2
f(x); // 3
I doubt there is any clean solution to this, as it behaves as Java varargs. You may test the size of the array inside the closure, or, as in Java, use a method overload:
public class Arraying {
public static void main(String[] args) {
// prints "2"
System.out.println( concat( new Object[] { "a", "b" } ) );
// prints "a". Commenting the second concat(), prints "1"
System.out.println( concat( "a" ) );
// prints "3"
System.out.println( concat( "a", "b", "c" ) );
}
static String concat(Object... args) {
return String.valueOf(args.length);
}
static String concat(Object obj) { return obj.toString(); }
}
If you comment the concat(Object obj) method, all three methods will match the concat(Object... args).
You can use a label for the argument as follow:
def f = {
Object... args ->
print "There are: ";
print args.size();
println " arguments and they are: ";
args.each { println it };
println "DONE"
}
def x = new int[2];
x[0] = 1;
x[1] = 2;
f(1,2); // 1
f([1,2]); // 2
f(a:x); // <--- used label 'a', or anything else
then the output is:
There are: 2 arguments and they are:
1
2
DONE
There are: 1 arguments and they are:
[1, 2]
DONE
There are: 1 arguments and they are:
[a:[1, 2]]
DONE

how to accept multiple parameters from returning function in groovy

I want to return multiple values from a function written in groovy and receive them , but i am getting an error
class org.codehaus.groovy.ast.expr.ListExpression, with its value '[a,
b]', is a bad expression as the left hand side of an assignment
operator
My code is
int a=10
int b=0
println "a is ${a} , b is ${b}"
[a,b]=f1(a)
println "a is NOW ${a} , b is NOW ${b}"
def f1(int x) {
return [a*10,a*20]
}
You almost have it. Conceptually [ a, b ] creates a list, and ( a, b ) unwraps one, so you want (a,b)=f1(a) instead of [a,b]=f1(a).
int a=10
int b=0
println "a is ${a} , b is ${b}"
(a,b)=f1(a)
println "a is NOW ${a} , b is NOW ${b}"
def f1(int x) {
return [x*10,x*20]
}
Another example returning objects, which don't need to be the same type:
final Date foo
final String bar
(foo, bar) = baz()
println foo
println bar
def baz() {
return [ new Date(0), 'Test' ]
}
Additionally you can combine the declaration and assignment:
final def (Date foo, String bar) = baz()
println foo
println bar
def baz() {
return [ new Date(0), 'Test' ]
}
You can declare and assign the variables in which the return values are stored in one line like this, which is a slightly more compact syntax than that used in Justin's answer:
def (int a, int b) = f1(22)
In your particular case you may not be able to use this because one of the variables passed to f1 is also used to store a return value
When running Groovy in the context of Jenkins pipeline job the above answers do not work (at least on version 2.60.2), but the following does:
node {
obj = ret2()
fw = obj[0]
lw = obj[1]
echo "fw=${fw}"
echo "lw=${lw}"
}
def ret2()
{
return [5, 7]
}
Or alternatively:
node {
obj = ret2()
fw = obj.a
lw = obj.b
echo "fw=${fw}"
echo "lw=${lw}"
}
def ret2()
{
return [a:5, b:7]
}

How do I keep a line number count when using reader.eachLine to read a BufferedInputStream?

How can I keep track of the line number I'm on when using eachLine to read a BufferedInputStream?
def input = new GZIPInputStream(new FileInputStream(f))
def reader = new BufferedReader(new InputStreamReader(input))
reader.eachLine {
line ->if(line.contains(searchString)){
println "${f} - ${line}"
}
}
The closure you pass to eachLine can also take 2 parameters. First being the line of data and the second being the line number.
....
....
reader.eachLine { line, lineNumber ->
if(line.contains(searchString)) {
println "${lineNumber} - ${line}"
}
}
See GDK Doc for InputStream eachLine method.

Groovy executing shell commands

Groovy adds the execute method to String to make executing shells fairly easy;
println "ls".execute().text
but if an error happens, then there is no resulting output. Is there an easy way to get both the standard error and standard out? (other than creating a bunch of code to; create two threads to read both inputstreams, then using a parent stream to wait for them to complete then convert the strings back to text?)
It would be nice to have something like;
def x = shellDo("ls /tmp/NoFile")
println "out: ${x.out} err:${x.err}"
Ok, solved it myself;
def sout = new StringBuilder(), serr = new StringBuilder()
def proc = 'ls /badDir'.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println "out> $sout\nerr> $serr"
displays:
out> err> ls: cannot access /badDir: No such file or directory
"ls".execute() returns a Process object which is why "ls".execute().text works. You should be able to just read the error stream to determine if there were any errors.
There is a extra method on Process that allow you to pass a StringBuffer to retrieve the text: consumeProcessErrorStream(StringBuffer error).
Example:
def proc = "ls".execute()
def b = new StringBuffer()
proc.consumeProcessErrorStream(b)
println proc.text
println b.toString()
// a wrapper closure around executing a string
// can take either a string or a list of strings (for arguments with spaces)
// prints all output, complains and halts on error
def runCommand = { strList ->
assert ( strList instanceof String ||
( strList instanceof List && strList.each{ it instanceof String } ) \
)
def proc = strList.execute()
proc.in.eachLine { line -> println line }
proc.out.close()
proc.waitFor()
print "[INFO] ( "
if(strList instanceof List) {
strList.each { print "${it} " }
} else {
print strList
}
println " )"
if (proc.exitValue()) {
println "gave the following error: "
println "[ERROR] ${proc.getErrorStream()}"
}
assert !proc.exitValue()
}
I find this more idiomatic:
def proc = "ls foo.txt doesnotexist.txt".execute()
assert proc.in.text == "foo.txt\n"
assert proc.err.text == "ls: doesnotexist.txt: No such file or directory\n"
As another post mentions, these are blocking calls, but since we want to work with the output, this may be necessary.
To add one more important information to above provided answers -
For a process
def proc = command.execute();
always try to use
def outputStream = new StringBuffer();
proc.waitForProcessOutput(outputStream, System.err)
//proc.waitForProcessOutput(System.out, System.err)
rather than
def output = proc.in.text;
to capture the outputs after executing commands in groovy as the latter is a blocking call (SO question for reason).
def exec = { encoding, execPath, execStr, execCommands ->
def outputCatcher = new ByteArrayOutputStream()
def errorCatcher = new ByteArrayOutputStream()
def proc = execStr.execute(null, new File(execPath))
def inputCatcher = proc.outputStream
execCommands.each { cm ->
inputCatcher.write(cm.getBytes(encoding))
inputCatcher.flush()
}
proc.consumeProcessOutput(outputCatcher, errorCatcher)
proc.waitFor()
return [new String(outputCatcher.toByteArray(), encoding), new String(errorCatcher.toByteArray(), encoding)]
}
def out = exec("cp866", "C:\\Test", "cmd", ["cd..\n", "dir\n", "exit\n"])
println "OUT:\n" + out[0]
println "ERR:\n" + out[1]
command = "ls *"
def execute_state=sh(returnStdout: true, script: command)
but if the command failure the process will terminate

Resources