From 73b879ea8957c4550d1c58607db96924010c022b Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Fri, 10 Mar 2017 18:24:02 +0300 Subject: [PATCH] Misc: Include cli-parser 1.1.2 sources into the project under different package and drop original library dependency This would allow building the project with Kotlin JPS plugin on TeamCity where older library takes precendence due to appearing earlier in JPS classpath --- .idea/artifacts/KotlinJpsPlugin.xml | 1 - .idea/libraries/cli_parser.xml | 11 - .../kotlin/compilerRunner/ArgumentUtils.java | 2 +- build.xml | 4 +- compiler/cli/cli-common/cli-common.iml | 1 - .../arguments/CommonCompilerArguments.java | 2 +- .../arguments/K2JSCompilerArguments.java | 2 +- .../arguments/K2JVMCompilerArguments.java | 2 +- .../K2MetadataCompilerArguments.java | 2 +- .../cli/common/arguments/argumentUtils.kt | 2 +- .../parser/com/sampullara/cli/Args.java | 529 ++++++++++++++++++ .../parser/com/sampullara/cli/Argument.java | 41 ++ .../com/sampullara/cli/PropertiesArgs.java | 111 ++++ .../jetbrains/kotlin/cli/common/Usage.java | 2 +- .../arguments/GenerateGradleOptions.kt | 2 +- .../jetbrains/kotlin/idea/project/Platform.kt | 2 +- idea/idea-maven/idea-maven.iml | 1 - .../idea/stubs/AbstractMultiModuleTest.kt | 2 +- jps-plugin/jps-plugin.iml | 1 - update_dependencies.xml | 5 +- 20 files changed, 693 insertions(+), 32 deletions(-) delete mode 100644 .idea/libraries/cli_parser.xml create mode 100644 compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Args.java create mode 100644 compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Argument.java create mode 100644 compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/PropertiesArgs.java diff --git a/.idea/artifacts/KotlinJpsPlugin.xml b/.idea/artifacts/KotlinJpsPlugin.xml index 3780f366e85..e33799f83e9 100644 --- a/.idea/artifacts/KotlinJpsPlugin.xml +++ b/.idea/artifacts/KotlinJpsPlugin.xml @@ -11,7 +11,6 @@ - diff --git a/.idea/libraries/cli_parser.xml b/.idea/libraries/cli_parser.xml deleted file mode 100644 index 9e3c7cbd887..00000000000 --- a/.idea/libraries/cli_parser.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java index 2feb0cf2683..fdcf4cce51b 100644 --- a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java +++ b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java @@ -19,9 +19,9 @@ package org.jetbrains.kotlin.compilerRunner; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Function; import com.intellij.util.containers.ComparatorUtil; -import com.sampullara.cli.Argument; import org.jetbrains.annotations.NotNull; import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments; +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument; import java.lang.reflect.Field; import java.util.ArrayList; diff --git a/build.xml b/build.xml index 0bab79efbac..95f130117d3 100644 --- a/build.xml +++ b/build.xml @@ -1,4 +1,4 @@ - + @@ -72,7 +72,6 @@ - @@ -589,7 +588,6 @@ - diff --git a/compiler/cli/cli-common/cli-common.iml b/compiler/cli/cli-common/cli-common.iml index 7447a45530f..a44850e98ce 100644 --- a/compiler/cli/cli-common/cli-common.iml +++ b/compiler/cli/cli-common/cli-common.iml @@ -9,7 +9,6 @@ - diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java index 21a07c9204e..dbb8f970d5c 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CommonCompilerArguments.java @@ -17,8 +17,8 @@ package org.jetbrains.kotlin.cli.common.arguments; import com.intellij.util.SmartList; -import com.sampullara.cli.Argument; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument; import java.io.Serializable; import java.util.List; diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java index 37da1d56d8b..cafc7fc278b 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.java @@ -16,9 +16,9 @@ package org.jetbrains.kotlin.cli.common.arguments; -import com.sampullara.cli.Argument; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument; import static org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.CALL; import static org.jetbrains.kotlin.cli.common.arguments.K2JsArgumentConstants.NO_CALL; diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java index 23b1509125a..4d62eca82b4 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JVMCompilerArguments.java @@ -16,8 +16,8 @@ package org.jetbrains.kotlin.cli.common.arguments; -import com.sampullara.cli.Argument; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument; public class K2JVMCompilerArguments extends CommonCompilerArguments { public static final long serialVersionUID = 0L; diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2MetadataCompilerArguments.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2MetadataCompilerArguments.java index d87c7c240f2..18e5d383bb4 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2MetadataCompilerArguments.java +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2MetadataCompilerArguments.java @@ -16,7 +16,7 @@ package org.jetbrains.kotlin.cli.common.arguments; -import com.sampullara.cli.Argument; +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument; public class K2MetadataCompilerArguments extends CommonCompilerArguments { public static final long serialVersionUID = 0L; diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt index 33a87c78d47..2b8bdc1136f 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt @@ -17,7 +17,7 @@ package org.jetbrains.kotlin.cli.common.arguments import com.intellij.util.xmlb.XmlSerializerUtil -import com.sampullara.cli.Args +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Args import java.lang.reflect.Field import java.lang.reflect.Modifier import java.util.* diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Args.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Args.java new file mode 100644 index 00000000000..6d9ff44aa85 --- /dev/null +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Args.java @@ -0,0 +1,529 @@ +/* + * Copyright (c) 2005, Sam Pullara. All Rights Reserved. + * You may modify and redistribute as long as this attribution remains. + */ + +package org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli; + + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.io.PrintStream; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +public class Args { + + /** + * {@link ValueCreator} building object using a one arg constructor taking a {@link String} object as parameter + */ + public static final ValueCreator FROM_STRING_CONSTRUCTOR = new ValueCreator() { + public Object createValue(Class type, String value) { + Object v = null; + try { + Constructor init = type.getDeclaredConstructor(String.class); + v = init.newInstance(value); + } catch (NoSuchMethodException e) { + // ignore + } catch (Exception e) { + throw new IllegalArgumentException("Failed to convert " + value + " to type " + type.getName(), e); + } + return v; + } + }; + public static final ValueCreator ENUM_CREATOR = new ValueCreator() { + @SuppressWarnings({"unchecked", "rawtypes"}) + public Object createValue(Class type, String value) { + if (Enum.class.isAssignableFrom(type)) { + return Enum.valueOf(type, value); + } + return null; + } + }; + private static final List DEFAULT_VALUE_CREATORS = Arrays.asList(Args.FROM_STRING_CONSTRUCTOR, Args.ENUM_CREATOR); + private static List valueCreators = new ArrayList(DEFAULT_VALUE_CREATORS); + + /** + * A convenience method for parsing and automatically producing error messages. + * + * @param target Either an instance or a class + * @param args The arguments you want to parse and populate + * @return The list of arguments that were not consumed + */ + public static List parseOrExit(Object target, String[] args) { + try { + return parse(target, args); + } catch (IllegalArgumentException e) { + System.err.println(e.getMessage()); + Args.usage(target); + System.exit(1); + throw e; + } + } + + public static List parse(Object target, String[] args) { + return parse(target, args, true); + } + + /** + * Parse a set of arguments and populate the target with the appropriate values. + * + * @param target + * Either an instance or a class + * @param args + * The arguments you want to parse and populate + * @param failOnExtraFlags + * Throw an IllegalArgumentException if extra flags are present + * @return The list of arguments that were not consumed + */ + public static List parse(Object target, String[] args, boolean failOnExtraFlags) { + List arguments = new ArrayList(); + arguments.addAll(Arrays.asList(args)); + Class clazz; + if (target instanceof Class) { + clazz = (Class) target; + } else { + clazz = target.getClass(); + try { + BeanInfo info = Introspector.getBeanInfo(clazz); + for (PropertyDescriptor pd : info.getPropertyDescriptors()) { + processProperty(target, pd, arguments); + } + } catch (IntrospectionException e) { + // If its not a JavaBean we ignore it + } + } + + // Check fields of 'target' class and its superclasses + for (Class currentClazz = clazz; currentClazz != null; currentClazz = currentClazz.getSuperclass()) { + for (Field field : currentClazz.getDeclaredFields()) { + processField(target, field, arguments); + } + } + + if (failOnExtraFlags) { + for (String argument : arguments) { + if (argument.startsWith("-")) { + throw new IllegalArgumentException("Invalid argument: " + argument); + } + } + } + return arguments; + } + + private static void processField(Object target, Field field, List arguments) { + Argument argument = field.getAnnotation(Argument.class); + if (argument != null) { + boolean set = false; + for (Iterator i = arguments.iterator(); i.hasNext(); ) { + String arg = i.next(); + String prefix = argument.prefix(); + String delimiter = argument.delimiter(); + if (arg.startsWith(prefix)) { + Object value; + String name = getName(argument, field); + String alias = getAlias(argument); + arg = arg.substring(prefix.length()); + Class type = field.getType(); + if (arg.equals(name) || (alias != null && arg.equals(alias))) { + i.remove(); + value = consumeArgumentValue(type, argument, i); + if (!set) { + setField(type, field, target, value, delimiter); + } else { + addArgument(type, field, target, value, delimiter); + } + set = true; + } + if (set && !type.isArray()) break; + } + } + if (!set && argument.required()) { + String name = getName(argument, field); + throw new IllegalArgumentException("You must set argument " + name); + } + } + } + + private static void addArgument(Class type, Field field, Object target, Object value, String delimiter) { + try { + Object[] os = (Object[]) field.get(target); + Object[] vs = (Object[]) getValue(type, value, delimiter); + Object[] s = (Object[]) Array.newInstance(type.getComponentType(), os.length + vs.length); + System.arraycopy(os, 0, s, 0, os.length); + System.arraycopy(vs, 0, s, os.length, vs.length); + field.set(target, s); + } catch (IllegalAccessException iae) { + throw new IllegalArgumentException("Could not set field " + field, iae); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e); + } + } + + private static void addPropertyArgument(Class type, PropertyDescriptor property, Object target, Object value, String delimiter) { + try { + Object[] os = (Object[]) property.getReadMethod().invoke(target); + Object[] vs = (Object[]) getValue(type, value, delimiter); + Object[] s = (Object[]) Array.newInstance(type.getComponentType(), os.length + vs.length); + System.arraycopy(os, 0, s, 0, os.length); + System.arraycopy(vs, 0, s, os.length, vs.length); + property.getWriteMethod().invoke(target, (Object) s); + } catch (IllegalAccessException iae) { + throw new IllegalArgumentException("Could not set property " + property, iae); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e); + } catch (InvocationTargetException e) { + throw new IllegalArgumentException("Failed to validate argument " + value + " for " + property); + } + } + + private static void processProperty(Object target, PropertyDescriptor property, List arguments) { + Method writeMethod = property.getWriteMethod(); + if (writeMethod != null) { + Argument argument = writeMethod.getAnnotation(Argument.class); + if (argument != null) { + boolean set = false; + for (Iterator i = arguments.iterator(); i.hasNext(); ) { + String arg = i.next(); + String prefix = argument.prefix(); + String delimiter = argument.delimiter(); + if (arg.startsWith(prefix)) { + Object value; + String name = getName(argument, property); + String alias = getAlias(argument); + arg = arg.substring(prefix.length()); + Class type = property.getPropertyType(); + if (arg.equals(name) || (alias != null && arg.equals(alias))) { + i.remove(); + value = consumeArgumentValue(type, argument, i); + if (!set) { + setProperty(type, property, target, value, delimiter); + } else { + addPropertyArgument(type, property, target, value, delimiter); + } + set = true; + } + if (set && !type.isArray()) break; + } + } + if (!set && argument.required()) { + String name = getName(argument, property); + throw new IllegalArgumentException("You must set argument " + name); + } + } + } + } + + /** + * Generate usage information based on the target annotations. + * + * @param target An instance or class. + */ + public static void usage(Object target) { + usage(System.err, target); + } + + /** + * Generate usage information based on the target annotations. + * + * @param errStream A {@link java.io.PrintStream} to print the usage information to. + * @param target An instance or class. + */ + public static void usage(PrintStream errStream, Object target) { + Class clazz; + if (target instanceof Class) { + clazz = (Class) target; + } else { + clazz = target.getClass(); + } + errStream.println("Usage: " + clazz.getName()); + for (Class currentClazz = clazz; currentClazz != null; currentClazz = currentClazz.getSuperclass()) { + for (Field field : currentClazz.getDeclaredFields()) { + fieldUsage(errStream, target, field); + } + } + try { + BeanInfo info = Introspector.getBeanInfo(clazz); + for (PropertyDescriptor pd : info.getPropertyDescriptors()) { + propertyUsage(errStream, target, pd); + } + } catch (IntrospectionException e) { + // If its not a JavaBean we ignore it + } + } + + private static void fieldUsage(PrintStream errStream, Object target, Field field) { + Argument argument = field.getAnnotation(Argument.class); + if (argument != null) { + String name = getName(argument, field); + String alias = getAlias(argument); + String prefix = argument.prefix(); + String delimiter = argument.delimiter(); + String description = argument.description(); + makeAccessible(field); + try { + Object defaultValue = field.get(target); + Class type = field.getType(); + propertyUsage(errStream, prefix, name, alias, type, delimiter, description, defaultValue); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Could not use thie field " + field + " as an argument field", e); + } + } + } + + private static void propertyUsage(PrintStream errStream, Object target, PropertyDescriptor field) { + Method writeMethod = field.getWriteMethod(); + if (writeMethod != null) { + Argument argument = writeMethod.getAnnotation(Argument.class); + if (argument != null) { + String name = getName(argument, field); + String alias = getAlias(argument); + String prefix = argument.prefix(); + String delimiter = argument.delimiter(); + String description = argument.description(); + try { + Method readMethod = field.getReadMethod(); + Object defaultValue; + if (readMethod == null) { + defaultValue = null; + } else { + defaultValue = readMethod.invoke(target, (Object[]) null); + } + Class type = field.getPropertyType(); + propertyUsage(errStream, prefix, name, alias, type, delimiter, description, defaultValue); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Could not use thie field " + field + " as an argument field", e); + } catch (InvocationTargetException e) { + throw new IllegalArgumentException("Could not get default value for " + field, e); + } + } + } + + } + + private static void propertyUsage(PrintStream errStream, String prefix, String name, String alias, Class type, String delimiter, String description, Object defaultValue) { + StringBuilder sb = new StringBuilder(" "); + sb.append(prefix); + sb.append(name); + if (alias != null) { + sb.append(" ("); + sb.append(prefix); + sb.append(alias); + sb.append(")"); + } + if (type == Boolean.TYPE || type == Boolean.class) { + sb.append(" [flag] "); + sb.append(description); + } else { + sb.append(" ["); + if (type.isArray()) { + String typeName = getTypeName(type.getComponentType()); + sb.append(typeName); + sb.append("["); + sb.append(delimiter); + sb.append("]"); + } else { + String typeName = getTypeName(type); + sb.append(typeName); + } + sb.append("] "); + sb.append(description); + if (defaultValue != null) { + sb.append(" ("); + if (type.isArray()) { + List list = new ArrayList(); + int len = Array.getLength(defaultValue); + for (int i = 0; i < len; i++) { + list.add(Array.get(defaultValue, i)); + } + sb.append(list); + } else { + sb.append(defaultValue); + } + sb.append(")"); + } + + } + errStream.println(sb); + } + + private static String getTypeName(Class type) { + String typeName = type.getName(); + int beginIndex = typeName.lastIndexOf("."); + typeName = typeName.substring(beginIndex + 1); + return typeName; + } + + static String getName(Argument argument, PropertyDescriptor property) { + String name = argument.value(); + if (name.equals("")) { + name = property.getName(); + } + return name; + + } + + private static Object consumeArgumentValue(Class type, Argument argument, Iterator i) { + Object value; + if (type == Boolean.TYPE || type == Boolean.class) { + value = true; + } else { + if (i.hasNext()) { + value = i.next(); + i.remove(); + } else { + throw new IllegalArgumentException("Must have a value for non-boolean argument " + argument.value()); + } + } + return value; + } + + static void setProperty(Class type, PropertyDescriptor property, Object target, Object value, String delimiter) { + try { + value = getValue(type, value, delimiter); + property.getWriteMethod().invoke(target, value); + } catch (IllegalAccessException iae) { + throw new IllegalArgumentException("Could not set property " + property, iae); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e); + } catch (InvocationTargetException e) { + throw new IllegalArgumentException("Failed to validate argument " + value + " for " + property); + } + } + + static String getAlias(Argument argument) { + String alias = argument.alias(); + if (alias.equals("")) { + alias = null; + } + return alias; + } + + static String getName(Argument argument, Field field) { + String name = argument.value(); + if (name.equals("")) { + name = field.getName(); + } + return name; + } + + static void setField(Class type, Field field, Object target, Object value, String delimiter) { + makeAccessible(field); + try { + value = getValue(type, value, delimiter); + field.set(target, value); + } catch (IllegalAccessException iae) { + throw new IllegalArgumentException("Could not set field " + field, iae); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException("Could not find constructor in class " + type.getName() + " that takes a string", e); + } + } + + private static Object getValue(Class type, Object value, String delimiter) throws NoSuchMethodException { + if (type != String.class && type != Boolean.class && type != Boolean.TYPE) { + String string = (String) value; + if (type.isArray()) { + String[] strings = string.split(delimiter); + type = type.getComponentType(); + if (type == String.class) { + value = strings; + } else { + Object[] array = (Object[]) Array.newInstance(type, strings.length); + for (int i = 0; i < array.length; i++) { + array[i] = createValue(type, strings[i]); + } + value = array; + } + } else { + value = createValue(type, string); + } + } + return value; + } + + private static Object createValue(Class type, String valueAsString) throws NoSuchMethodException { + for (ValueCreator valueCreator : valueCreators) { + Object createdValue = valueCreator.createValue(type, valueAsString); + if (createdValue != null) { + return createdValue; + } + } + throw new IllegalArgumentException(String.format("cannot instanciate any %s object using %s value", type.toString(), valueAsString)); + } + + private static void makeAccessible(AccessibleObject ao) { + if (ao instanceof Member) { + Member member = (Member) ao; + if (!Modifier.isPublic(member.getModifiers())) { + ao.setAccessible(true); + } + } + } + + /** + * Creates a {@link ValueCreator} object able to create object assignable from given type, + * using a static one arg method which name is the the given one taking a String object as parameter + * + * @param compatibleType the base assignable for which this object will try to invoke the given method + * @param methodName the name of the one arg method taking a String as parameter that will be used to built a new value + * @return null if the object could not be created, the value otherwise + */ + public static ValueCreator byStaticMethodInvocation(final Class compatibleType, final String methodName) { + return new ValueCreator() { + public Object createValue(Class type, String value) { + Object v = null; + if (compatibleType.isAssignableFrom(type)) { + try { + Method m = type.getMethod(methodName, String.class); + return m.invoke(null, value); + } catch (NoSuchMethodException e) { + // ignore + } catch (Exception e) { + throw new IllegalArgumentException(String.format("could not invoke %s#%s to create an obejct from %s", type.toString(), methodName, value)); + } + } + return v; + } + }; + } + + /** + * Allows external extension of the valiue creators. + * + * @param vc another value creator to take into account for trying to create values + */ + public static void registerValueCreator(ValueCreator vc) { + valueCreators.add(vc); + } + + /** + * Cleanup of registered ValueCreators (mainly for tests) + */ + public static void resetValueCreators() { + valueCreators.clear(); + valueCreators.addAll(DEFAULT_VALUE_CREATORS); + } + + public static interface ValueCreator { + /** + * Creates a value object of the given type using the given string value representation; + * + * @param type the type to create an instance of + * @param value the string represented value of the object to create + * @return null if the object could not be created, the value otherwise + */ + public Object createValue(Class type, String value); + } +} diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Argument.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Argument.java new file mode 100644 index 00000000000..2149455966a --- /dev/null +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/Argument.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2005, Sam Pullara. All Rights Reserved. + * You may modify and redistribute as long as this attribution remains. + */ + +package org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface Argument { + /** + * This is the actual command line argument itself + */ + String value() default ""; + /** + * If this is true, then the argument must be set or the parse will fail + */ + boolean required() default false; + + /** + * This is the prefix expected for the argument + */ + String prefix() default "-"; + /** + * Each argument can have an alias + */ + String alias() default ""; + /** + * A description of the argument that will appear in the usage method + */ + String description() default ""; + + /** + * A delimiter for arguments that are multi-valued. + */ + String delimiter() default ","; +} diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/PropertiesArgs.java b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/PropertiesArgs.java new file mode 100644 index 00000000000..7816feb3776 --- /dev/null +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/parser/com/sampullara/cli/PropertiesArgs.java @@ -0,0 +1,111 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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.jetbrains.kotlin.cli.common.parser.com.sampullara.cli; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Properties; + +/** + * Created by IntelliJ IDEA. + *

+ * User: samp + * Date: Nov 11, 2007 + * Time: 3:42:27 PM + */ +public class PropertiesArgs { + /** + * Parse properties instead of String arguments. Any additional arguments need to be passed some other way. + * This is often used in a second pass when the property filename is passed on the command line. Because of + * required properties you must be careful to set them all in the property file. + * + * @param target Either an instance or a class + * @param arguments The properties that contain the arguments + */ + public static void parse(Object target, Properties arguments) { + Class clazz; + if (target instanceof Class) { + clazz = (Class) target; + } else { + clazz = target.getClass(); + } + for (Field field : clazz.getDeclaredFields()) { + processField(target, field, arguments); + } + try { + BeanInfo info = Introspector.getBeanInfo(clazz); + for (PropertyDescriptor pd : info.getPropertyDescriptors()) { + processProperty(target, pd, arguments); + } + } catch (IntrospectionException e) { + // If its not a JavaBean we ignore it + } + } + + private static void processField(Object target, Field field, Properties arguments) { + Argument argument = field.getAnnotation(Argument.class); + if (argument != null) { + String name = Args.getName(argument, field); + String alias = Args.getAlias(argument); + Class type = field.getType(); + Object value = arguments.get(name); + if (value == null && alias != null) { + value = arguments.get(alias); + } + if (value != null) { + if (type == Boolean.TYPE || type == Boolean.class) { + value = true; + } + Args.setField(type, field, target, value, argument.delimiter()); + } else { + if (argument.required()) { + throw new IllegalArgumentException("You must set argument " + name); + } + } + } + } + + private static void processProperty(Object target, PropertyDescriptor property, Properties arguments) { + Method writeMethod = property.getWriteMethod(); + if (writeMethod != null) { + Argument argument = writeMethod.getAnnotation(Argument.class); + if (argument != null) { + String name = Args.getName(argument, property); + String alias = Args.getAlias(argument); + Object value = arguments.get(name); + if (value == null && alias != null) { + value = arguments.get(alias); + } + if (value != null) { + Class type = property.getPropertyType(); + if (type == Boolean.TYPE || type == Boolean.class) { + value = true; + } + Args.setProperty(type, property, target, value, argument.delimiter()); + } else { + if (argument.required()) { + throw new IllegalArgumentException("You must set argument " + name); + } + } + } + } + } +} diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java b/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java index 53da3338202..ceb1ca6212d 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/common/Usage.java @@ -16,11 +16,11 @@ package org.jetbrains.kotlin.cli.common; -import com.sampullara.cli.Argument; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments; import org.jetbrains.kotlin.cli.common.arguments.ValueDescription; +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument; import java.io.PrintStream; import java.lang.reflect.Field; diff --git a/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt b/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt index 438256e0360..4aa2db321c1 100644 --- a/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt +++ b/generators/src/org/jetbrains/kotlin/generators/arguments/GenerateGradleOptions.kt @@ -16,8 +16,8 @@ package org.jetbrains.kotlin.generators.arguments -import com.sampullara.cli.Argument import org.jetbrains.kotlin.cli.common.arguments.* +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.utils.Printer import java.io.File diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/Platform.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/Platform.kt index 641a7714403..34dc21ef87a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/Platform.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/Platform.kt @@ -22,9 +22,9 @@ import com.intellij.openapi.module.ModuleUtilCore import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ProjectFileIndex -import com.sampullara.cli.Argument import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder diff --git a/idea/idea-maven/idea-maven.iml b/idea/idea-maven/idea-maven.iml index 6c9da6cf829..0f939d887d9 100644 --- a/idea/idea-maven/idea-maven.iml +++ b/idea/idea-maven/idea-maven.iml @@ -9,7 +9,6 @@ - diff --git a/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiModuleTest.kt b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiModuleTest.kt index 74a9d4f679c..0627121727d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiModuleTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/stubs/AbstractMultiModuleTest.kt @@ -27,8 +27,8 @@ import com.intellij.openapi.roots.ModuleRootModificationUtil import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.testFramework.PsiTestUtil -import com.sampullara.cli.Argument import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.cli.common.parser.com.sampullara.cli.Argument import org.jetbrains.kotlin.config.CompilerSettings import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider import org.jetbrains.kotlin.config.TargetPlatformKind diff --git a/jps-plugin/jps-plugin.iml b/jps-plugin/jps-plugin.iml index f5fcf5cec86..59e6dad560b 100644 --- a/jps-plugin/jps-plugin.iml +++ b/jps-plugin/jps-plugin.iml @@ -21,6 +21,5 @@ - \ No newline at end of file diff --git a/update_dependencies.xml b/update_dependencies.xml index 1a3d0c67119..1ebd5424dbf 100644 --- a/update_dependencies.xml +++ b/update_dependencies.xml @@ -1,4 +1,4 @@ - + @@ -227,9 +227,6 @@ - - -