コード例 #1
0
 private function assertFlagCorrection($expect, $input, $flags)
 {
     $result = PhutilArgumentSpellingCorrector::newFlagCorrector()->correctSpelling($input, $flags);
     sort($result);
     sort($expect);
     $flags = implode(', ', $flags);
     $this->assertEqual($expect, $result, pht('Correction of %s against: %s', $input, $flags));
 }
コード例 #2
0
 private function parseInternal(array $specs, $correct_spelling)
 {
     $specs = PhutilArgumentSpecification::newSpecsFromList($specs);
     $this->mergeSpecs($specs);
     $specs_by_name = mpull($specs, null, 'getName');
     $specs_by_short = mpull($specs, null, 'getShortAlias');
     unset($specs_by_short[null]);
     $argv = $this->argv;
     $len = count($argv);
     for ($ii = 0; $ii < $len; $ii++) {
         $arg = $argv[$ii];
         $map = null;
         $options = null;
         if (!is_string($arg)) {
             // Non-string argument; pass it through as-is.
         } else {
             if ($arg == '--') {
                 // This indicates "end of flags".
                 break;
             } else {
                 if ($arg == '-') {
                     // This is a normal argument (e.g., stdin).
                     continue;
                 } else {
                     if (!strncmp('--', $arg, 2)) {
                         $pre = '--';
                         $arg = substr($arg, 2);
                         $map = $specs_by_name;
                         $options = array_keys($specs_by_name);
                     } else {
                         if (!strncmp('-', $arg, 1) && strlen($arg) > 1) {
                             $pre = '-';
                             $arg = substr($arg, 1);
                             $map = $specs_by_short;
                         }
                     }
                 }
             }
         }
         if ($map) {
             $val = null;
             $parts = explode('=', $arg, 2);
             if (count($parts) == 2) {
                 list($arg, $val) = $parts;
             }
             // Try to correct flag spelling for full flags, to allow users to make
             // minor mistakes.
             if ($correct_spelling && $options && !isset($map[$arg])) {
                 $corrections = PhutilArgumentSpellingCorrector::newFlagCorrector()->correctSpelling($arg, $options);
                 if (count($corrections) == 1) {
                     $corrected = head($corrections);
                     $this->logMessage(tsprintf("%s\n", pht('(Assuming "%s" is the British spelling of "%s".)', $pre . $arg, $pre . $corrected)));
                     $arg = $corrected;
                 }
             }
             if (isset($map[$arg])) {
                 $spec = $map[$arg];
                 unset($argv[$ii]);
                 $param_name = $spec->getParamName();
                 if ($val !== null) {
                     if ($param_name === null) {
                         throw new PhutilArgumentUsageException(pht("Argument '%s' does not take a parameter.", "{$pre}{$arg}"));
                     }
                 } else {
                     if ($param_name !== null) {
                         if ($ii + 1 < $len) {
                             $val = $argv[$ii + 1];
                             unset($argv[$ii + 1]);
                             $ii++;
                         } else {
                             throw new PhutilArgumentUsageException(pht("Argument '%s' requires a parameter.", "{$pre}{$arg}"));
                         }
                     } else {
                         $val = true;
                     }
                 }
                 if (!$spec->getRepeatable()) {
                     if (array_key_exists($spec->getName(), $this->results)) {
                         throw new PhutilArgumentUsageException(pht("Argument '%s' was provided twice.", "{$pre}{$arg}"));
                     }
                 }
                 $conflicts = $spec->getConflicts();
                 foreach ($conflicts as $conflict => $reason) {
                     if (array_key_exists($conflict, $this->results)) {
                         if (!is_string($reason) || !strlen($reason)) {
                             $reason = '.';
                         } else {
                             $reason = ': ' . $reason . '.';
                         }
                         throw new PhutilArgumentUsageException(pht("Argument '%s' conflicts with argument '%s'%s", "{$pre}{$arg}", "--{$conflict}", $reason));
                     }
                 }
                 if ($spec->getRepeatable()) {
                     if ($spec->getParamName() === null) {
                         if (empty($this->results[$spec->getName()])) {
                             $this->results[$spec->getName()] = 0;
                         }
                         $this->results[$spec->getName()]++;
                     } else {
                         $this->results[$spec->getName()][] = $val;
                     }
                 } else {
                     $this->results[$spec->getName()] = $val;
                 }
             }
         }
     }
     foreach ($specs as $spec) {
         if ($spec->getWildcard()) {
             $this->results[$spec->getName()] = $this->filterWildcardArgv($argv);
             $argv = array();
             break;
         }
     }
     $this->argv = array_values($argv);
     return $this;
 }
