CommonsCliValidateOptions.java
/*
* 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.maven.cling.invoker.mvnval;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.mvnval.ValidateOptions;
import org.apache.maven.cling.invoker.CommonsCliOptions;
/**
* Implementation of {@link ValidateOptions} (base + mvnval).
*/
public class CommonsCliValidateOptions extends CommonsCliOptions implements ValidateOptions {
/**
* Deliberately does not check {@code --format}. Throwing here marks the whole invocation as
* unparseable, and the CLI exits 1 before the tool runs, which contradicts the exit code the
* tool documents for bad usage. {@link ValidateInvoker} checks it instead, which also covers
* the value only becoming wrong once options are interpolated.
*/
public static CommonsCliValidateOptions parse(String[] args) throws ParseException {
CLIManager cliManager = new CLIManager();
return new CommonsCliValidateOptions(Options.SOURCE_CLI, cliManager, cliManager.parse(args));
}
protected CommonsCliValidateOptions(String source, CLIManager cliManager, CommandLine commandLine) {
super(source, cliManager, commandLine);
}
@Override
@Nonnull
public Optional<String> format() {
return Optional.ofNullable(commandLine.getOptionValue(CLIManager.FORMAT));
}
@Override
@Nonnull
public Optional<String> mode() {
return Optional.ofNullable(commandLine.getOptionValue(CLIManager.MODE));
}
@Override
@Nonnull
public Optional<String> localRepository() {
return Optional.ofNullable(commandLine.getOptionValue(CLIManager.LOCAL_REPOSITORY));
}
@Override
@Nonnull
public Optional<Boolean> tempLocalRepository() {
return commandLine.hasOption(CLIManager.TEMP_LOCAL_REPOSITORY) ? Optional.of(true) : Optional.empty();
}
@Override
@Nonnull
public Optional<Integer> context() {
String val = commandLine.getOptionValue(CLIManager.CONTEXT);
if (val == null) {
return Optional.empty();
}
try {
int n = Integer.parseInt(val);
if (n < 0) {
throw new IllegalArgumentException("--context value must be non-negative: " + val);
}
return Optional.of(n);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("--context value must be an integer: " + val);
}
}
@Override
@Nonnull
public Optional<List<String>> poms() {
if (commandLine.getArgList().isEmpty()) {
return Optional.empty();
}
return Optional.of(commandLine.getArgList());
}
@Override
public void displayHelp(ParserRequest request, Consumer<String> printStream) {
super.displayHelp(request, printStream);
printStream.accept("");
printStream.accept("Validates the given POM files, or ./pom.xml when none are given. No");
printStream.accept("build is run: the POMs are read and reported on, never written back.");
printStream.accept("");
printStream.accept("--mode raw reads the file and raw models only: it reaches no repository");
printStream.accept("and works offline, but it cannot see a dependency whose version is");
printStream.accept("inherited. --mode effective, the default, runs that and then resolves");
printStream.accept("parents and imported boms so the checks needing them run as well. That");
printStream.accept("goes to the network, to the repositories the settings declare and to");
printStream.accept("any the POM itself declares, caching what it fetches locally.");
printStream.accept("");
printStream.accept("A subproject is read when its parent needs it, and only the POMs named");
printStream.accept("on the command line are reported on, though a problem inherited from a");
printStream.accept("parent is reported against the POM that inherited it.");
printStream.accept("");
printStream.accept("--local-repository aims resolution at another local repository, and");
printStream.accept("--temp-local-repository at one created for the run and deleted when it");
printStream.accept("ends, so that validating a POM leaves the configured one untouched.");
printStream.accept("Without --local-repository, maven.repo.local is used as elsewhere.");
printStream.accept("Neither option changes what --mode raw does, since it resolves nothing.");
printStream.accept("");
printStream.accept("-o works in effective mode: resolution is limited to the local");
printStream.accept("repository and fails fast when a parent or BOM is absent there.");
printStream.accept("--temp-local-repository -o together prove that the named POMs are");
printStream.accept("fully self-contained: if any parent is missing the run fails.");
printStream.accept("");
printStream.accept("When more than one POM is given in effective mode, members of the set");
printStream.accept("that reference each other as parents or BOM imports are resolved from");
printStream.accept("disk rather than from a repository: the verdict does not depend on");
printStream.accept("publication order and the run does not download what is on disk.");
printStream.accept("");
printStream.accept("-s, -ps and -is are refused: they redirect the settings file that");
printStream.accept("resolution reads, and that file is read before this tool can act on");
printStream.accept("those flags.");
printStream.accept("");
printStream.accept("Exits with 0 when nothing was reported, 1 when anything was rejected,");
printStream.accept("2 on bad usage, and 4 when only warnings were reported.");
printStream.accept("");
printStream.accept("--format json writes one document to standard output, and quietens the");
printStream.accept("log so that it stays a document. Asking for -e or -X turns the log back");
printStream.accept("on, and its lines land in front of the document; -V prints the version");
printStream.accept("banner there whatever the log level.");
printStream.accept("");
printStream.accept("-C N (--context N) shows N lines of source before and after each problem");
printStream.accept("location, like grep -C. The default is 2. Pass 0 to suppress. Has no");
printStream.accept("effect under --format json, which always reports the raw line number.");
printStream.accept("");
}
@Override
protected CommonsCliValidateOptions copy(
String source, CommonsCliOptions.CLIManager cliManager, CommandLine commandLine) {
return new CommonsCliValidateOptions(source, (CLIManager) cliManager, commandLine);
}
protected static class CLIManager extends CommonsCliOptions.CLIManager {
public static final String FORMAT = "format";
public static final String MODE = "mode";
public static final String LOCAL_REPOSITORY = "local-repository";
public static final String TEMP_LOCAL_REPOSITORY = "temp-local-repository";
public static final String CONTEXT = "context";
@Override
protected void prepareOptions(org.apache.commons.cli.Options options) {
super.prepareOptions(options);
options.addOption(Option.builder()
.longOpt(FORMAT)
.hasArg()
.desc("Output format: text (default) or json.")
.get());
options.addOption(Option.builder()
.longOpt(MODE)
.hasArg()
.desc("How far to validate: effective (default) or raw.")
.get());
options.addOption(Option.builder()
.longOpt(LOCAL_REPOSITORY)
.hasArg()
.desc("Resolve into this local repository instead of the configured one.")
.get());
options.addOption(Option.builder()
.longOpt(TEMP_LOCAL_REPOSITORY)
.desc("Resolve into a directory created for this run and deleted when it ends.")
.get());
options.addOption(Option.builder("C")
.longOpt(CONTEXT)
.hasArg()
.argName("N")
.desc("Show N lines of XML context around each problem location (default 2, 0 to disable).")
.get());
}
@Override
protected String commandLineSyntax(String command) {
// The base syntax offers goals and phases. This tool runs neither.
return command + " [options] [<pom> ...]";
}
}
}