GetOpts for Groovy? - groovy

Is there a standard or recommended getopts library for Groovy that will allow me to quickly process long and short command line arguements in Groovy?
groovy foo.groovy --fname=foo.txt --output=foo.html --verbose

You could also simply use Groovy CliBuilder (which internally uses Apache Commons Cli).
You will find a good example of how it works here=> http://www.reverttoconsole.com/blog/codesnippets/groovy-clibuilder-in-practice/
def cli = new CliBuilder()
cli.with {
usage: 'Self'
h longOpt:'help', 'usage information'
i longOpt:'input', 'input file', args:1
o longOpt:'output', 'output file',args:1
a longOpt:'action', 'action to invoke',args:1
d longOpt:'directory','process all files of directory', args:1
}
def opt = cli.parse(args)
def action
if( args.length == 0) {
cli.usage()
return
}
if( opt.h ) {
cli.usage()
return
}
if( opt.i ) {
input = opt.i
}
...

One of the major strengths of Groovy is interoperability with Java. Therefore, when looking for libraries to use in Groovy, my first instinct is to look for existing Java libraries.
Args4j is a concise and elegant library for parsing command line options and it works perfectly with Groovy classes. I've rewritten parts of the tutorial to work with Groovy.
Consider the following Groovy class:
import org.kohsuke.args4j.Option;
class Business {
#Option(name="-name",usage="Sets a name")
String name
public void run() {
println("Business-Logic")
println("-name: " + name)
}
}
Compile it with:
groovyc -classpath .:args4j-2.0.12/args4j-2.0.12.jar Business.groovy
and run it with
java -cp .:args4j-2.0.12/args4j-2.0.12.jar:/usr/share/java/groovy/embeddable/groovy-all-1.6.4.jar -Dmainclass=Business org.kohsuke.args4j.Starter -name sample
To get the output
Business-Logic
-name: sample

Once upon a time I wrote the Groovy Option Parser to accomplish this task. It's pretty straight forward and has some niceties.

Apache Commons CLI is another Java library that you could use in Groovy

Related

Groovy, "try-with-resources" construction alternative

I'm a new to Groovy. I used to use 'try-with-resources' construction in my Java code during work with I/O streams.
Could you please advise, is there any analogue of such construction in Groovy?
Groovy 2.3 also has withCloseable which will work on anything that implements Closeable
Groovy 3 newsflash
And Groovy 3+ supports try..with..resources as Java does
https://groovy-lang.org/releasenotes/groovy-3.0.html#_arm_try_with_resources
Have a look at the docs on Groovy IO and the associated javadoc.
It presents the withStream, withWriter, withReader constructions which are means of getting streams with auto-closeability
Simplest try-with-resources for all Groovy versions is the following (even works with AutoCloseable interface). Where class Thing is a closeable class or implements AutoCloseable.
new Thing().with { res ->
try {
// do stuff with res here
} finally {
res.close()
}
}
Which is the equivalent in later versions of Groovy doing:
new Thing().withCloseable { res ->
// do stuff with res here
}

opennlp.groovy has NullPointerException

