org.netbeans.api.sendopts.CommandLine Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.netbeans.api.sendopts;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.MessageFormat;
import java.util.*;
import org.netbeans.modules.sendopts.DefaultProcessor;
import org.netbeans.modules.sendopts.OptionImpl;
import org.netbeans.spi.sendopts.Env;
import org.netbeans.spi.sendopts.Option;
import org.netbeans.spi.sendopts.OptionProcessor;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
/**
* A class for clients that have an array of strings and want to process
* it - e.g. parse it and also invoke associated {@link OptionProcessor}s
* and {@link org.netbeans.spi.sendopts.Arg declarative options}.
*
* @author Jaroslav Tulach
*/
public final class CommandLine {
/** internal errors of CommandLine start here and end here + 100 */
private static final int ERROR_BASE = 50345;
/** associated options providers */
private final Collection extends OptionProcessor> processors;
/** Use factory methods to create the line. */
CommandLine(Collection extends OptionProcessor> p) {
this.processors = p;
}
/** Getter for the default command line processor in the system. List
* of {@link OptionProcessor}s is taken from default
* {@link Lookup#getDefault() }.
*/
public static CommandLine getDefault() {
return new CommandLine(null);
}
/** Creates new command line processor based on options defined in
* the provided classes
. These classes are scanned for
* fields annotated with {@code @}{@link org.netbeans.spi.sendopts.Arg}
* annotation or (since version 2.37) checked whether they implement
* {@link org.netbeans.spi.sendopts.OptionProcessor @OptionProcessor}.
*
* @param classes classes that declare the options
* @return new command line object that contains options declared in the
* provided classes
* @since 2.20
*/
public static CommandLine create(Class>... classes) {
return createImpl(classes);
}
/** Creates new command line processor based on options defined in
* the provided objects
. The objects can implement
* the {@link org.netbeans.spi.sendopts.OptionProcessor processor}
* interface or (if they don't) their classes are scanned
* for fields annotated with {@code @}{@link org.netbeans.spi.sendopts.Arg}
* annotation. Alternatively one can register {@link Class} instances with
* default constructor - such classes will be instantiated and then
* processed as described above.
*
* @param instances objects that declare the command line options
* @return new command line object that contains options declared in the
* provided classes
* @since 2.37
*/
public static CommandLine create(Object... instances) {
return createImpl(instances);
}
private static CommandLine createImpl(Object[] instances) {
List arr = new ArrayList<>();
for (Object o : instances) {
Class> c;
Object instance;
if (o instanceof Class>) {
c = (Class>)o;
instance = null;
} else {
c = o.getClass();
instance = o;
}
if (OptionProcessor.class.isAssignableFrom(c)) {
try {
if (instance == null) {
instance = c.getDeclaredConstructor().newInstance();
}
arr.add((OptionProcessor) instance);
} catch (ReflectiveOperationException ex) {
throw new IllegalStateException(ex);
}
} else {
arr.add(DefaultProcessor.create(c, instance));
}
}
return new CommandLine(arr);
}
/** Process the array of arguments and invoke associated {@link OptionProcessor}s.
*
* @param args the array of strings to process
* @exception CommandException if processing is not possible or failed
*/
public void process(String... args) throws CommandException {
process(args, null, null, null, null);
}
/** Process the array of arguments and invoke associated {@link OptionProcessor}s.
*
* @param args the array of strings to process
* @param is the input stream that processors can read
* @param os the output stream that processors can write to
* @param err the output stream that processors can send error messages to
* @param currentDir directory that processors should use as current user dir
* @exception CommandException if processing is not possible or failed
*/
public void process(String[] args, InputStream is, OutputStream os, OutputStream err, File currentDir) throws CommandException {
if (is == null) {
is = System.in;
}
if (os == null) {
os = System.out;
}
if (err == null) {
err = System.err;
}
if (currentDir == null) {
currentDir = new File(System.getProperty("user.dir")); // NOI18N
}
Env env = OptionImpl.Trampoline.DEFAULT.create(this, is, os, err, currentDir);
ArrayList additionalParams = new ArrayList();
ArrayList opts = new ArrayList();
OptionImpl acceptsAdons = null;
OptionImpl[] mainOptions = getOptions();
LinkedHashSet allOptions = new LinkedHashSet();
for (int i = 0; i < mainOptions.length; i++) {
mainOptions[i] = mainOptions[i].addWorkingCopy(allOptions);
}
OptionImpl[] arr = allOptions.toArray(new OptionImpl[0]);
boolean optionMode = true;
ARGS: for (int i = 0; i < args.length; i++) {
if (args[i] == null) {
continue ARGS;
}
if (optionMode) {
if (args[i].startsWith("--")) { //NOI18N
if (args[i].length() == 2) {
optionMode = false;
continue ARGS;
}
String text = args[i].substring(2);
String value = null;
int textEqual = text.indexOf('=');
if (textEqual >= 0) {
// strip the name of the option
value = text.substring(textEqual + 1);
text = text.substring(0, textEqual);
}
OptionImpl opt = findByLongName (text, arr);
if (opt == null) {
throw new CommandException(args[i], ERROR_BASE + 1,
getMessage("MSG_Unknown", args[i])
);
}
if (opt.getArgumentType() == 1 && value == null) {
// read next value from the argument
for(;;) {
if (++i == args.length) {
throw new CommandException(getMessage("MSG_MissingArgument", "--" + opt.getLongName()), ERROR_BASE + 2); // NOI18N
}
if (args[i].equals("--")) { //NOI18N
optionMode = false;
continue;
}
if (optionMode && args[i].startsWith("-")) { //NOI18N
throw new CommandException(getMessage("MSG_MissingArgument", "--" + opt.getLongName()), ERROR_BASE + 2); // NOI18N
}
break;
}
value = args[i];
}
if (value != null) {
if (opt.getArgumentType() != 1 && opt.getArgumentType() != 2) {
throw new CommandException(getMessage("MSG_OPTION_CANNOT_HAVE_VALUE", opt, value), ERROR_BASE + 2);
}
opt.associateValue(value);
}
if (opt.getArgumentType() == 3) {
if (acceptsAdons != null) {
String oName1 = findOptionName(acceptsAdons, args);
String oName2 = findOptionName(opt, args);
String msg = getMessage("MSG_CannotTogether", oName1, oName2); // NOI18N
throw new CommandException(msg, ERROR_BASE + 3);
}
acceptsAdons = opt;
}
opts.add(opt);
continue ARGS;
} else if (args[i].startsWith("-") && args[i].length() > 1) { //NOI18N
for (int j = 1; j < args[i].length(); j++) {
char ch = args[i].charAt(j);
OptionImpl opt = findByShortName(ch, arr);
if (opt == null) {
throw new CommandException(getMessage("MSG_UNKNOWN_OPTION", args[i]), ERROR_BASE + 1);
}
if (args[i].length() == j + 1 && opt.getArgumentType() == 1) {
throw new CommandException(getMessage("MSG_MissingArgument", args[i]), ERROR_BASE + 2);
}
if (args[i].length() > j && (opt.getArgumentType() == 1 || opt.getArgumentType() == 2)) {
opt.associateValue(args[i].substring(j + 1));
j = args[i].length();
}
if (opt.getArgumentType() == 3) {
if (acceptsAdons != null) {
String oName1 = findOptionName(acceptsAdons, args);
String oName2 = findOptionName(opt, args);
String msg = getMessage("MSG_CannotTogether", oName1, oName2); // NOI18N
throw new CommandException(msg, ERROR_BASE + 3);
}
acceptsAdons = opt;
}
opts.add(opt);
}
continue ARGS;
}
}
additionalParams.add(args[i]);
}
if (acceptsAdons == null && !additionalParams.isEmpty()) {
for (int i = 0; i < arr.length; i++) {
if (arr[i].getArgumentType() == 4) {
if (acceptsAdons != null) {
throw new CommandException(getMessage("MSG_TWO_DEFAULT_OPTIONS", acceptsAdons, arr[i]), ERROR_BASE + 3);
}
acceptsAdons = arr[i];
opts.add(acceptsAdons);
}
}
if (acceptsAdons == null) {
throw new CommandException(getMessage("MSG_NOT_PROCESSED_PARAMS", additionalParams), ERROR_BASE + 2);
}
}
OptionImpl.Appearance[] postProcess = new OptionImpl.Appearance[mainOptions.length];
{
HashSet used = new HashSet(opts);
for (int i = 0; i < mainOptions.length; i++) {
OptionImpl.Appearance res = mainOptions[i].checkConsistent(used);
postProcess[i] = res;
if (res.isThere()) {
mainOptions[i].markConsistent(res);
}
/*
if (res.isError()) {
throw new CommandException(res.errorMessage(args), ERROR_BASE + 4);
}
*/
}
}
{
HashSet used = new HashSet(opts);
for (int i = 0; i < mainOptions.length; i++) {
if (postProcess[i].isError()) {
OptionImpl error = mainOptions[i].findNotUsedOption(used);
if (error != null) {
throw new CommandException(postProcess[i].errorMessage(args), ERROR_BASE + 4);
}
}
}
}
Map> providers = new LinkedHashMap>();
{
for (int i = 0; i < mainOptions.length; i++) {
if (postProcess[i].isThere()) {
Map
© 2015 - 2025 Weber Informatics LLC | Privacy Policy