Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GROOVY-6675 : Base script support for JCommander annotation-based parameters #371

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Merge in tweaks from current Gondor version. Primarily that subcomman…
…ds are called Subcommand now and exit codes are handled.
  • Loading branch information
jimwhite committed May 30, 2014
commit ed28b8c93ac12cf3736a2a119f6034f5f98c8cac
Original file line number Diff line number Diff line change
@@ -15,7 +15,9 @@
*/

package groovy.cli;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterDescription;
import com.beust.jcommander.ParameterException;

import groovy.lang.MissingPropertyException;
@@ -51,13 +53,37 @@ public Object run() {
JCommander jc = getScriptJCommanderWithInit();
try {
parseScriptArguments(jc, args);
for (ParameterDescription pd : jc.getParameters()) {
if (pd.isHelp() && pd.isAssigned()) return exitCode(printHelpMessage(jc, args));
}
runScriptCommand(jc);
return runScriptBody();
return exitCode(runScriptBody());
} catch (ParameterException pe) {
return handleParameterException(jc, args, pe);
return exitCode(handleParameterException(jc, args, pe));
}
}

/**
* If the given numeric code is numeric and non-zero, then return that from this process using System.exit.
* Non-numeric values (including null) are taken to be zero and returned as-is.
*
* @param code
* @return the given code
*/
public Object exitCode(Object code) {
if (code instanceof Number) {
int codeValue = ((Number) code).intValue();
if (codeValue != 0) System.exit(codeValue);
}
return code;
}

/**
* Return the script arguments as an array of strings.
* The default implementation is to get the "args" property.
*
* @return the script arguments as an array of strings.
*/
public String[] getScriptArguments() {
return (String[]) getProperty("args");
}
@@ -77,8 +103,8 @@ protected JCommander getScriptJCommanderWithInit() {
// this then it just gets stuffed into a binding that shadows the property.
// This is somewhat related to other bugged behavior in Script wrt properties and bindings.
// See http://jira.codehaus.org/browse/GROOVY-6582 for example.
// The correct behavior for Script.setProperty should to check for the
// property before creating a binding doesn't already exist.
// The correct behavior for Script.setProperty would be to check whether
// the property has a setter before creating a new script binding.
this.getMetaClass().setProperty(this, SCRIPT_JCOMMANDER, jc);
}
return jc;
@@ -117,7 +143,7 @@ public void initializeJCommanderCommands(JCommander jc) {
while (cls != null) {
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
Annotation annotation = field.getAnnotation(Command.class);
Annotation annotation = field.getAnnotation(Subcommand.class);
if (annotation != null) {
try {
field.setAccessible(true);
@@ -187,31 +213,51 @@ public void printErrorMessage(String message) {
/**
* If a ParameterException occurs during parseScriptArguments, runScriptCommand, or runScriptBody
* then this gets called to report the problem.
* The default behavior is to show the arguments and the JCommander.usage using printErrorMessage.
* The default behavior is to show the exception message using printErrorMessage, then call printHelpMessage.
* The return value becomes the return value for the Script.run which will be the exit code
* if we've been called from the command line.
*
* @param jc The JCommander instance
* @param args The argument array
* @param pe The ParameterException that occurred
* @return The value that Script.run should return.
* @return The value that Script.run should return (2 by default).
*/
public Object handleParameterException(JCommander jc, String[] args, ParameterException pe) {
StringBuilder sb = new StringBuilder();

sb.append(pe.getMessage());
sb.append("\n");

sb.append("args: [");
sb.append(join(args, ", "));
sb.append("]");
sb.append("\n");

sb.append(pe.getMessage());

printErrorMessage(sb.toString());

printHelpMessage(jc, args);

return 3;
}

/**
* If a @Parameter whose help attribute is annotated as true appears in the arguments.
* then the script body is not run and this printHelpMessage method is called instead.
* The default behavior is to show the arguments and the JCommander.usage using printErrorMessage.
* The return value becomes the return value for the Script.run which will be the exit code
* if we've been called from the command line.
*
* @param jc The JCommander instance
* @param args The argument array
* @return The value that Script.run should return (1 by default).
*/
public Object printHelpMessage(JCommander jc, String[] args) {
StringBuilder sb = new StringBuilder();

jc.usage(sb);

printErrorMessage(sb.toString());

return -1;
return 2;
}

}
Original file line number Diff line number Diff line change
@@ -33,5 +33,5 @@
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Command {
public @interface Subcommand {
}
Original file line number Diff line number Diff line change
@@ -46,8 +46,8 @@ public class CommandAdd {
private Boolean interactive = false;
}

@Command @Field CommandCommit commitCommand = new CommandCommit()
@Command @Field CommandAdd addCommand = new CommandAdd()
@Subcommand @Field CommandCommit commitCommand = new CommandCommit()
@Subcommand @Field CommandAdd addCommand = new CommandAdd()

println verbose
println scriptJCommander.parsedCommand