All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.palantir.javaformat.java.CommandLineOptionsParser Maven / Gradle / Ivy

There is a newer version: 2.50.0
Show newest version
/*
 * Copyright 2016 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.palantir.javaformat.java;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.base.CharMatcher;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.Range;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nullable;

/** A parser for {@link CommandLineOptions}. */
final class CommandLineOptionsParser {

    private static final Splitter COMMA_SPLITTER = Splitter.on(',');
    private static final Splitter COLON_SPLITTER = Splitter.on(':');
    private static final Splitter ARG_SPLITTER =
            Splitter.on(CharMatcher.breakingWhitespace()).omitEmptyStrings().trimResults();

    /** Parses {@link CommandLineOptions}. */
    static CommandLineOptions parse(Iterable options) {
        CommandLineOptions.Builder optionsBuilder = CommandLineOptions.builder();
        List expandedOptions = new ArrayList<>();
        expandParamsFiles(options, expandedOptions);
        Iterator it = expandedOptions.iterator();
        while (it.hasNext()) {
            String option = it.next();
            if (!option.startsWith("-")) {
                optionsBuilder.filesBuilder().add(option).addAll(it);
                break;
            }
            String flag;
            @Nullable String value;
            int idx = option.indexOf('=');
            if (idx >= 0) {
                flag = option.substring(0, idx);
                value = option.substring(idx + 1, option.length());
            } else {
                flag = option;
                value = null;
            }
            // NOTE: update usage information in UsageException when new flags are added
            switch (flag) {
                case "-i":
                case "-r":
                case "-replace":
                case "--replace":
                    optionsBuilder.inPlace(true);
                    break;
                case "--lines":
                case "-lines":
                case "--line":
                case "-line":
                    parseRangeSet(optionsBuilder.linesBuilder(), getValue(flag, it, value));
                    break;
                case "--character-ranges":
                case "-character-ranges":
                case "--character-range":
                case "-character-range":
                    parseRangeSet(optionsBuilder.characterRangesBuilder(), getValue(flag, it, value));
                    break;
                case "--offset":
                case "-offset":
                    optionsBuilder.addOffset(parseInteger(it, flag, value));
                    break;
                case "--length":
                case "-length":
                    optionsBuilder.addLength(parseInteger(it, flag, value));
                    break;
                case "--aosp":
                case "-aosp":
                case "-a":
                    optionsBuilder.aosp(true);
                    break;
                case "--palantir":
                case "-palantir":
                    optionsBuilder.palantirStyle(true);
                    break;
                case "--version":
                case "-version":
                case "-v":
                    optionsBuilder.version(true);
                    break;
                case "--help":
                case "-help":
                case "-h":
                    optionsBuilder.help(true);
                    break;
                case "--fix-imports-only":
                    optionsBuilder.fixImportsOnly(true);
                    break;
                case "--skip-sorting-imports":
                    optionsBuilder.sortImports(false);
                    break;
                case "--skip-removing-unused-imports":
                    optionsBuilder.removeUnusedImports(false);
                    break;
                case "--skip-reflowing-long-strings":
                    optionsBuilder.reflowLongStrings(false);
                    break;
                case "-":
                    optionsBuilder.stdin(true);
                    break;
                case "-n":
                case "--dry-run":
                    optionsBuilder.dryRun(true);
                    break;
                case "--set-exit-if-changed":
                    optionsBuilder.setExitIfChanged(true);
                    break;
                case "-assume-filename":
                case "--assume-filename":
                    optionsBuilder.assumeFilename(getValue(flag, it, value));
                    break;
                case "-output-replacements":
                case "--output-replacements":
                    optionsBuilder.outputReplacements(true);
                    break;
                default:
                    throw new IllegalArgumentException("unexpected flag: " + flag);
            }
        }
        return optionsBuilder.build();
    }

    private static Integer parseInteger(Iterator it, String flag, String value) {
        try {
            return Integer.valueOf(getValue(flag, it, value));
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException(String.format("invalid integer value for %s: %s", flag, value), e);
        }
    }

    private static String getValue(String flag, Iterator it, @Nullable String value) {
        if (value != null) {
            return value;
        }
        if (!it.hasNext()) {
            throw new IllegalArgumentException("required value was not provided for: " + flag);
        }
        return it.next();
    }

    /**
     * Parse multiple --lines flags, like {"1:12,14,20:36", "40:45,50"}. Multiple ranges can be given with multiple
     * --lines flags or separated by commas. A single line can be set by a single number. Line numbers are
     * {@code 1}-based, but are converted to the {@code 0}-based numbering used internally by google-java-format.
     */
    private static void parseRangeSet(ImmutableRangeSet.Builder result, String ranges) {
        for (String range : COMMA_SPLITTER.split(ranges)) {
            result.add(parseRange(range));
        }
    }

    /**
     * Parse a range, as in "1:12" or "42". Line numbers provided are {@code 1}-based, but are converted here to
     * {@code 0}-based.
     */
    private static Range parseRange(String arg) {
        List args = COLON_SPLITTER.splitToList(arg);
        switch (args.size()) {
            case 1:
                int line = Integer.parseInt(args.get(0)) - 1;
                return Range.closedOpen(line, line + 1);
            case 2:
                int line0 = Integer.parseInt(args.get(0)) - 1;
                int line1 = Integer.parseInt(args.get(1)) - 1;
                return Range.closedOpen(line0, line1 + 1);
            default:
                throw new IllegalArgumentException(arg);
        }
    }

    /**
     * Pre-processes an argument list, expanding arguments of the form {@code @filename} by reading the content of the
     * file and appending whitespace-delimited options to {@code arguments}.
     */
    private static void expandParamsFiles(Iterable args, List expanded) {
        for (String arg : args) {
            if (arg.isEmpty()) {
                continue;
            }
            if (!arg.startsWith("@")) {
                expanded.add(arg);
            } else if (arg.startsWith("@@")) {
                expanded.add(arg.substring(1));
            } else {
                Path path = Paths.get(arg.substring(1));
                try {
                    String sequence = new String(Files.readAllBytes(path), UTF_8);
                    expandParamsFiles(ARG_SPLITTER.split(sequence), expanded);
                } catch (IOException e) {
                    throw new UncheckedIOException(path + ": could not read file: " + e.getMessage(), e);
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy