SHL-113 Allow for there two be options with two empty keys
Looking for a better solution, but work well for the more common case
of having default options that correspond to an empty string value,
CliOption(key = { "", "command" }
This commit is contained in:
@@ -21,7 +21,6 @@ import java.util.logging.Logger;
|
|||||||
import org.springframework.shell.core.CommandMarker;
|
import org.springframework.shell.core.CommandMarker;
|
||||||
import org.springframework.shell.core.annotation.CliCommand;
|
import org.springframework.shell.core.annotation.CliCommand;
|
||||||
import org.springframework.shell.core.annotation.CliOption;
|
import org.springframework.shell.core.annotation.CliOption;
|
||||||
import org.springframework.shell.core.annotation.PassThroughOptions;
|
|
||||||
import org.springframework.shell.support.logging.HandlerUtils;
|
import org.springframework.shell.support.logging.HandlerUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -40,7 +39,6 @@ public class OsCommands implements CommandMarker {
|
|||||||
private OsOperations osOperations = new OsOperationsImpl();
|
private OsOperations osOperations = new OsOperationsImpl();
|
||||||
|
|
||||||
@CliCommand(value = "!", help = "Allows execution of operating system (OS) commands")
|
@CliCommand(value = "!", help = "Allows execution of operating system (OS) commands")
|
||||||
@PassThroughOptions
|
|
||||||
public void command(
|
public void command(
|
||||||
@CliOption(key = { "", "command" }, mandatory = false, specifiedDefaultValue = "", unspecifiedDefaultValue = "", help = "The command to execute") final String command) {
|
@CliOption(key = { "", "command" }, mandatory = false, specifiedDefaultValue = "", unspecifiedDefaultValue = "", help = "The command to execute") final String command) {
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import java.util.logging.Logger;
|
|||||||
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
|
import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
|
||||||
import org.springframework.shell.core.annotation.CliCommand;
|
import org.springframework.shell.core.annotation.CliCommand;
|
||||||
import org.springframework.shell.core.annotation.CliOption;
|
import org.springframework.shell.core.annotation.CliOption;
|
||||||
import org.springframework.shell.core.annotation.PassThroughOptions;
|
|
||||||
import org.springframework.shell.event.ParseResult;
|
import org.springframework.shell.event.ParseResult;
|
||||||
import org.springframework.shell.support.logging.HandlerUtils;
|
import org.springframework.shell.support.logging.HandlerUtils;
|
||||||
import org.springframework.shell.support.util.ExceptionUtils;
|
import org.springframework.shell.support.util.ExceptionUtils;
|
||||||
@@ -160,13 +159,8 @@ public class SimpleParser implements Parser {
|
|||||||
// Attempt to parse
|
// Attempt to parse
|
||||||
Map<String, String> options = null;
|
Map<String, String> options = null;
|
||||||
|
|
||||||
// Hint to the parser that options will not be of the form --key=value, but should attempt to parse and
|
|
||||||
// pass through the command option 'as is'
|
|
||||||
PassThroughOptions passThroughOptions = methodTarget.getMethod()
|
|
||||||
.getAnnotation(PassThroughOptions.class);
|
|
||||||
try {
|
try {
|
||||||
options = new Tokenizer(methodTarget.getRemainingBuffer(),
|
options = new Tokenizer(methodTarget.getRemainingBuffer()).getTokens();
|
||||||
false, passThroughOptions != null).getTokens();
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
LOGGER.warning(ExceptionUtils.extractRootCause(e).getMessage());
|
LOGGER.warning(ExceptionUtils.extractRootCause(e).getMessage());
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.springframework.shell.core;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.shell.support.util.StringUtils;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,12 +56,6 @@ public class Tokenizer {
|
|||||||
/** Useful when trying to do auto complete. */
|
/** Useful when trying to do auto complete. */
|
||||||
private boolean allowUnbalancedLastQuotedValue;
|
private boolean allowUnbalancedLastQuotedValue;
|
||||||
|
|
||||||
/**
|
|
||||||
* When processing 'raw' command options, allow them to be aggregated
|
|
||||||
* together
|
|
||||||
*/
|
|
||||||
private boolean allowMultipleEmptyOptions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to indicate that the last value was indeed half enclosed in quotes.
|
* Used to indicate that the last value was indeed half enclosed in quotes.
|
||||||
* Useful so that parser can re-add it.
|
* Useful so that parser can re-add it.
|
||||||
@@ -76,14 +71,8 @@ public class Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Tokenizer(String text, boolean allowUnbalancedLastQuotedValue) {
|
public Tokenizer(String text, boolean allowUnbalancedLastQuotedValue) {
|
||||||
this(text, allowUnbalancedLastQuotedValue, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Tokenizer(String text, boolean allowUnbalancedLastQuotedValue,
|
|
||||||
boolean allowMultipleEmptyOptions) {
|
|
||||||
this.buffer = text.toCharArray();
|
this.buffer = text.toCharArray();
|
||||||
this.allowUnbalancedLastQuotedValue = allowUnbalancedLastQuotedValue;
|
this.allowUnbalancedLastQuotedValue = allowUnbalancedLastQuotedValue;
|
||||||
this.allowMultipleEmptyOptions = allowMultipleEmptyOptions;
|
|
||||||
tokenize();
|
tokenize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,9 +125,9 @@ public class Tokenizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void store(String key, String value) {
|
private void store(String key, String value) {
|
||||||
if (this.allowMultipleEmptyOptions) {
|
if (key.length() == 0) {
|
||||||
//collect up all the options and reconstruct the full 'string' by appending
|
// collect up all the value for the empty key, common when
|
||||||
//each parsed option together with a space.
|
// trying to use a default value for a command option.
|
||||||
if (result.containsKey(key)) {
|
if (result.containsKey(key)) {
|
||||||
String originalValue = result.get(key);
|
String originalValue = result.get(key);
|
||||||
result.put(key, originalValue + " " + value);
|
result.put(key, originalValue + " " + value);
|
||||||
@@ -146,9 +135,12 @@ public class Tokenizer {
|
|||||||
result.put(key, value);
|
result.put(key, value);
|
||||||
}
|
}
|
||||||
} else if (result.put(key, value) != null) {
|
} else if (result.put(key, value) != null) {
|
||||||
|
//don't allow key value pairs such as --foo bar --foo buzz"
|
||||||
throw new IllegalArgumentException("You cannot specify option '"
|
throw new IllegalArgumentException("You cannot specify option '"
|
||||||
+ key + "' more than once in a single command");
|
+ key + "' more than once in a single command");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2012 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.shell.core.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A marker annotation on a method that indicates if the options for this command
|
|
||||||
* should not be parsed by the shell.
|
|
||||||
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* An example of when to use this is when passing arguments through to the the underying
|
|
||||||
* Operating System Shell, e.g using the command " ! ls /tmp" *
|
|
||||||
* <p>
|
|
||||||
*
|
|
||||||
* @author Mark Pollack
|
|
||||||
* @since 1.1
|
|
||||||
*/
|
|
||||||
@Inherited
|
|
||||||
@Documented
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
public @interface PassThroughOptions {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,6 +81,7 @@ public class TokenizerTests {
|
|||||||
tokenize("--foo bar --foo buzz");
|
tokenize("--foo bar --foo buzz");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Ignore
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testTwoOptionsSameEmptyKey() {
|
public void testTwoOptionsSameEmptyKey() {
|
||||||
tokenize("bar buzz");
|
tokenize("bar buzz");
|
||||||
|
|||||||
Reference in New Issue
Block a user