Println as argument in groovy script - groovy

I have one groovy script which print some statistics: println: "..."
now I have another groovy script which needs this data. Is possible somehow run first script from second and save this data as paramater and then work with them from second script ? I just know how to run script: with GroovyShell() and then run(...) but this doesnt return output of first script

A few options:
If you're calling it from a script, redefine stdout.
Fix the first script so it prints data retrieved from a class, and re-write the calling script to use that class instead of relying on the printed output from the first. Long-term may be the best option.
Use a pipe on the command line: groovy s1.groovy | groovy s2.groovy
Personally, when composing things that do stuff with stdin/stdio, I prefer the last method. Example:
s1.groovy
5.times { println it }
s2.groovy
r = new BufferedReader(new InputStreamReader(System.in))
while (l = r.readLine()) { println((l as Integer) * 2) }
Output
$ groovy s1.groovy
0
1
2
3
4
$ groovy s1.groovy | groovy s2.groovy
0
2
4
6
8

One way to do this would be to set the out parameter in the binding when calling the first script:
So given a script s1.groovy:
//Print the letters of 'tim_yates', one per line
'tim_yates'.each this.&println
We can do (in s2.groovy)
// Create a StringWriter that will capture output
String output = new StringWriter().with { sw ->
// And make a Binding for our script
new Binding().with { b ->
// Set 'out' in the Binding to be our StringWriter
b[ 'out' ] = sw
// evaluate the file with the GroovyShell (using the binding)
new GroovyShell( b ).evaluate( new File( 's1.groovy' ) )
}
// And return the String captured in our writer
sw.toString()
}
println output
And then run it with groovy s2.groovy
Edit
I think this is option #1 in Dave's answer...

Related

Java Application taking long time to execute Groovy scripts which are precomplied

I have my groovy script precomplied on server start (I have stored groovy scripts as varchar in DB) up like below in Map ,
final Binding sharedData = new Binding();
final GroovyShell shell = new GroovyShell(sharedData);
script= shell.parse(rs.getString("VALIDATION_SCRIPT"));
Now when checking the validation on input records based on specified validation id i try to execute the precompiled script as below.
Script scrpt = Validation.getScript(); //getting from cache
scrpt.getBinding().setVariable("attributes", objects);
scrpt.getBinding().setVariable("tools", scrpt);
GroovyResponse gr = scrpt.evaluate("tools.valid(attributes)");
but here my application takes long time to evaluate..i guess heap size also gets increase and GC takes place. Can any one help me if there are better way to do it. with out impacting the performance.
one of My groovy script :
import com.fis.derivatives.utility.generic.model.GroovyResponse;
def valid(Map mapInput){
GroovyResponse obj = new GroovyResponse()
if(mapInput.inputVal.equals("1")){
obj.setStatus(true) ;
obj.setResultValue("B") ;
} else if(mapInput.inputVal.equals("2")){
obj.setStatus(true) ;
obj.setResultValue("S") ;
}else{
obj.setStatus(false);
obj.setComment("Error : Unable to extract BUY_SELL. Please check BS value "+mapInput.inputVal+".")
}
return obj;
}
1 - I have doubts about your cache. getting from cache without any key is strange...
Script scrpt = Validation.getScript(); //getting from cache
2 - rework a little the call of groovy:
Script scrpt = Validation.getScript(); //getting from cache
//we will pass attributes as a parameter to method
//scrpt.getBinding().setVariable("attributes", objects);
//not necessary to pass to script link to itself
//scrpt.getBinding().setVariable("tools", scrpt);
GroovyResponse gr = scrpt.invokeMethod​("valid", objects);

Using Groovy, how can we call a python script, in windows, with one argument