I am trying to get the following code snippet from GitHub to work so that I can use OpenNLP tools in Groovy scripts.
(OpenNLP class from https://gist.github.com/nagaimasato/1178725)
#!/usr/bin/env groovy
#Grapes(
#Grab(
group='org.apache.opennlp',
module='opennlp-tools',
version='1.5.3'
)
)
import opennlp.tools.tokenize.*
import opennlp.tools.postag.*
OpenNLP nlp = new OpenNLP()
def tokens = nlp.workTokenize("Hello world")
println tokens
class OpenNLP {
static TokenizerModel tokenizerModel
static POSModel posModel
static {
def classLoader = OpenNLP.class.classLoader
classLoader.getResource('opennlp/en-token.bin').withInputStream {
tokenizerModel = new TokenizerModel(it)
}
classLoader.getResource('opennlp/en-pos-maxent.bin').withInputStream {
posModel = new POSModel(it)
}
}
Tokenizer tokenizer
POSTagger tagger
OpenNLP() {
tokenizer = new TokenizerME(tokenizerModel)
tagger = new POSTaggerME(posModel)
}
List workTokenize(String text) {
return tokenizer.tokenize(text)
}
List posTag(List tokens) {
return [tokens, tagger.tag(tokens)].transpose()
}
}
I get the following error when I try to run the script:
Caught: java.lang.ExceptionInInitializerError
java.lang.ExceptionInInitializerError
at Greetings.class$(Greetings.groovy)
at Greetings.$get$$class$OpenNLP(Greetings.groovy)
at Greetings.run(Greetings.groovy:13)
Caused by: java.lang.NullPointerException: Cannot invoke method withInputStream() on null object
at OpenNLP.<clinit>(Greetings.groovy:25)
... 3 more
I have en-token.bin and en-pos-maxent.bin in the right place for the script to find, but classLoader.getResource("opennlp/en-token.bin") is indeed null when I print it. Any ideas?
Make sure the en-token.bin and en-pos-maxent.bin files are in a directory named opennlp and that the classpath includes the parent directory of opennlp.
Note that ./ is included in the classpath when you execute your Groovy script, so if you have your opennlp directory in the same directory as your Groovy script and you also invoke the Groovy script while you are in that directory, it should work (at least it worked for me). But if you execute the script while you are not currently in that directory (e.g. by using a path like path/to/script.groovy) it won't work. In that case, you can just invoke it using groovy -cp path/to path/to/script.groovy, thus putting the parent directory of your opennlp directory into the classpath manually.

How to "include" common methods in groovys

I have developed a number of groovys used as plugins by Serviio.
Many of the methods used by these plugins are common, but when changes are made, each plugin needs to be updated. Therefore I want to "include" those methods in each plugin from a tools.groovy. I have tried 2 different approaches suggested in other posts.
I tried using
evaluate(new File("C:\\Program Files\\Serviio\\plugins\\tools.groovy"))
at the start of each plugin where tools.groovy just has
class Tools{method1{return}method2{return}}
but when executing the plugin I get
Caught: groovy.lang.MissingMethodException: No signature of method: Tools.main() is applicable for argument types: () values: []
If I then add
void main(args) { }
to class Tools, the error goes away but that Tools.main is run instead of the plugin.main and I get no output.
My second approach as suggested was to use
def script = new GroovyScriptEngine( '.' ).with {
loadScriptByName( 'C:\\Program Files\\Serviio\\plugins\\tools.groovy' )
}
this.metaClass.mixin script
This however gives the error
unexpected token: this # line 55, column 2.
this.metaClass.mixin script
Any suggestions on how to make either of these solutions work would be appreciated.
Did you try defining a common base script and giving it as a compiler configuration.
http://groovy.codehaus.org/Embedding+Groovy
From the groovy documentation...
class ScriptBaseTest {
#Test
void extend_groovy_script() {
def compiler = new CompilerConfiguration()
compiler.setScriptBaseClass("ScriptBaseTestScript")
def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
assertEquals shell.evaluate("foo()"), "this is foo"
}
}
abstract class ScriptBaseTestScript extends Script {
def foo() {
"this is foo"
}
}

How to retrieve Jenkins build parameters using the Groovy API?

