<commit_before><?php

final class PhabricatorRepositorySvnCommitChangeParserWorker
  extends PhabricatorRepositoryCommitChangeParserWorker {

  protected function parseCommitChanges(
    PhabricatorRepository $repository,
    PhabricatorRepositoryCommit $commit) {

    // PREAMBLE: This class is absurdly complicated because it is very difficult
    // to get the information we need out of SVN. The actual data we need is:
    //
    //  1. Recursively, what were the affected paths?
    //  2. For each affected path, is it a file or a directory?
    //  3. How was each path affected (e.g. add, delete, move, copy)?
    //
    // We spend nearly all of our effort figuring out (1) and (2) because
    // "svn log" is not recursive and does not give us file/directory
    // information (that is, it will report a directory move as a single move,
    // even if many thousands of paths are affected).
    //
    // Instead, we have to "svn ls -R" the location of each path in its previous
    // life to figure out whether it is a file or a directory and exactly which
    // recursive paths were affected if it was moved or copied. This is very
    // complicated and has many special cases.

    $uri = $repository->getSubversionPathURI();
    $svn_commit = $commit->getCommitIdentifier();

    // Pull the top-level path changes out of "svn log". This is pretty
    // straightforward; just parse the XML log.
    $log = $this->getSVNLogXMLObject($repository, $uri, $svn_commit);

    $entry = $log->logentry[0];

    if (!$entry->paths) {
      // TODO: Explicitly mark this commit as broken elsewhere? This isn't
      // supposed to happen but we have some cases like rE27 and rG935 in the
      // Facebook repositories where things got all clowned up.
      return array();
    }

    $raw_paths = array();
    foreach ($entry->paths->path as $path) {
      $name = trim((string)$path);
      $raw_paths[$name] = array(
        'rawPath'         => $name,
        'rawTargetPath'   => (string)$path['copyfrom-path'],
        'rawChangeType'   => (string)$path['action'],
        'rawTargetCommit' => (string)$path['copyfrom-rev'],
      );
    }

    $copied_or_moved_map = array();
    $deleted_paths = array();
    $add_paths = array();

    foreach ($raw_paths as $path => $raw_info) {
      if ($raw_info['rawTargetPath']) {
        $copied_or_moved_map[$raw_info['rawTargetPath']][] = $raw_info;
      }
      switch ($raw_info['rawChangeType']) {
        case 'D':
          $deleted_paths[$path] = $raw_info;
          break;<commit_msg>Use in-repository revision in copy operations<commit_after><?php

final class PhabricatorRepositorySvnCommitChangeParserWorker
  extends PhabricatorRepositoryCommitChangeParserWorker {

  protected function parseCommitChanges(
    PhabricatorRepository $repository,
    PhabricatorRepositoryCommit $commit) {

    // PREAMBLE: This class is absurdly complicated because it is very difficult
    // to get the information we need out of SVN. The actual data we need is:
    //
    //  1. Recursively, what were the affected paths?
    //  2. For each affected path, is it a file or a directory?
    //  3. How was each path affected (e.g. add, delete, move, copy)?
    //
    // We spend nearly all of our effort figuring out (1) and (2) because
    // "svn log" is not recursive and does not give us file/directory
    // information (that is, it will report a directory move as a single move,
    // even if many thousands of paths are affected).
    //
    // Instead, we have to "svn ls -R" the location of each path in its previous
    // life to figure out whether it is a file or a directory and exactly which
    // recursive paths were affected if it was moved or copied. This is very
    // complicated and has many special cases.

    $uri = $repository->getSubversionPathURI();
    $svn_commit = $commit->getCommitIdentifier();

    // Pull the top-level path changes out of "svn log". This is pretty
    // straightforward; just parse the XML log.
    $log = $this->getSVNLogXMLObject($repository, $uri, $svn_commit);

    $entry = $log->logentry[0];

    if (!$entry->paths) {
      // TODO: Explicitly mark this commit as broken elsewhere? This isn't
      // supposed to happen but we have some cases like rE27 and rG935 in the
      // Facebook repositories where things got all clowned up.
      return array();
    }

    $raw_paths = array();
    foreach ($entry->paths->path as $path) {
      $name = trim((string)$path);
      $raw_paths[$name] = array(
        'rawPath'         => $name,
        'rawTargetPath'   => (string)$path['copyfrom-path'],
        'rawChangeType'   => (string)$path['action'],
        'rawTargetCommit' => (string)$path['copyfrom-rev'],
      );

      // For copied items get revision from Diffusion repository sub-path,
      // because SVN reports last revision per whole SVN repository, not
      // sub-path, that is used in Diffusion.
      if ($raw_paths[$name]['rawTargetCommit']) {
        $better_revision = $repository->getSubversionParentCommit(
          $raw_paths[$name]['rawTargetCommit'] + 1);

        if ($better_revision) {
          $raw_paths[$name]['rawTargetCommit'] = $better_revision;
        }
      }
    }

    $copied_or_moved_map = array();
    $deleted_paths = array();
    $add_paths = array();

    foreach ($raw_paths as $path => $raw_info) {
      if ($raw_info['rawTargetPath']) {
        $copied_or_moved_map[$raw_info['rawTargetPath']][] = $raw_info;
      }
      switch ($raw_info['rawChangeType']) {
        case 'D':
          $deleted_paths[$path] = $raw_info;
          break;
{'fraction_non_alphanumeric': 0.11235555555555556, 'fraction_numerical': 0.004088888888888889, 'mean_word_length': 2.8064952638700946, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 28, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5112633', 'n_tokens_mistral': 1642, 'n_tokens_neox': 1622, 'n_words': 573}