コード例 #3
0
 public final function parseArguments(array $args)
 {
     $this->passedArguments = $args;
     $spec = $this->getCompleteArgumentSpecification();
     $dict = array();
     $more_key = null;
     if (!empty($spec['*'])) {
         $more_key = $spec['*'];
         unset($spec['*']);
         $dict[$more_key] = array();
     }
     $short_to_long_map = array();
     foreach ($spec as $long => $options) {
         if (!empty($options['short'])) {
             $short_to_long_map[$options['short']] = $long;
         }
     }
     foreach ($spec as $long => $options) {
         if (!empty($options['repeat'])) {
             $dict[$long] = array();
         }
     }
     $more = array();
     $size = count($args);
     for ($ii = 0; $ii < $size; $ii++) {
         $arg = $args[$ii];
         $arg_name = null;
         $arg_key = null;
         if ($arg == '--') {
             $more = array_merge($more, array_slice($args, $ii + 1));
             break;
         } else {
             if (!strncmp($arg, '--', 2)) {
                 $arg_key = substr($arg, 2);
                 $parts = explode('=', $arg_key, 2);
                 if (count($parts) == 2) {
                     list($arg_key, $val) = $parts;
                     array_splice($args, $ii, 1, array('--' . $arg_key, $val));
                     $size++;
                 }
                 if (!array_key_exists($arg_key, $spec)) {
                     $corrected = PhutilArgumentSpellingCorrector::newFlagCorrector()->correctSpelling($arg_key, array_keys($spec));
                     if (count($corrected) == 1) {
                         PhutilConsole::getConsole()->writeErr(pht("(Assuming '%s' is the British spelling of '%s'.)", '--' . $arg_key, '--' . head($corrected)) . "\n");
                         $arg_key = head($corrected);
                     } else {
                         throw new ArcanistUsageException(pht("Unknown argument '%s'. Try '%s'.", $arg_key, 'arc help'));
                     }
                 }
             } else {
                 if (!strncmp($arg, '-', 1)) {
                     $arg_key = substr($arg, 1);
                     if (empty($short_to_long_map[$arg_key])) {
                         throw new ArcanistUsageException(pht("Unknown argument '%s'. Try '%s'.", $arg_key, 'arc help'));
                     }
                     $arg_key = $short_to_long_map[$arg_key];
                 } else {
                     $more[] = $arg;
                     continue;
                 }
             }
         }
         $options = $spec[$arg_key];
         if (empty($options['param'])) {
             $dict[$arg_key] = true;
         } else {
             if ($ii == $size - 1) {
                 throw new ArcanistUsageException(pht("Option '%s' requires a parameter.", $arg));
             }
             if (!empty($options['repeat'])) {
                 $dict[$arg_key][] = $args[$ii + 1];
             } else {
                 $dict[$arg_key] = $args[$ii + 1];
             }
             $ii++;
         }
     }
     if ($more) {
         if ($more_key) {
             $dict[$more_key] = $more;
         } else {
             $example = reset($more);
             throw new ArcanistUsageException(pht("Unrecognized argument '%s'. Try '%s'.", $example, 'arc help'));
         }
     }
     foreach ($dict as $key => $value) {
         if (empty($spec[$key]['conflicts'])) {
             continue;
         }
         foreach ($spec[$key]['conflicts'] as $conflict => $more) {
             if (isset($dict[$conflict])) {
                 if ($more) {
                     $more = ': ' . $more;
                 } else {
                     $more = '.';
                 }
                 // TODO: We'll always display these as long-form, when the user might
                 // have typed them as short form.
                 throw new ArcanistUsageException(pht("Arguments '%s' and '%s' are mutually exclusive", "--{$key}", "--{$conflict}") . $more);
             }
         }
     }
     $this->arguments = $dict;
     $this->didParseArguments();
     return $this;
 }