public static function createDiffDict(DifferentialDiff $diff)
 {
     $dict = array('id' => $diff->getID(), 'parent' => $diff->getParentRevisionID(), 'sourceControlBaseRevision' => $diff->getSourceControlBaseRevision(), 'sourceControlPath' => $diff->getSourceControlPath(), 'changes' => array());
     foreach ($diff->getChangesets() as $changeset) {
         $hunks = array();
         foreach ($changeset->getHunks() as $hunk) {
             $hunks[] = array('oldOffset' => $hunk->getOldOffset(), 'newOffset' => $hunk->getNewOffset(), 'oldLength' => $hunk->getOldLen(), 'newLength' => $hunk->getNewLen(), 'addLines' => null, 'delLines' => null, 'isMissingOldNewline' => null, 'isMissingNewNewline' => null, 'corpus' => $hunk->getChanges());
         }
         $change = array('metadata' => $changeset->getMetadata(), 'oldPath' => $changeset->getOldFile(), 'currentPath' => $changeset->getFileName(), 'awayPaths' => $changeset->getAwayPaths(), 'oldProperties' => $changeset->getOldProperties(), 'newProperties' => $changeset->getNewProperties(), 'type' => $changeset->getChangeType(), 'fileType' => $changeset->getFileType(), 'commitHash' => null, 'hunks' => $hunks);
         $dict['changes'][] = $change;
     }
     return $dict;
 }
 public function getAbsoluteRepositoryPath(PhabricatorRepository $repository, DifferentialDiff $diff = null)
 {
     $base = '/';
     if ($diff && $diff->getSourceControlPath()) {
         $base = id(new PhutilURI($diff->getSourceControlPath()))->getPath();
     }
     $path = $this->getFilename();
     $path = rtrim($base, '/') . '/' . ltrim($path, '/');
     $vcs = $repository->getVersionControlSystem();
     if ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) {
         $prefix = $repository->getDetail('remote-uri');
         $prefix = id(new PhutilURI($prefix))->getPath();
         if (!strncmp($path, $prefix, strlen($prefix))) {
             $path = substr($path, strlen($prefix));
         }
         $path = '/' . ltrim($path, '/');
     }
     return $path;
 }
 /**
  * Update the table which links Differential revisions to paths they affect,
  * so Diffusion can efficiently find pending revisions for a given file.
  */
 private function updateAffectedPathTable(DifferentialRevision $revision, DifferentialDiff $diff)
 {
     $repository = $revision->getRepository();
     if (!$repository) {
         // The repository where the code lives is untracked.
         return;
     }
     $path_prefix = null;
     $local_root = $diff->getSourceControlPath();
     if ($local_root) {
         // We're in a working copy which supports subdirectory checkouts (e.g.,
         // SVN) so we need to figure out what prefix we should add to each path
         // (e.g., trunk/projects/example/) to get the absolute path from the
         // root of the repository. DVCS systems like Git and Mercurial are not
         // affected.
         // Normalize both paths and check if the repository root is a prefix of
         // the local root. If so, throw it away. Note that this correctly handles
         // the case where the remote path is "/".
         $local_root = id(new PhutilURI($local_root))->getPath();
         $local_root = rtrim($local_root, '/');
         $repo_root = id(new PhutilURI($repository->getRemoteURI()))->getPath();
         $repo_root = rtrim($repo_root, '/');
         if (!strncmp($repo_root, $local_root, strlen($repo_root))) {
             $path_prefix = substr($local_root, strlen($repo_root));
         }
     }
     $changesets = $diff->getChangesets();
     $paths = array();
     foreach ($changesets as $changeset) {
         $paths[] = $path_prefix . '/' . $changeset->getFilename();
     }
     // Mark this as also touching all parent paths, so you can see all pending
     // changes to any file within a directory.
     $all_paths = array();
     foreach ($paths as $local) {
         foreach (DiffusionPathIDQuery::expandPathToRoot($local) as $path) {
             $all_paths[$path] = true;
         }
     }
     $all_paths = array_keys($all_paths);
     $path_ids = PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths($all_paths);
     $table = new DifferentialAffectedPath();
     $conn_w = $table->establishConnection('w');
     $sql = array();
     foreach ($path_ids as $path_id) {
         $sql[] = qsprintf($conn_w, '(%d, %d, %d, %d)', $repository->getID(), $path_id, time(), $revision->getID());
     }
     queryfx($conn_w, 'DELETE FROM %T WHERE revisionID = %d', $table->getTableName(), $revision->getID());
     foreach (array_chunk($sql, 256) as $chunk) {
         queryfx($conn_w, 'INSERT INTO %T (repositoryID, pathID, epoch, revisionID) VALUES %Q', $table->getTableName(), implode(', ', $chunk));
     }
 }
 /**
  * Update the table which links Differential revisions to paths they affect,
  * so Diffusion can efficiently find pending revisions for a given file.
  */
 private function updateAffectedPathTable(DifferentialRevision $revision, DifferentialDiff $diff, array $changesets)
 {
     assert_instances_of($changesets, 'DifferentialChangeset');
     $project = $diff->loadArcanistProject();
     if (!$project) {
         // Probably an old revision from before projects.
         return;
     }
     $repository = $project->loadRepository();
     if (!$repository) {
         // Probably no project <-> repository link, or the repository where the
         // project lives is untracked.
         return;
     }
     $path_prefix = null;
     $local_root = $diff->getSourceControlPath();
     if ($local_root) {
         // We're in a working copy which supports subdirectory checkouts (e.g.,
         // SVN) so we need to figure out what prefix we should add to each path
         // (e.g., trunk/projects/example/) to get the absolute path from the
         // root of the repository. DVCS systems like Git and Mercurial are not
         // affected.
         // Normalize both paths and check if the repository root is a prefix of
         // the local root. If so, throw it away. Note that this correctly handles
         // the case where the remote path is "/".
         $local_root = id(new PhutilURI($local_root))->getPath();
         $local_root = rtrim($local_root, '/');
         $repo_root = id(new PhutilURI($repository->getRemoteURI()))->getPath();
         $repo_root = rtrim($repo_root, '/');
         if (!strncmp($repo_root, $local_root, strlen($repo_root))) {
             $path_prefix = substr($local_root, strlen($repo_root));
         }
     }
     $paths = array();
     foreach ($changesets as $changeset) {
         $paths[] = $path_prefix . '/' . $changeset->getFilename();
     }
     // Mark this as also touching all parent paths, so you can see all pending
     // changes to any file within a directory.
     $all_paths = array();
     foreach ($paths as $local) {
         foreach (DiffusionPathIDQuery::expandPathToRoot($local) as $path) {
             $all_paths[$path] = true;
         }
     }
     $all_paths = array_keys($all_paths);
     $path_map = id(new DiffusionPathIDQuery($all_paths))->loadPathIDs();
     $table = new DifferentialAffectedPath();
     $conn_w = $table->establishConnection('w');
     $sql = array();
     foreach ($all_paths as $path) {
         $path_id = idx($path_map, $path);
         if (!$path_id) {
             // Don't bother creating these, it probably means we're either adding
             // a file (in which case having this row is irrelevant since Diffusion
             // won't be querying for it) or something is misconfigured (in which
             // case we'd just be writing garbage).
             continue;
         }
         $sql[] = qsprintf($conn_w, '(%d, %d, %d, %d)', $repository->getID(), $path_id, time(), $revision->getID());
     }
     queryfx($conn_w, 'DELETE FROM %T WHERE revisionID = %d', $table->getTableName(), $revision->getID());
     foreach (array_chunk($sql, 256) as $chunk) {
         queryfx($conn_w, 'INSERT INTO %T (repositoryID, pathID, epoch, revisionID) VALUES %Q', $table->getTableName(), implode(', ', $chunk));
     }
 }