<commit_before><?php

/**
 * Applies changes from Differential or a file to the working copy.
 */
final class ArcanistPatchWorkflow extends ArcanistWorkflow {

  const SOURCE_BUNDLE         = 'bundle';
  const SOURCE_PATCH          = 'patch';
  const SOURCE_REVISION       = 'revision';
  const SOURCE_DIFF           = 'diff';

  private $source;
  private $sourceParam;

  public function getWorkflowName() {
    return 'patch';
  }

  public function getCommandSynopses() {
    return phutil_console_format(<<<EOTEXT
      **patch** __D12345__
      **patch** __--revision__ __revision_id__
      **patch** __--diff__ __diff_id__
      **patch** __--patch__ __file__
      **patch** __--arcbundle__ __bundlefile__
EOTEXT
      );
  }

  public function getCommandHelp() {
    return phutil_console_format(<<<EOTEXT
          Supports: git, svn, hg
          Apply the changes in a Differential revision, patchfile, or arc
          bundle to the working copy.
EOTEXT
      );
  }

  public function getArguments() {
    return array(
      'revision' => array(
        'param' => 'revision_id',
        'paramtype' => 'complete',
        'help' => pht(
          "Apply changes from a Differential revision, using the most recent ".
          "diff that has been attached to it. You can run '%s' as a shorthand.",
          'arc patch D12345'),
      ),
      'diff' => array(
        'param' => 'diff_id',
        'help' => pht(
          'Apply changes from a Differential diff. Normally you want to use '.
          '%s to get the most recent changes, but you can specifically apply '.
          'an out-of-date diff or a diff which was never attached to a '.
          'revision by using this flag.',
          '--revision'),
      ),
      'arcbundle' => array(
        'param' => 'bundlefile',
        'paramtype' => 'file',
        'help' => pht(
          "Apply changes from an arc bundle generated with '%s'.",
          'arc export'),
      ),
      'patch' => array(
        'param' => 'patchfile',
        'paramtype' => 'file',
        'help' => pht(
          'Apply changes from a git patchfile or unified patchfile.'),
      ),
      'encoding' => array(
        'param' => 'encoding',
        'help' => pht(
          'Attempt to convert non UTF-8 patch into specified encoding.'),
      ),
      'update' => array(
        'supports' => array('git', 'svn', 'hg'),
        'help' => pht(
          'Update the local working copy before applying the patch.'),
        'conflicts' => array(
          'nobranch' => true,
          'bookmark' => true,
        ),
      ),
      'nocommit' => array(
        'supports' => array('git', 'hg'),
        'help' => pht(
          'Normally under git/hg, if the patch is successful, the changes '.
          'are committed to the working copy. This flag prevents the commit.'),
      ),
      'skip-dependencies' => array(
        'supports' => array('git', 'hg'),
        'help' => pht(
          'Normally, if a patch has dependencies that are not present in the '.
          'working copy, arc tries to apply them as well. This flag prevents '.
          'such work.'),
      ),
      'nobranch' => array(
        'supports' => array('git', 'hg'),
        'help' => pht(
          'Normally, a new branch (git) or bookmark (hg) is created and then '.
          'the patch is applied and committed in the new branch/bookmark. '.
          'This flag cherry-picks the resultant commit onto the original '.
          'branch and deletes the temporary branch.'),
        'conflicts' => array(
          'update' => true,
        ),
      ),
      'force' => array(
        'help' => pht('Do not run any sanity checks.'),
      ),
      '*' => 'name',
    );
  }

  protected function didParseArguments() {
    $source = null;
    $requested = 0;
    if ($this->getArgument('revision')) {
      $source = self::SOURCE_REVISION;
      $requested++;
    }
    if ($this->getArgument('diff')) {
      $source = self::SOURCE_DIFF;
      $requested++;
    }
    if ($this->getArgument('arcbundle')) {
      $source = self::SOURCE_BUNDLE;
      $requested++;
    }
    if ($this->getArgument('patch')) {
      $source = self::SOURCE_PATCH;
      $requested++;
    }

    $use_revision_id = null;
    if ($this->getArgument('name')) {
      $namev = $this->getArgument('name');
      if (count($namev) > 1) {
        throw new ArcanistUsageException(
          pht('Specify at most one revision name.'));
      }
      $source = self::SOURCE_REVISION;
      $requested++;

      $use_revision_id = $this->normalizeRevisionID(head($namev));
    }

    if ($requested === 0) {
      throw new ArcanistUsageException(
        pht(
          "Specify one of '%s', '%s' (to select the current changes attached ".
          "to a Differential revision), '%s' (to select a specific, ".
          "out-of-date diff or a diff which is not attached to a revision), ".
          "'%s' or '%s' to choose a patch source.",
          'D12345',
          '--revision <revision_id>',
          '--diff <diff_id>',
          '--arcbundle <file>',
          '--patch <file>'));
    } else if ($requested > 1) {
      throw new ArcanistUsageException(
        pht(
          "Options '%s', '%s', '%s', '%s' and '%s' are not compatible. ".
          "Choose exactly one patch source.",
          'D12345',
          '--revision',
          '--diff',
          '--arcbundle',
          '--patch'));
    }

    $this->source = $source;
    $this->sourceParam = nonempty(
      $use_revision_id,
      $this->getArgument($source));
  }

  public function requiresConduit() {
    return ($this->getSource() != self::SOURCE_PATCH);
  }

  public function requiresRepositoryAPI() {
    return true;
  }

  public function requiresWorkingCopy() {
    return true;
  }

  private function getSource() {
    return $this->source;
  }

  private function getSourceParam() {
    return $this->sourceParam;
  }

