|
18 | 18 | import com.rabbitmq.stream.StreamCreator.LeaderLocator;
|
19 | 19 | import com.rabbitmq.stream.compression.Compression;
|
20 | 20 | import com.sun.management.OperatingSystemMXBean;
|
| 21 | +import java.lang.reflect.Constructor; |
| 22 | +import java.lang.reflect.Field; |
21 | 23 | import java.lang.reflect.Method;
|
22 | 24 | import java.security.cert.X509Certificate;
|
23 | 25 | import java.text.CharacterIterator;
|
|
27 | 29 | import java.time.format.DateTimeFormatter;
|
28 | 30 | import java.time.format.DateTimeParseException;
|
29 | 31 | import java.time.temporal.TemporalAccessor;
|
| 32 | +import java.util.ArrayList; |
30 | 33 | import java.util.Arrays;
|
| 34 | +import java.util.Collection; |
31 | 35 | import java.util.Collections;
|
| 36 | +import java.util.Comparator; |
32 | 37 | import java.util.HashMap;
|
33 | 38 | import java.util.List;
|
34 | 39 | import java.util.Locale;
|
|
38 | 43 | import java.util.concurrent.ThreadFactory;
|
39 | 44 | import java.util.concurrent.atomic.AtomicLong;
|
40 | 45 | import java.util.function.BiFunction;
|
| 46 | +import java.util.function.Function; |
41 | 47 | import java.util.function.LongSupplier;
|
42 | 48 | import java.util.stream.Collectors;
|
43 | 49 | import java.util.stream.IntStream;
|
|
47 | 53 | import org.slf4j.Logger;
|
48 | 54 | import org.slf4j.LoggerFactory;
|
49 | 55 | import picocli.CommandLine;
|
| 56 | +import picocli.CommandLine.Command; |
50 | 57 | import picocli.CommandLine.ITypeConverter;
|
| 58 | +import picocli.CommandLine.Model.CommandSpec; |
| 59 | +import picocli.CommandLine.Model.OptionSpec; |
| 60 | +import picocli.CommandLine.Option; |
51 | 61 |
|
52 | 62 | class Utils {
|
53 | 63 |
|
54 | 64 | static final X509TrustManager TRUST_EVERYTHING_TRUST_MANAGER = new TrustEverythingTrustManager();
|
| 65 | + static final Function<String, String> OPTION_TO_ENVIRONMENT_VARIABLE = |
| 66 | + option -> { |
| 67 | + if (option.startsWith("--")) { |
| 68 | + return option.replace("--", "").replace('-', '_').toUpperCase(Locale.ENGLISH); |
| 69 | + } else if (option.startsWith("-")) { |
| 70 | + return option.substring(1).replace('-', '_').toUpperCase(Locale.ENGLISH); |
| 71 | + } else { |
| 72 | + return option.replace('-', '_').toUpperCase(Locale.ENGLISH); |
| 73 | + } |
| 74 | + }; |
| 75 | + static final Function<String, String> ENVIRONMENT_VARIABLE_PREFIX = |
| 76 | + name -> { |
| 77 | + String prefix = System.getenv("RABBITMQ_STREAM_PERF_TEST_ENV_PREFIX"); |
| 78 | + if (prefix == null || prefix.trim().isEmpty()) { |
| 79 | + return name; |
| 80 | + } |
| 81 | + if (prefix.endsWith("_")) { |
| 82 | + return prefix + name; |
| 83 | + } else { |
| 84 | + return prefix + "_" + name; |
| 85 | + } |
| 86 | + }; |
| 87 | + static final Function<String, String> ENVIRONMENT_VARIABLE_LOOKUP = name -> System.getenv(name); |
55 | 88 | private static final LongSupplier TOTAL_MEMORY_SIZE_SUPPLIER;
|
56 | 89 | private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class);
|
57 | 90 | private static final String RANGE_SEPARATOR_1 = "-";
|
@@ -166,6 +199,85 @@ private static void throwConversionException(String format, String... arguments)
|
166 | 199 | throw new CommandLine.TypeConversionException(String.format(format, (Object[]) arguments));
|
167 | 200 | }
|
168 | 201 |
|
| 202 | + static void assignValuesToCommand(Object command, Function<String, String> optionMapping) |
| 203 | + throws Exception { |
| 204 | + LOGGER.debug("Assigning values to command {}", command.getClass()); |
| 205 | + Collection<String> arguments = new ArrayList<>(); |
| 206 | + Collection<Field> fieldsToAssign = new ArrayList<>(); |
| 207 | + for (Field field : command.getClass().getDeclaredFields()) { |
| 208 | + Option option = field.getAnnotation(Option.class); |
| 209 | + if (option == null) { |
| 210 | + LOGGER.debug("No option annotation for field {}", field.getName()); |
| 211 | + continue; |
| 212 | + } |
| 213 | + String longOption = |
| 214 | + Arrays.stream(option.names()) |
| 215 | + .sorted(Comparator.comparingInt(String::length).reversed()) |
| 216 | + .findFirst() |
| 217 | + .get(); |
| 218 | + LOGGER.debug("Looking up new value for option {}", longOption); |
| 219 | + String newValue = optionMapping.apply(longOption); |
| 220 | + |
| 221 | + LOGGER.debug( |
| 222 | + "New value found for option {} (field {}): {}", longOption, field.getName(), newValue); |
| 223 | + if (newValue == null) { |
| 224 | + continue; |
| 225 | + } |
| 226 | + fieldsToAssign.add(field); |
| 227 | + if (field.getType().equals(boolean.class) || field.getType().equals(Boolean.class)) { |
| 228 | + if (Boolean.parseBoolean(newValue)) { |
| 229 | + arguments.add(longOption); |
| 230 | + } |
| 231 | + } else { |
| 232 | + arguments.add(longOption + " " + newValue); |
| 233 | + } |
| 234 | + } |
| 235 | + if (fieldsToAssign.size() > 0) { |
| 236 | + Constructor<?> defaultConstructor = command.getClass().getConstructor(); |
| 237 | + Object commandBuffer = defaultConstructor.newInstance(); |
| 238 | + String argumentsLine = String.join(" ", arguments); |
| 239 | + LOGGER.debug("Arguments line with extra values: {}", argumentsLine); |
| 240 | + String[] args = argumentsLine.split(" "); |
| 241 | + commandBuffer = CommandLine.populateCommand(commandBuffer, args); |
| 242 | + for (Field field : fieldsToAssign) { |
| 243 | + field.setAccessible(true); |
| 244 | + field.set(command, field.get(commandBuffer)); |
| 245 | + } |
| 246 | + } |
| 247 | + } |
| 248 | + |
| 249 | + static CommandSpec buildCommandSpec(Object... commands) { |
| 250 | + Object mainCommand = commands[0]; |
| 251 | + Command commandAnnotation = mainCommand.getClass().getAnnotation(Command.class); |
| 252 | + CommandSpec spec = CommandSpec.create(); |
| 253 | + spec.name(commandAnnotation.name()); |
| 254 | + spec.mixinStandardHelpOptions(commandAnnotation.mixinStandardHelpOptions()); |
| 255 | + for (Object command : commands) { |
| 256 | + for (Field f : command.getClass().getDeclaredFields()) { |
| 257 | + Option annotation = f.getAnnotation(Option.class); |
| 258 | + if (annotation == null) { |
| 259 | + continue; |
| 260 | + } |
| 261 | + String name = |
| 262 | + Arrays.stream(annotation.names()) |
| 263 | + .sorted(Comparator.comparingInt(String::length).reversed()) |
| 264 | + .findFirst() |
| 265 | + .map(OPTION_TO_ENVIRONMENT_VARIABLE::apply) |
| 266 | + .get(); |
| 267 | + spec.addOption( |
| 268 | + OptionSpec.builder(name) |
| 269 | + .type(f.getType()) |
| 270 | + .description(annotation.description()) |
| 271 | + .paramLabel("<" + name.replace("_", "-") + ">") |
| 272 | + .defaultValue(annotation.defaultValue()) |
| 273 | + .showDefaultValue(annotation.showDefaultValue()) |
| 274 | + .build()); |
| 275 | + } |
| 276 | + } |
| 277 | + |
| 278 | + return spec; |
| 279 | + } |
| 280 | + |
169 | 281 | static class ByteCapacityTypeConverter implements CommandLine.ITypeConverter<ByteCapacity> {
|
170 | 282 |
|
171 | 283 | @Override
|
|
0 commit comments