Groovy-script in jenkins println output disappears when called inside class environment - groovy

The output from println from within a class function is lost.
An example script (outputclass.groovy):
class OutputClass
{
OutputClass()
{
println("Inside class") // This will not show in the console
}
}
println("Outside class") // Only this is shown in the console
output = new OutputClass()
I use Jenkins CLI to execute the groovy script
java -jar ..\jenkins-cli.jar -s JENKINS_SERVER_URL groovy outputclass.groovy
It only outputs this:
Outside class
It seems like the class inmplicitly uses println from System.out.println, and System.out is directed to the log files, but the println outside the class is using something else, which is outputted in the script console. The following code shows the behavior.
System.out.println("First")
println("Second")
Output:
Second
How do I explicitly set the output device to output to the Jenkins script console?

I found the solution myself here http://mriet.wordpress.com.
When the Groovy plugin starts is passes two bindings to the script. From the bindings we can get the out variable. Get it and use out.println to output to the script console, not the plain println.
The script below shows full solution.
import hudson.model.*
// Get the out variable
def out = getBinding().out;
class OutputClass
{
OutputClass(out) // Have to pass the out variable to the class
{
out.println ("Inside class")
}
}
out.println("Outside class")
output = new OutputClass(out)

If you use the skript as a post build step (I'm not shure whether it works with the mentioned CLI) you can use the build in logger:
manager.listener.logger.println("some output")
So in your case something like this may be helpful:
class OutputClass
{
OutputClass(logger) // Have to pass the out variable to the class
{
logger.println ("Inside class")
}
}
output = new OutputClass(manager.listener.logger)
See also Example 10 in Groovy Plugin Doc

Does this mailing list post help?
the output is sent to standard output, so if you check your log file, you
will probably see something like this: INFO [STDOUT] Hello World
if you insist on using system script, you have to pass out variable to
your class, as the binding is not visible inside the class (so it's
passed to standard output). You should use something like this
public class Hello {
static void say(out) {
out << "Hello World "
}
}
println "Started ..."
Hello.say(out)

A simple solution that worked well for me was to add this line on top of each script. This enables usage of traditional println commands all over the code (inside and outside of classes) leaving the code intuitive.
import hudson.model.*
System.out = getBinding().out;
This enables to create log entries like this:
println("Outside class");
class OutputClass {
OutputClass() {
println ("Inside class")
}
}
new OutputClass();
It replaces the default print stream in System.out with the one handed over from Jenkins via bindings.

Related

Groovy - Type check AST generated code

I have a Groovy application that can be custimized by a small Groovy DSL I wrote. On startup, the application loads several Groovy scripts, applies some AST transformations and finally executes whatever was specified in the scripts.
One of the AST transformations inserts a couple of lines of code into certain methods. That works fine and I can see the different behavior during runtime. However, sometimes the generated code is not correct. Although I load the scripts with the TypeChecked customizer in place, my generated code is never checked for soundness.
To show my problem, I constructed an extreme example. I have the following script:
int test = 10
println test // prints 10 when executed without AST
I load this script and insert a new line of code between the declaration of test and println:
public void visitBlockStatement(BlockStatement block) {
def assignment = (new AstBuilder().buildFromSpec {
binary {
variable "test"
token "="
constant 15
}
}).first()
def newStmt = new ExpressionStatement(assignment)
newStmt.setSourcePosition(block.statements[1])
block.statements.add(2, newStmt)
super.visitBlockStatement(block)
}
After applying this AST, the script prints 15. When I use AstNodeToScriptVisitor to print the Groovy code of the resulting script, I can see the new assignment added to the code.
However, if I change the value of the assignment to a String value:
// ...
def assignment = (new AstBuilder().buildFromSpec {
binary {
variable "test"
token "="
constant "some value"
}
}).first()
// ...
I get a GroovyCastExcpetion at runtime. Although the resulting script looks like this:
int test = 10
test = "some value" // no compile error but a GroovyCastException at runtime here. WHY?
println test
no error is raised by TypeChecked. I read in this mailing list, that you need to set the source position for generated code to be checked, but I'm doing that an it still doesn't work. Can anyone provide some feedback of what I am doing wrong? Thank you very much!
Update
I call the AST by attaching it to the GroovyShell like this:
def config = new CompilerConfiguration()
config.addCompilationCustomizers(
new ASTTransformationCustomizer(TypeChecked)
)
config.addCompilationCustomizers(
new ASTTransformationCustomizer(new AddAssignmentAST())
)
def shell = new GroovyShell(config)
shell.evaluate(new File("./path/to/file.groovy"))
The class for the AST itself looks like this:
#GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
class AddAssignmentAST implements ASTTransformation {
#Override
public void visit(ASTNode[] nodes, SourceUnit source) {
def transformer = new AddAssignmentTransformer()
source.getAST().getStatementBlock().visit(transformer)
}
private class AddAssignmentTransformer extends CodeVisitorSupport {
#Override
public void visitBlockStatement(BlockStatement block) {
// already posted above
}
}
}
Since my Groovy script only consists of one block (for this small example) the visitBlockStatement method is called exactly once, adds the assignment (which I can verify since the output changes) but does not ever throw a compile-time error.

groovy script binding does not seem to operate

though I like Groovy sometimes the documentation is ... well terse
I have a problem to pass a binding to a script.
here is the code :
def conf = new CompilerConfiguration()
Binding env = new Binding()
//....
env.setProperty( // some key and value set
//
conf.setScriptBaseClass(// name of class that is a Script
def shell = new GroovyShell(env,conf)
//isReader is the reader of the code// argz is an array of Strings
shell.run(isReader, scriptName, argz)
well, for one, the "scriptname" parameter in "run" is an obscure feature (any hint? -the reader does not have the notion of a file-)
then the Binding I get in my script instance is different from the one I created! (so unable to pass variables back and forth)
I need to invoke my script using my script base class and pass a Binding and parameters to it ... if there is another way that works I would be delighted! thanks!
edit ... trying to set up examples :
package abcgroovy
abstract class MyScript extends Script{
MyScript() {
super()
def _env = getBinding()
println _env
}
MyScript(Binding binding) {
super(binding)
def _env = binding
println _env
}
}
then the invoking code :
def conf = new CompilerConfiguration()
Binding env = new Binding()
println "ENV calling :$env"
conf.setScriptBaseClass("abcgroovy.MyScript")
def shell = new GroovyShell(env,conf)
Reader isReader = new StringReader("println 'hello world'")
// second argument: can't guess what to put
shell.run(isReader,'abcgroovy.MyScript',new String[0])
now the result of a run :
ENV calling :groovy.lang.Binding#67a20f67
groovy.lang.Binding#6a192cfe
hello world
From my understanding the second parameters (fileName) is the name of the file that is parsed. This has no relevance to any functionality, but is used for error reporting. So if you have an error in your provided script, the fileName will be used in the error message. Thus, when using a different signature where you provide a URI or a File that parameter cannot be specified.
In your example the Binding from the GroovyShell actually is used, which you can verify by printing the Binding in the actual script.
def conf = new CompilerConfiguration()
Binding env = new Binding()
println "ENV calling :$env"
conf.setScriptBaseClass("abcgroovy.MyScript")
def shell = new GroovyShell(env,conf)
Reader isReader = new StringReader('println "binding in script: ${getBinding()}"')
shell.run(isReader,'abcgroovy.MyScript',new String[0])
The reason your example outputs a different Binding is the way the script is initialized. First a new MyScript instance is created without passing the Binding, then the Binding from the GroovyShell is set using setBinding. The constructor with the Binding parameter is not used.
abstract class MyScript extends Script {
MyScript() {
super()
println "MyScript() with binding ${getBinding()}"
}
MyScript(Binding binding) {
super(binding)
// not invoked!
println "MyScript(${binding})"
}
public void setBinding(Binding binding) {
super.setBinding(binding)
println "setBinding to ${binding}"
}
}
Example output
ENV calling :groovy.lang.Binding#335eadca
MyScript() with binding groovy.lang.Binding#45018215
setBinding to groovy.lang.Binding#335eadca
binding in script: groovy.lang.Binding#335eadca
Note that the Binding is temporarily different in the MyScript() constructor only.

Groovy : java introspection is bypassing metaprogramming. How to fix that?

I'm trying to redefine a method of a class for test purpose.
For doing this I'm using the meta-programming feature of Groovy.
Unfortunately this method is called by introspection by some code out of my control.
In this situation the real method is called instead of the overridden version.
Here is a groovy script example demonstrating this:
class Dummy { void sayHello() {println "Hi"} }
def dummy = new Dummy()
dummy.sayHello()
dummy.metaClass.sayHello = {println "Hello world"}
dummy.sayHello()
def method = dummy.class.getDeclaredMethod("sayHello")
method.invoke(dummy)
This code output is:
Hi
Hello world
Hi
But I would like the last line to be 'Hello World'
I have tried to override the Method.invoke method, but it was a mess.
Is there a preferred way to tell to Groovy that it should also intercept call to Method.invoke when a call to Dummy#sayHello is detected ?

Message is not printing on the console in jmeter using JSR223 and groovy

println() inside static void main method is not printing anything anywhere, whereas only println() prints in terminal. Here is my code:
class CalcMain {
static void main(def args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("groovy");
println("testing");
}
}
And when I ran it shows pass (Green Triangle in Jmeter) but doesnt print anything on terminal
Whereas a simple program such as
println("testing");
prints on terminal.
Could someone please let me know where I am doing wrong?
Don't use System.out.println in a Groovy or Beanshell step in jmeter. Instead , do this:
1. Enable the stdout console in Jmeter so that you can see the output.
2. Use log.info("Message:" + vars.get("variableName")); instead.
Use below to display text in JMeter Response Tab in "Results Tree":
SampleResult.setResponseData("Document: " + variable,"UTF-8");
Use below to log in the console text area of JMeter:
log.info("hello");
A 3rd option is to use Java standard:
System.out.println("Any String");
Above can be written from any Java/Groovy/JSR223 sampler.
But it will be printed on the Parent CMD window that opened the JMeter UI in windows.
Chapter "2. OUT" shows the answer:
https://jmetervn.com/2016/12/05/jsr223-with-groovy-variables-part-1/
use the OUT command.
OUT.println("INPUT MESSAGE HERE");
Try it:
System.out.println("testing")
You have not provided all code, just your part produces errors as imports are also needed. Definition of class does not run by its own, you need as instance and then run in explicitly, then it prints (both with and w/out System.out. prefix) to terminal:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
class CalcMain {
static void main(def args) throws Exception {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("groovy");
println ("testing1");
System.out.println ("testing2");
}
}
CalcMain test1 = new CalcMain();
test1.main();
println ("testing3");
Output:
testing1
testing2
testing3

Groovyc successfully compiles invalid groovy scripts

c:\>cat invalid.groovy
com.test.build(binding)
c:\junk>groovyc invalid.groovy
c:\junk>ls invalid.class
invalid.class
Why does this not result in an compilation error? There is no such method com.test.build!
In what scenario will this compilation be successful?
As Groovy is dynamic it cannot know that there will be no com.test.build at runtime
com may be an object added to the binding at a later date in the code's execution
An example:
Say we have this bit of groovy inside Script.groovy
com.test.build( binding )
Compile it with groovyc:
groovyc Script.groovy
Then, keep the Script.class file, and throw away the groovy script to make sure we are using the class file:
rm Script.groovy
Now, say we have the following in Runner.groovy
// Create a class which you can call test.build( a ) on
class Example {
Map test = [
build : { it ->
println "build called with parameter $it"
}
]
}
// Create one of our Com objects
def variable = new Example()
// Load the Script.class, and make an instance of it
def otherscript = new GroovyClassLoader().loadClass( 'Script' ).newInstance()
// Then, set `com` in the scripts binding to be our variable from above
otherscript.binding.com = variable
// Then, run the script
otherscript.run()
That prints:
build called with parameter groovy.lang.Binding#7bf35647
So as you can see, it gets the test parameter of the com object (the map above) and calls the build closure with the binding as a parameter...
Hope this makes sense...

Resources