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 @@ - - -