private function assertArgumentCompletion($expect, $input, $arguments)
 {
     $result = ArcanistConfiguration::correctArgumentSpelling($input, $arguments);
     sort($result);
     sort($expect);
     $arguments = implode(', ', $arguments);
     $this->assertEqual($expect, $result, "Correction of {$input} against: {$arguments}");
 }
 public 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();
     for ($ii = 0; $ii < count($args); $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);
                 if (!array_key_exists($arg_key, $spec)) {
                     $corrected = ArcanistConfiguration::correctArgumentSpelling($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("Unknown argument '{$arg_key}'. Try 'arc help'.");
                     }
                 }
             } else {
                 if (!strncmp($arg, '-', 1)) {
                     $arg_key = substr($arg, 1);
                     if (empty($short_to_long_map[$arg_key])) {
                         throw new ArcanistUsageException("Unknown argument '{$arg_key}'. Try '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 == count($args) - 1) {
                 throw new ArcanistUsageException("Option '{$arg}' requires a parameter.");
             }
             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("Unrecognized argument '{$example}'. Try '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("Arguments '--{$key}' and '--{$conflict}' are mutually exclusive" . $more);
             }
         }
     }
     $this->arguments = $dict;
     $this->didParseArguments();
     return $this;
 }