| /* |
| * 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.apache.openmeetings.cli; |
| |
| import java.io.PrintWriter; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| |
| import org.apache.commons.cli.HelpFormatter; |
| import org.apache.commons.cli.Option; |
| import org.apache.commons.cli.OptionGroup; |
| import org.apache.commons.cli.Options; |
| |
| public class OmHelpFormatter extends HelpFormatter { |
| private static String GENERAL_OPTION_GROUP = ""; |
| private int maxPrefixLength = 0; |
| |
| @SuppressWarnings("unchecked") |
| private List<OmOption> getReqOptions(Options opts) { |
| //suppose we have only 1 group (for now) |
| OptionGroup g = ((List<OptionGroup>)opts.getRequiredOptions()).get(0); |
| List<OmOption> result = new ArrayList<OmOption>(g.getOptions()); |
| Collections.sort(result, new Comparator<OmOption>() { |
| public int compare(OmOption o1, OmOption o2) { |
| return o1.getOrder() - o2.getOrder(); |
| } |
| }); |
| return result; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private LinkedHashMap<String, List<OmOption>> getOptions(Options opts, int leftPad) { |
| final String longOptSeparator = " "; |
| final String lpad = createPadding(leftPad); |
| final String lpadParam = createPadding(leftPad + 2); |
| List<OmOption> reqOptions = getReqOptions(opts); |
| LinkedHashMap<String, List<OmOption>> map = new LinkedHashMap<String, List<OmOption>>(reqOptions.size()); |
| map.put(GENERAL_OPTION_GROUP, new ArrayList<OmOption>()); |
| for (OmOption o : reqOptions) { |
| map.put(o.getOpt(), new ArrayList<OmOption>()); |
| } |
| for (OmOption o : (Collection<OmOption>)opts.getOptions()) { |
| //TODO need better check (required option should go first and should not be duplicated |
| boolean skipOption = map.containsKey(o.getOpt()); |
| boolean mainOption = skipOption || o.getGroup() == null; |
| |
| // first create list containing only <lpad>-a,--aaa where |
| // -a is opt and --aaa is long opt; in parallel look for |
| // the longest opt string this list will be then used to |
| // sort options ascending |
| StringBuilder optBuf = new StringBuilder(); |
| if (o.getOpt() == null) { |
| optBuf.append(mainOption ? lpad : lpadParam).append(" ").append(getLongOptPrefix()) |
| .append(o.getLongOpt()); |
| } else { |
| optBuf.append(mainOption ? lpad : lpadParam).append(getOptPrefix()) |
| .append(o.getOpt()); |
| |
| if (o.hasLongOpt()) { |
| optBuf.append(',').append(getLongOptPrefix()) |
| .append(o.getLongOpt()); |
| } |
| } |
| |
| if (o.hasArg()) { |
| String argName = o.getArgName(); |
| if (argName != null && argName.length() == 0) { |
| // if the option has a blank argname |
| optBuf.append(' '); |
| } else { |
| optBuf.append(o.hasLongOpt() ? longOptSeparator : " "); |
| optBuf.append("<") |
| .append(argName != null ? o.getArgName() |
| : getArgName()).append(">"); |
| } |
| } |
| |
| o.setHelpPrefix(optBuf); |
| maxPrefixLength = Math.max(optBuf.length(), maxPrefixLength); |
| |
| if (skipOption) { |
| //TODO need better check (required option should go first and should not be duplicated |
| continue; |
| } |
| String grp = o.getGroup(); |
| grp = grp == null ? GENERAL_OPTION_GROUP : grp; |
| String[] grps = grp.split(","); |
| for(String g : grps) { |
| map.get(g).add(o); |
| } |
| } |
| for (String _key : map.keySet()) { |
| final String key = _key; |
| List<OmOption> options = map.get(key); |
| Collections.sort(options, new Comparator<OmOption>(){ |
| public int compare(OmOption o1, OmOption o2) { |
| boolean o1opt = !o1.isOptional(key); |
| boolean o2opt = !o2.isOptional(key); |
| return (o1opt && o2opt || !o1opt && !o2opt) ? (o1.getOpt() == null ? 1 : -1) : (o1opt ? -1 : 1); |
| } |
| |
| }); |
| if (opts.hasOption(key)) { |
| options.add(0, (OmOption)opts.getOption(key)); |
| } |
| } |
| return map; |
| } |
| |
| private StringBuilder getReqOptionsString(Options opts) { |
| String delim = ""; |
| StringBuilder result = new StringBuilder(); |
| for (Option o : getReqOptions(opts)) { |
| result.append(delim).append("-").append(o.getOpt()); |
| delim = "|"; |
| } |
| return result; |
| } |
| |
| @Override |
| protected StringBuffer renderOptions(StringBuffer sb, int width, Options options, int leftPad, int descPad) { |
| final String dpad = createPadding(descPad); |
| final String optional = "(optional) "; |
| |
| LinkedHashMap<String, List<OmOption>> optList = getOptions(options, leftPad); |
| |
| char[] delimiter = new char[width - 2]; |
| Arrays.fill(delimiter, '-'); |
| |
| for (String key : optList.keySet()) { |
| if (GENERAL_OPTION_GROUP.equals(key)) { |
| sb.append("General options:").append(getNewLine()); |
| } |
| for (OmOption option : optList.get(key)) { |
| StringBuilder optBuf = new StringBuilder(option.getHelpPrefix()); |
| |
| if (optBuf.length() < maxPrefixLength) { |
| optBuf.append(createPadding(maxPrefixLength - optBuf.length())); |
| } |
| |
| optBuf.append(dpad); |
| |
| int nextLineTabStop = maxPrefixLength + descPad; |
| |
| if (option.isOptional(key)) { |
| optBuf.append(optional); |
| } |
| if (option.getDescription() != null) { |
| optBuf.append(option.getDescription()); |
| } |
| |
| renderWrappedText(sb, width, nextLineTabStop, optBuf.toString()); |
| |
| sb.append(getNewLine()); |
| } |
| sb.append(delimiter).append(getNewLine()); |
| } |
| return sb; |
| } |
| |
| @Override |
| public void printHelp(PrintWriter pw, int width, String cmdLineSyntax, |
| String header, Options options, int leftPad, int descPad, |
| String footer, boolean autoUsage) { |
| if ((cmdLineSyntax == null) || (cmdLineSyntax.length() == 0)) { |
| throw new IllegalArgumentException("cmdLineSyntax not provided"); |
| } |
| |
| printUsage(pw, width, cmdLineSyntax, options); |
| |
| if ((header != null) && (header.trim().length() > 0)) { |
| printWrapped(pw, width, header); |
| } |
| |
| printOptions(pw, width, options, leftPad, descPad); |
| |
| if ((footer != null) && (footer.trim().length() > 0)) { |
| printWrapped(pw, width, footer); |
| } |
| } |
| |
| public void printUsage(PrintWriter pw, int width, String app, Options opts) { |
| pw.println(String.format("usage: %1$s [%2$s] [options]", app, getReqOptionsString(opts))); |
| } |
| } |