  private function shouldCommit() {
    return !$this->getArgument('nocommit', false);<commit_msg>Improve argument parsing for "arc patch --revision Dxxx"<commit_after><?php

/**
 * Applies changes from Differential or a file to the working copy.
 */
final class ArcanistPatchWorkflow extends ArcanistWorkflow {

  const SOURCE_BUNDLE         = 'bundle';
  const SOURCE_PATCH          = 'patch';
  const SOURCE_REVISION       = 'revision';
  const SOURCE_DIFF           = 'diff';

  private $source;
  private $sourceParam;

  public function getWorkflowName() {
    return 'patch';
  }

  public function getCommandSynopses() {
    return phutil_console_format(<<<EOTEXT
      **patch** __D12345__
      **patch** __--revision__ __revision_id__
      **patch** __--diff__ __diff_id__
      **patch** __--patch__ __file__
      **patch** __--arcbundle__ __bundlefile__
EOTEXT
      );
  }

  public function getCommandHelp() {
    return phutil_console_format(<<<EOTEXT
          Supports: git, svn, hg
          Apply the changes in a Differential revision, patchfile, or arc
          bundle to the working copy.
EOTEXT
      );
  }

  public function getArguments() {
    return array(
      'revision' => array(
        'param' => 'revision_id',
        'paramtype' => 'complete',
        'help' => pht(
          "Apply changes from a Differential revision, using the most recent ".
          "diff that has been attached to it. You can run '%s' as a shorthand.",
          'arc patch D12345'),
      ),
      'diff' => array(
        'param' => 'diff_id',
        'help' => pht(
          'Apply changes from a Differential diff. Normally you want to use '.
          '%s to get the most recent changes, but you can specifically apply '.
          'an out-of-date diff or a diff which was never attached to a '.
          'revision by using this flag.',
          '--revision'),
      ),
      'arcbundle' => array(
        'param' => 'bundlefile',
        'paramtype' => 'file',
        'help' => pht(
          "Apply changes from an arc bundle generated with '%s'.",
          'arc export'),
      ),
      'patch' => array(
        'param' => 'patchfile',
        'paramtype' => 'file',
        'help' => pht(
          'Apply changes from a git patchfile or unified patchfile.'),
      ),
      'encoding' => array(
        'param' => 'encoding',
        'help' => pht(
          'Attempt to convert non UTF-8 patch into specified encoding.'),
      ),
      'update' => array(
        'supports' => array('git', 'svn', 'hg'),
        'help' => pht(
          'Update the local working copy before applying the patch.'),
        'conflicts' => array(
          'nobranch' => true,
          'bookmark' => true,
        ),
      ),
      'nocommit' => array(
        'supports' => array('git', 'hg'),
        'help' => pht(
          'Normally under git/hg, if the patch is successful, the changes '.
          'are committed to the working copy. This flag prevents the commit.'),
      ),
      'skip-dependencies' => array(
        'supports' => array('git', 'hg'),
        'help' => pht(
          'Normally, if a patch has dependencies that are not present in the '.
          'working copy, arc tries to apply them as well. This flag prevents '.
          'such work.'),
      ),
      'nobranch' => array(
        'supports' => array('git', 'hg'),
        'help' => pht(
          'Normally, a new branch (git) or bookmark (hg) is created and then '.
          'the patch is applied and committed in the new branch/bookmark. '.
          'This flag cherry-picks the resultant commit onto the original '.
          'branch and deletes the temporary branch.'),
        'conflicts' => array(
          'update' => true,
        ),
      ),
      'force' => array(
        'help' => pht('Do not run any sanity checks.'),
      ),
      '*' => 'name',
    );
  }

  protected function didParseArguments() {
    $arguments = array(
      'revision' => self::SOURCE_REVISION,
      'diff' => self::SOURCE_DIFF,
      'arcbundle' => self::SOURCE_BUNDLE,
      'patch' => self::SOURCE_PATCH,
      'name' => self::SOURCE_REVISION,
    );

    $sources = array();
    foreach ($arguments as $key => $source_type) {
      $value = $this->getArgument($key);
      if (!$value) {
        continue;
      }

      switch ($key) {
        case 'revision':
          $value = $this->normalizeRevisionID($value);
          break;
        case 'name':
          if (count($value) > 1) {
            throw new ArcanistUsageException(
              pht('Specify at most one revision name.'));
          }
          $value = $this->normalizeRevisionID(head($value));
          break;
      }

      $sources[] = array(
        $source_type,
        $value,
      );
    }

    if (!$sources) {
      throw new ArcanistUsageException(
        pht(
          'You must specify changes to apply to the working copy with '.
          '"D12345", "--revision", "--diff", "--arcbundle", or "--patch".'));
    }

    if (count($sources) > 1) {
      throw new ArcanistUsageException(
        pht(
          'Options "D12345", "--revision", "--diff", "--arcbundle" and '.
          '"--patch" are mutually exclusive. Choose exactly one patch '.
          'source.'));
    }

    $source = head($sources);

    $this->source = $source[0];
    $this->sourceParam = $source[1];
  }

  public function requiresConduit() {
    return ($this->getSource() != self::SOURCE_PATCH);
  }

  public function requiresRepositoryAPI() {
    return true;
  }

  public function requiresWorkingCopy() {
    return true;
  }

  private function getSource() {
    return $this->source;
  }

  private function getSourceParam() {
    return $this->sourceParam;
  }

  private function shouldCommit() {
    return !$this->getArgument('nocommit', false);
{'fraction_non_alphanumeric': 0.13924589326751213, 'fraction_numerical': 0.004255681334581667, 'mean_word_length': 2.1084656084656084, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 116, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6525695', 'n_tokens_mistral': 3564, 'n_tokens_neox': 3425, 'n_words': 1042}