Home | History | Annotate | Download | only in options
      1 // Copyright 2017 The Bazel Authors. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 package com.google.devtools.common.options;
     15 
     16 import java.io.IOException;
     17 import java.nio.file.FileSystem;
     18 import java.nio.file.Path;
     19 import java.util.List;
     20 
     21 /**
     22  * Defines an {@link ArgsPreProcessor} that will determine if the arguments list contains a "params"
     23  * file that contains a list of options to be parsed.
     24  *
     25  * <p>Params files are used when the argument list of {@link Option} exceed the shells commandline
     26  * length. A params file argument is defined as a path starting with @. It will also be the only
     27  * entry in an argument list.
     28  */
     29 public abstract class ParamsFilePreProcessor implements ArgsPreProcessor {
     30 
     31   static final String ERROR_MESSAGE_FORMAT = "Error reading params file: %s %s";
     32 
     33   static final String TOO_MANY_ARGS_ERROR_MESSAGE_FORMAT =
     34       "A params file must be the only argument: %s";
     35 
     36   static final String UNFINISHED_QUOTE_MESSAGE_FORMAT = "Unfinished quote %s at %s";
     37 
     38   private final FileSystem fs;
     39 
     40   ParamsFilePreProcessor(FileSystem fs) {
     41     this.fs = fs;
     42   }
     43 
     44   /**
     45    * Parses the param file path and replaces the arguments list with the contents if one exists.
     46    *
     47    * @param args A list of arguments that may contain @&lt;path&gt; to a params file.
     48    * @return A list of arguments suitable for parsing.
     49    * @throws OptionsParsingException if the path does not exist.
     50    */
     51   @Override
     52   public List<String> preProcess(List<String> args) throws OptionsParsingException {
     53     if (!args.isEmpty() && args.get(0).startsWith("@")) {
     54       if (args.size() > 1) {
     55         throw new OptionsParsingException(
     56             String.format(TOO_MANY_ARGS_ERROR_MESSAGE_FORMAT, args), args.get(0));
     57       }
     58       Path path = fs.getPath(args.get(0).substring(1));
     59       try {
     60         return parse(path);
     61       } catch (RuntimeException | IOException e) {
     62         throw new OptionsParsingException(
     63             String.format(ERROR_MESSAGE_FORMAT, path, e.getMessage()), args.get(0), e);
     64       }
     65     }
     66     return args;
     67   }
     68 
     69   /**
     70    * Parses the paramsFile and returns a list of argument tokens to be further processed by the
     71    * {@link OptionsParser}.
     72    *
     73    * @param paramsFile The path of the params file to parse.
     74    * @return a list of argument tokens.
     75    * @throws IOException if there is an error reading paramsFile.
     76    * @throws OptionsParsingException if there is an error reading paramsFile.
     77    */
     78   protected abstract List<String> parse(Path paramsFile)
     79       throws IOException, OptionsParsingException;
     80 }
     81