I have a parameterized job that uses the Perforce plugin and would like to retrieve the build parameters/properties as well as the p4.change property that's set by the Perforce plugin.
How do I retrieve these properties with the Jenkins Groovy API?
Update: Jenkins 2.x solution:
With Jenkins 2 pipeline dsl, you can directly access any parameter with the trivial syntax based on the params (Map) built-in:
echo " FOOBAR value: ${params.'FOOBAR'}"
The returned value will be a String or a boolean depending on the Parameter type itself. The syntax is the same for scripted or declarative syntax. More info at: https://jenkins.io/doc/book/pipeline/jenkinsfile/#handling-parameters
If your parameter name is itself in a variable:
def paramName = "FOOBAR"
def paramValue = params.get(paramName) // or: params."${paramName}"
echo """ FOOBAR value: ${paramValue}"
Original Answer for Jenkins 1.x:
For Jenkins 1.x, the syntax is based on the build.buildVariableResolver built-ins:
// ... or if you want the parameter by name ...
def hardcoded_param = "FOOBAR"
def resolver = build.buildVariableResolver
def hardcoded_param_value = resolver.resolve(hardcoded_param)
Please note the official Jenkins Wiki page covers this in more details as well, especially how to iterate upon the build parameters:
https://wiki.jenkins-ci.org/display/JENKINS/Parameterized+System+Groovy+script
The salient part is reproduced below:
// get parameters
def parameters = build?.actions.find{ it instanceof ParametersAction }?.parameters
parameters.each {
println "parameter ${it.name}:"
println it.dump()
}
For resolving a single parameter (I guess what's most commonly needed), this is the simplest I found:
build.buildVariableResolver.resolve("myparameter")
in your Groovy System script build step.
Regarding parameters:
See this answer first. To get a list of all the builds for a project (obtained as per that answer):
project.builds
When you find your particular build, you need to get all actions of type ParametersAction with build.getActions(hudson.model.ParametersAction). You then query the returned object for your specific parameters.
Regarding p4.change: I suspect that it is also stored as an action. In Jenkins Groovy console get all actions for a build that contains p4.change and examine them - it will give you an idea what to look for in your code.
I've just got this working, so specifically, using the Groovy Postbuild plugin, you can do the following:
def paramText
def actionList = manager.build.getActions(hudson.model.ParametersAction)
if (actionList.size() != 0)
{
def pA = actionList.get(0)
paramText = pA.createVariableResolver(manager.build).resolve("MY_PARAM_NAME")
}
In cases when a parameter name cannot be hardcoded I found this would be the simplest and best way to access parameters:
def myParam = env.getProperty(dynamicParamName)
In cases, when a parameter name is known and can be hardcoded the following 3 lines are equivalent:
def myParam = env.getProperty("myParamName")
def myParam = env.myParamName
def myParam = myParamName
To get the parameterized build params from the current build from your GroovyScript (using Pipeline), all you need to do is:
Say you had a variable called VARNAME.
def myVariable = env.VARNAME
Get all of the parameters:
System.getenv().each{
println it
}
Or more sophisticated:
def myvariables = getBinding().getVariables()
for (v in myvariables) {
echo "${v} " + myvariables.get(v)
}
You will need to disable "Use Groovy Sandbox" for both.
If you are trying to get all parameters passed to Jenkins job you can use the global variable params in your groovy pipeline to fetch it.
http://jenkins_host:8080/pipeline-syntax/globals
params
Use something like below.
def dumpParameter()
{
params.each {
println it.key + " = " + it.value
}
}
thanks patrice-n! this code worked to get both queued and running jobs and their parameters:
import hudson.model.Job
import hudson.model.ParametersAction
import hudson.model.Queue
import jenkins.model.Jenkins
println("================================================")
for (Job job : Jenkins.instanceOrNull.getAllItems(Job.class)) {
if (job.isInQueue()) {
println("------------------------------------------------")
println("InQueue " + job.name)
Queue.Item queue = job.getQueueItem()
if (queue != null) {
println(queue.params)
}
}
if (job.isBuilding()) {
println("------------------------------------------------")
println("Building " + job.name)
def build = job.getBuilds().getLastBuild()
def parameters = build?.getAllActions().find{ it instanceof ParametersAction }?.parameters
parameters.each {
def dump = it.dump()
println "parameter ${it.name}: ${dump}"
}
}
}
println("================================================")
The following can be used to retreive an environment parameter:
println System.getenv("MY_PARAM")
The following snippet worked for me to get a parameter value in a parameterized project:
String myParameter = this.getProperty('binding').getVariable('MY_PARAMETER')
The goal was to dynamically lock a resource based on the selected project parameter.
In "[✓] This build requires lockable resources" I have the following "[✓] Groovy Expression":
if (resourceName == 'resource_lock_name') {
Binding binding = this.getProperty('binding')
String profile = binding.getVariable('BUILD_PROFILE')
return profile == '-Poradb' // acquire lock if "oradb" profile is selected
}
return false
In "[✓] This project is parameterized" section I have a "Choice Parameter" named e.g. BUILD_PROFILE
Example of Choices are:
-Poradb
-Ph2db
-DskipTests -T4
The lock on "resource_lock_name" will be acquired only if "-Poradb" is selected when building project with parameters
[-] Use Groovy Sandbox shall be unchecked for this syntax to work

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

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.

Resources