| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 // Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file |  | 
| 2 // for details. All rights reserved. Use of this source code is governed by a |  | 
| 3 // BSD-style license that can be found in the LICENSE file. |  | 
| 4 |  | 
| 5 library fasta.command_line; |  | 
| 6 |  | 
| 7 import 'fasta_codes.dart' show Message, templateFastaCLIArgumentRequired; |  | 
| 8 |  | 
| 9 import 'deprecated_problems.dart' show deprecated_inputError; |  | 
| 10 |  | 
| 11 import 'problems.dart' show unhandled; |  | 
| 12 |  | 
| 13 deprecated_argumentError(Message usage, String message) { |  | 
| 14   if (usage != null) print(usage.message); |  | 
| 15   deprecated_inputError(null, null, message); |  | 
| 16 } |  | 
| 17 |  | 
| 18 argumentError(Message usage, Message message) { |  | 
| 19   if (usage != null) print(usage.message); |  | 
| 20   deprecated_inputError(null, null, message.message); |  | 
| 21 } |  | 
| 22 |  | 
| 23 class ParsedArguments { |  | 
| 24   final Map<String, dynamic> options = <String, dynamic>{}; |  | 
| 25   final List<String> arguments = <String>[]; |  | 
| 26 |  | 
| 27   toString() => "ParsedArguments($options, $arguments)"; |  | 
| 28 } |  | 
| 29 |  | 
| 30 /// Abstract parser for command-line options. |  | 
| 31 class CommandLine { |  | 
| 32   final Map<String, dynamic> options; |  | 
| 33 |  | 
| 34   final List<String> arguments; |  | 
| 35 |  | 
| 36   final Message usage; |  | 
| 37 |  | 
| 38   CommandLine.parsed(ParsedArguments p, this.usage) |  | 
| 39       : this.options = p.options, |  | 
| 40         this.arguments = p.arguments { |  | 
| 41     validate(); |  | 
| 42     if (verbose) { |  | 
| 43       print(p); |  | 
| 44     } |  | 
| 45   } |  | 
| 46 |  | 
| 47   CommandLine(List<String> arguments, |  | 
| 48       {Map<String, dynamic> specification, Message usage}) |  | 
| 49       : this.parsed(parse(arguments, specification, usage), usage); |  | 
| 50 |  | 
| 51   bool get verbose { |  | 
| 52     return options.containsKey("-v") || options.containsKey("--verbose"); |  | 
| 53   } |  | 
| 54 |  | 
| 55   /// Override to validate arguments and options. |  | 
| 56   void validate() {} |  | 
| 57 |  | 
| 58   /// Parses a list of command-line [arguments] into options and arguments. |  | 
| 59   /// |  | 
| 60   /// An /option/ is something that, normally, starts with `-` or `--` (one or |  | 
| 61   /// two dashes). However, as a special case `/?` and `/h` are also recognized |  | 
| 62   /// as options for increased compatibility with Windows. An option can have a |  | 
| 63   /// value. |  | 
| 64   /// |  | 
| 65   /// An /argument/ is something that isn't an option, for example, a file name. |  | 
| 66   /// |  | 
| 67   /// The specification is a map of options to one of the type literals `Uri`, |  | 
| 68   /// `int`, `bool`, or `String`, or a comma (`","`) that represents option |  | 
| 69   /// values of type [Uri], [int], [bool], [String], or a comma-separated list |  | 
| 70   /// of [String], respectively. |  | 
| 71   /// |  | 
| 72   /// If [arguments] contains `"--"`, anything before is parsed as options, and |  | 
| 73   /// arguments; anything following is treated as arguments (even if starting |  | 
| 74   /// with, for example, a `-`). |  | 
| 75   /// |  | 
| 76   /// Anything that looks like an option is assumed to be a `bool` option set |  | 
| 77   /// to true, unless it's mentioned in [specification] in which case the |  | 
| 78   /// option requires a value, either on the form `--option value` or |  | 
| 79   /// `--option=value`. |  | 
| 80   /// |  | 
| 81   /// This method performs only a limited amount of validation, but if an error |  | 
| 82   /// occurs, it will print [usage] along with a specific error message. |  | 
| 83   static ParsedArguments parse(List<String> arguments, |  | 
| 84       Map<String, dynamic> specification, Message usage) { |  | 
| 85     specification ??= const <String, dynamic>{}; |  | 
| 86     ParsedArguments result = new ParsedArguments(); |  | 
| 87     int index = arguments.indexOf("--"); |  | 
| 88     Iterable<String> nonOptions = const <String>[]; |  | 
| 89     Iterator<String> iterator = arguments.iterator; |  | 
| 90     if (index != -1) { |  | 
| 91       nonOptions = arguments.skip(index + 1); |  | 
| 92       iterator = arguments.take(index).iterator; |  | 
| 93     } |  | 
| 94     while (iterator.moveNext()) { |  | 
| 95       String argument = iterator.current; |  | 
| 96       if (argument.startsWith("-")) { |  | 
| 97         var valueSpecification = specification[argument]; |  | 
| 98         String value; |  | 
| 99         if (valueSpecification != null) { |  | 
| 100           if (!iterator.moveNext()) { |  | 
| 101             return argumentError(usage, |  | 
| 102                 templateFastaCLIArgumentRequired.withArguments(argument)); |  | 
| 103           } |  | 
| 104           value = iterator.current; |  | 
| 105         } else { |  | 
| 106           index = argument.indexOf("="); |  | 
| 107           if (index != -1) { |  | 
| 108             value = argument.substring(index + 1); |  | 
| 109             argument = argument.substring(0, index); |  | 
| 110             valueSpecification = specification[argument]; |  | 
| 111           } |  | 
| 112         } |  | 
| 113         if (valueSpecification == null) { |  | 
| 114           if (value != null) { |  | 
| 115             return deprecated_argumentError( |  | 
| 116                 usage, "Argument '$argument' doesn't take a value: '$value'."); |  | 
| 117           } |  | 
| 118           result.options[argument] = true; |  | 
| 119         } else { |  | 
| 120           if (valueSpecification is! String && valueSpecification is! Type) { |  | 
| 121             return deprecated_argumentError( |  | 
| 122                 usage, |  | 
| 123                 "Unrecognized type of value " |  | 
| 124                 "specification: ${valueSpecification.runtimeType}."); |  | 
| 125           } |  | 
| 126           switch ("$valueSpecification") { |  | 
| 127             case ",": |  | 
| 128               result.options |  | 
| 129                   .putIfAbsent(argument, () => <String>[]) |  | 
| 130                   .addAll(value.split(",")); |  | 
| 131               break; |  | 
| 132 |  | 
| 133             case "int": |  | 
| 134             case "bool": |  | 
| 135             case "String": |  | 
| 136             case "Uri": |  | 
| 137               if (result.options.containsKey(argument)) { |  | 
| 138                 return deprecated_argumentError( |  | 
| 139                     usage, |  | 
| 140                     "Multiple values for '$argument': " |  | 
| 141                     "'${result.options[argument]}' and '$value'."); |  | 
| 142               } |  | 
| 143               var parsedValue; |  | 
| 144               if (valueSpecification == int) { |  | 
| 145                 parsedValue = int.parse(value, onError: (_) { |  | 
| 146                   return deprecated_argumentError( |  | 
| 147                       usage, "Value for '$argument', '$value', isn't an int."); |  | 
| 148                 }); |  | 
| 149               } else if (valueSpecification == bool) { |  | 
| 150                 if (value == "true" || value == "yes") { |  | 
| 151                   parsedValue = true; |  | 
| 152                 } else if (value == "false" || value == "no") { |  | 
| 153                   parsedValue = false; |  | 
| 154                 } else { |  | 
| 155                   return deprecated_argumentError( |  | 
| 156                       usage, |  | 
| 157                       "Value for '$argument' is '$value', " |  | 
| 158                       "but expected one of: 'true', 'false', 'yes', or 'no'."); |  | 
| 159                 } |  | 
| 160               } else if (valueSpecification == Uri) { |  | 
| 161                 parsedValue = Uri.base.resolve(value); |  | 
| 162               } else if (valueSpecification == String) { |  | 
| 163                 parsedValue = value; |  | 
| 164               } else if (valueSpecification is String) { |  | 
| 165                 return deprecated_argumentError( |  | 
| 166                     usage, |  | 
| 167                     "Unrecognized value specification: " |  | 
| 168                     "'$valueSpecification', try using a type literal instead."); |  | 
| 169               } else { |  | 
| 170                 // All possible cases should have been handled above. |  | 
| 171                 return unhandled("${valueSpecification.runtimeType}", |  | 
| 172                     "CommandLine.parse", -1, null); |  | 
| 173               } |  | 
| 174               result.options[argument] = parsedValue; |  | 
| 175               break; |  | 
| 176 |  | 
| 177             default: |  | 
| 178               return deprecated_argumentError(usage, |  | 
| 179                   "Unrecognized value specification: '$valueSpecification'."); |  | 
| 180           } |  | 
| 181         } |  | 
| 182       } else if (argument == "/?" || argument == "/h") { |  | 
| 183         result.options[argument] = true; |  | 
| 184       } else { |  | 
| 185         result.arguments.add(argument); |  | 
| 186       } |  | 
| 187     } |  | 
| 188     result.arguments.addAll(nonOptions); |  | 
| 189     return result; |  | 
| 190   } |  | 
| 191 } |  | 
| OLD | NEW | 
|---|