Java tutorial
/* * Copyright (c) 2015 Google, Inc. * * 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 com.google.devtools.moe.client.options; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.devtools.moe.client.directives.Directives.SelectedDirective; import dagger.Provides; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.Nullable; import javax.inject.Qualifier; import javax.inject.Singleton; /** Dagger module to seed command-line arguments into the graph */ @dagger.Module public class OptionsModule { private String[] rawArgs; public OptionsModule(String[] args) { Preconditions.checkArgument(args.length > 0, OptionsModule.class.getSimpleName() + " requires a non-empty args list."); this.rawArgs = args; } @Provides @Nullable @Argument("config_file") static String configFile(String... args) { // TODO(cgruber) Migrate to JCommander, so we don't have to manually parse some of these. List<String> matchingArgs = ImmutableList.of("-c", "--config", "--config_file"); for (int i = 0; i < args.length; i++) { if (matchingArgs.contains(args[i])) { if ((i + 1) >= args.length) { throw new IllegalArgumentException("'" + args[i] + "' specified without a parameter"); } if (args[i + 1].startsWith("-")) { throw new IllegalArgumentException("'" + args[i] + "' is not followed by a path"); } return args[i + 1]; } // check for "--config=" style. for (String prefix : matchingArgs) { if (args[i].startsWith(prefix + "=")) { return args[i].substring(prefix.length() + 1); } } } // Some commands may not require config // TODO(cgruber) make this not-nullable when only config-requiring commands yank in the config. return null; } @Provides @SelectedDirective String selectedDirective() { return rawArgs[0]; } @Provides @Singleton // No need to parse arguments several times. String[] provideArgs() { return preProcessArgs(rawArgs); } /** * Preprocesses command line arguments to make them conform to args4j assumptions (for backwards * compability) and strip off the directive. */ private static String[] preProcessArgs(String[] unprocessedArgs) { List<String> args = new LinkedList<>(); Collections.addAll(args, unprocessedArgs); args.remove(0); // Remove the directive. // Args4j has a different format than the old command-line parser. // So we use some voodoo to get the args into the format that args4j // expects. Pattern argPattern = Pattern.compile("(--[a-zA-Z_]+)=(.*)"); // TODO(cgruber): Look at these patterns Pattern quotesPattern = Pattern.compile("^['\"](.*)['\"]$"); List<String> processedArgs = new ArrayList<>(args.size()); for (String arg : args) { Matcher matcher = argPattern.matcher(arg); if (matcher.matches()) { processedArgs.add(matcher.group(1)); String value = matcher.group(2); Matcher quotesMatcher = quotesPattern.matcher(value); if (quotesMatcher.matches()) { processedArgs.add(quotesMatcher.group(1)); } else { processedArgs.add(value); } } else { processedArgs.add(arg); } } return processedArgs.toArray(new String[args.size()]); } @Provides @Singleton @Flag("trace") static boolean traceFlagged(String... preprocessedArgs) { // Note, this is a stand-in to permit injection of this flag prior to the move to JCommander. // Ultimately this will be processed via the options parser instead of hand-parsed, but in the // short-term the global flags need to be pre-processed so we don't require parsing all of the // things before we even know what directive we're using, which args4j doesn't support. // TODO(cgruber): Don't parse this manually once JCommander has replaced args4j. return ImmutableSet.copyOf(preprocessedArgs).contains("--trace"); } /** * A JSR-330 {@link Qualifier} annotation to distinguish injected argument values from other * injected {@link String} values. */ @Qualifier public @interface Argument { String value(); } /** * A JSR-330 {@link Qualifier} annotation to distinguish injected flag values from other * injected {@link String} values. */ @Qualifier public @interface Flag { String value(); } }