I need to run a python script in windows system using groovy script.
Example:
python.exe c:/main.py argument1
I am new to groovy and I don't know, how to do it.
Please share me groovy syntax to run python as mentioned in the above example
I am preparing this script for jenkins.
so, "command".execute() is the right start.
But this command only starts a thread and you don't wait for the result.
try this code:
def task = "python main.py".execute()
task.waitFor()
println task.text
These lines start the execution, wait for it to finish and print the result.
To output already during execution for longer running tasks, I've written myself a small helper:
String.metaClass.executeCmd = { silent ->
//make sure that all paramters are interpreted through the cmd-shell
//TODO: make this also work with *nix
def p = "cmd /c ${delegate.value}".execute()
def result = [std: '', err: '']
def ready = false
Thread.start {
def reader = new BufferedReader(new InputStreamReader(p.in))
def line = ""
while ((line = reader.readLine()) != null) {
if (silent != false) {
println "" + line
}
result.std += line + "\n"
}
ready = true
reader.close()
}
p.waitForOrKill(30000)
def error = p.err.text
if (error.isEmpty()) {
return result
} else {
throw new RuntimeException("\n" + error)
}
}
This defines through meta programming a new method on String called executeCmd.
Put this on top of your file and then your line
"python c:/main.py".executeCmd()
This should show you all output during execution and it will help you to handle the paramaters the correcct way through the "cmd /c"-prefix. (If you just call execute on a string, you often run into problems with spaces and other characters in your command.
If you already have the parameters as a list and need some code which also runs on a *nix machine, try to call execute() on a list:
["python", "c:/main.py"].execute()
hope this helps
ps: http://mrhaki.blogspot.com/2009/10/groovy-goodness-executing-string-or.html

Groovy exec buffering output - not printing until batch file completes

When executing a bat file from Groovy, the output of this is not printed from the Groovy script until the bat file is complete. To compare, I tested the same exact bat file from C# and Perl. These both print the output of the bat file as it's being written to STDOUT.
def cmd = "batfile.bat param1"
println cmd.execute().text()
Is there a way to tell Groovy to read the stream and print immediately?
Thank you for the response! I addition to note is when using the recommendation the exec did not wait for the process to complete, which we desire in this case, so adding process.waitFor() accomplished this. Working code example below. (Note test.bat is anything you like, such as: sleep 5)
import groovy.time.*
def times = [:]
def progStartTime = new Date()
String[] caches = ["cache1", "cache2", "cache3"]
def cmd
def batFile = "test.bat "
println new Date()
for (String item : caches) {
def timeStart = new Date()
cmd = [batFile, item]
//println cmd.execute().text
def process = cmd.execute()
process.consumeProcessOutput(System.out, System.err)
process.waitFor()
def timeStop = new Date()
TimeDuration duration = TimeCategory.minus(timeStop, timeStart)
println "cache: " + item + " : " + duration
times.put(item,duration)
}
times.each{ k, v -> println "cache: ${k}, took: ${v}" }
def progStopTime = new Date()
TimeDuration duration = TimeCategory.minus(progStopTime, progStartTime)
println "Total Program duration: " + duration
println new Date()
First of all I believe it should read:
cmd.execute().text
without parenthesis so that we call the groovy Process.getText() method. However that will not solve your problem as the getText() method waits for process completion before returning.
If you don't need control of the output but just want it directly on standard out and standard err, you can use the groovy Process.consumeProcessOutput() method:
def process = "batfile.bat param1".execute()
process.consumeProcessOutput(System.out, System.err)
This will output the process out and err stream output directly on the system out and err streams as the output becomes available.
If you need processing or control, something like the following should solve your problem:
def process = "batfile.bat param1".execute()
process.in.withReader { r ->
r.eachLine { line ->
// some token processing
println "batfile output> ${line.toUpperCase()}"
}
}
also parameters with spaces tend to cause havoc so I have found it is often safer to use the groovy List.execute() form instead as in:
def process = ["batfile.bat", "param1"].execute()
which does the same thing but keeps parameter integrity with regards to spaces.

Using groovy Eval to process generated expression

I'm trying to create a field mapping to map fields from user-friendly names to member variables in a variety of domain objects. The larger context is that I'm building up an ElasticSearch query based on user-constructed rules stored in a database, but for the sake of MCVE:
class MyClass {
Integer amount = 123
}
target = new MyClass()
println "${target.amount}"
fieldMapping = [
'TUITION' : 'target.amount'
]
fieldName = 'TUITION'
valueSource = '${' + "${fieldMapping[fieldName]}" + '}'
println valueSource
value = Eval.me('valueSource')
The Eval fails. Here's the output:
123
${target.amount}
Caught: groovy.lang.MissingPropertyException: No such property: valueSource for class: Script1
groovy.lang.MissingPropertyException: No such property: valueSource for class: Script1
at Script1.run(Script1.groovy:1)
at t.run(t.groovy:17)
What's necessary to evaluate the generated variable name and return the value 123? It seems like the real problem is that it's not recognizing that valueSource has been defined, not the actual expression held in valueSource, but that could be wring, too.
You're almost there, but you need to use a slightly different mechanism: the GroovyShell. You can instantiate a GroovyShell and use it to evaluate a String as a script, returning the result. Here's your example, modified to work properly:
class MyClass {
Integer amount = 123
}
target = new MyClass()
fieldMapping = [
'TUITION' : 'target.amount'
]
fieldName = 'TUITION'
// These are the values made available to the script through the Binding
args = [target: target]
// Create the shell with the binding as a parameter
shell = new GroovyShell(args as Binding)
// Evaluate the "script", which in this case is just the string "target.amount".
// Inside the shell, "target" is available because you added it to the shell's binding.
result = shell.evaluate(fieldMapping[fieldName])
assert result == 123
assert result instanceof Integer

Use groovy script output as input for another groovy script

I'll apologise in advance, I'm new to groovy. The problem I have is I have 3 groovy scripts which perform different functionality, and I need to call them from my main groovy script, using the output from script 1 as input for script 2 and script 2's output as input for script 3.
I've tried the following code:
script = new GroovyShell(binding)
script.run(new File("script1.groovy"), "--p", "$var" ) | script.run(new File("script2.groovy"), "<", "$var" )
When I run the above code the first script runs successfully but the 2nd doesn't run at all.
Script 1 takes an int as a parameter using the "--p", "$var" code. This runs successfully in the main script using: script.run(new File("script1.groovy"), "--p", "$var" ) - Script 1's output is an xml file.
When I run script.run(new File("script2.groovy"), "<", "$var" ) on its own in the main groovy script nothing happens and the system hangs.
I can run script 2 from the command line using groovy script2.groovy < input_file and it works fine.
Any help would be greatly appreciated.
You cannot pass the < as an argument to the script as redirection is handled by the Shell when you run things from the command line...
Redirecting output from Scripts into other scripts is notoriously difficult, and basically relies on you changing System.out for the duration of each script (and hoping that nothing else in the JVM prints and messes up your data)
Better to use java processes like the following:
Given these 3 scripts:
script1.groovy
// For each argument
args.each {
// Wrap it in xml and write it out
println "<woo>$it</woo>"
}
linelength.groovy
// read input
System.in.eachLine { line ->
// Write out the number of chars in each line
println line.length()
}
pretty.groovy
// For each line print out a nice report
int index = 1
System.in.eachLine { line ->
println "Line $index contains $line chars (including the <woo></woo> bit)"
index++
}
We can then write something like this to get a new groovy process to run each in turn, and pipe the outputs into each other (using the overloaded or operator on Process):
def s1 = 'groovy script1.groovy arg1 andarg2'.execute()
def s2 = 'groovy linelength.groovy'.execute()
def s3 = 'groovy pretty.groovy'.execute()
// pipe the output of process1 to process2, and the output
// of process2 to process3
s1 | s2 | s3
s3.waitForProcessOutput( System.out, System.err )
Which prints out:
Line 1 contains 15 chars (including the <woo></woo> bit)
Line 2 contains 18 chars (including the <woo></woo> bit)
//store standard I/O
PrintStream systemOut = System.out
InputStream systemIn = System.in
//Buffer for exchanging data between scripts
ByteArrayOutputStream buffer = new ByteArrayOutputStream()
PrintStream out = new PrintStream(buffer)
//Redirecting "out" of 1st stream to buffer
System.out = out
//RUN 1st script
evaluate("println 'hello'")
out.flush()
//Redirecting buffer to "in" of 2nd script
System.in = new ByteArrayInputStream(buffer.toByteArray())
//set standard "out"
System.out = systemOut
//RUN 2nd script
evaluate("println 'message from the first script: ' + new Scanner(System.in).next()")
//set standard "in"
System.in = systemIn
result is: 'message from the first script: hello'

Resources