diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ea1e40dd57..3bdc63e7b2 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -450,6 +450,7 @@ phutil_register_library_map(array( 'DifferentialActionEmailCommand' => 'applications/differential/command/DifferentialActionEmailCommand.php', 'DifferentialAdjustmentMapTestCase' => 'applications/differential/storage/__tests__/DifferentialAdjustmentMapTestCase.php', 'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php', + 'DifferentialAffectedPathEngine' => 'applications/differential/engine/DifferentialAffectedPathEngine.php', 'DifferentialAsanaRepresentationField' => 'applications/differential/customfield/DifferentialAsanaRepresentationField.php', 'DifferentialAuditorsCommitMessageField' => 'applications/differential/field/DifferentialAuditorsCommitMessageField.php', 'DifferentialAuditorsField' => 'applications/differential/customfield/DifferentialAuditorsField.php', @@ -6533,6 +6534,7 @@ phutil_register_library_map(array( 'DifferentialActionEmailCommand' => 'MetaMTAEmailTransactionCommand', 'DifferentialAdjustmentMapTestCase' => 'PhabricatorTestCase', 'DifferentialAffectedPath' => 'DifferentialDAO', + 'DifferentialAffectedPathEngine' => 'Phobject', 'DifferentialAsanaRepresentationField' => 'DifferentialCustomField', 'DifferentialAuditorsCommitMessageField' => 'DifferentialCommitMessageCustomField', 'DifferentialAuditorsField' => 'DifferentialStoredCustomField', diff --git a/src/applications/differential/editor/DifferentialTransactionEditor.php b/src/applications/differential/editor/DifferentialTransactionEditor.php index af81af73a8..230558d797 100644 --- a/src/applications/differential/editor/DifferentialTransactionEditor.php +++ b/src/applications/differential/editor/DifferentialTransactionEditor.php @@ -356,7 +356,12 @@ final class DifferentialTransactionEditor // diff to a revision. $this->updateRevisionHashTable($object, $diff); - $this->updateAffectedPathTable($object, $diff); + + id(new DifferentialAffectedPathEngine()) + ->setRevision($object) + ->setDiff($diff) + ->updateAffectedPaths(); + break; } } @@ -1258,92 +1263,6 @@ final class DifferentialTransactionEditor return $adapter; } - /** - * 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 %LQ', - $table->getTableName(), - $chunk); - } - } - /** * Update the table connecting revisions to DVCS local hashes, so we can * identify revisions by commit/tree hashes. diff --git a/src/applications/differential/engine/DifferentialAffectedPathEngine.php b/src/applications/differential/engine/DifferentialAffectedPathEngine.php new file mode 100644 index 0000000000..cdf1c168b1 --- /dev/null +++ b/src/applications/differential/engine/DifferentialAffectedPathEngine.php @@ -0,0 +1,137 @@ +revision = $revision; + return $this; + } + + public function getRevision() { + return $this->revision; + } + + public function setDiff(DifferentialDiff $diff) { + $this->diff = $diff; + return $this; + } + + public function getDiff() { + return $this->diff; + } + + public function updateAffectedPaths() { + $revision = $this->getRevision(); + $diff = $this->getDiff(); + $repository = $revision->getRepository(); + + if ($repository) { + $repository_id = $repository->getID(); + } else { + return; + } + + $paths = $this->getAffectedPaths(); + + $path_ids = + PhabricatorRepositoryCommitChangeParserWorker::lookupOrCreatePaths( + $paths); + + $table = new DifferentialAffectedPath(); + $conn = $table->establishConnection('w'); + + $sql = array(); + foreach ($path_ids as $path_id) { + $sql[] = qsprintf( + $conn, + '(%d, %d, %d, %d)', + $repository_id, + $path_id, + PhabricatorTime::getNow(), + $revision->getID()); + } + + queryfx( + $conn, + 'DELETE FROM %R WHERE revisionID = %d', + $table, + $revision->getID()); + if ($sql) { + foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { + queryfx( + $conn, + 'INSERT INTO %R (repositoryID, pathID, epoch, revisionID) VALUES %LQ', + $table, + $chunk); + } + } + } + + public function destroyAffectedPaths() { + $revision = $this->getRevision(); + + $table = new DifferentialAffectedPath(); + $conn = $table->establishConnection('w'); + + queryfx( + $conn, + 'DELETE FROM %R WHERE revisionID = %d', + $table, + $revision->getID()); + } + + public function getAffectedPaths() { + $revision = $this->getRevision(); + $diff = $this->getDiff(); + $repository = $revision->getRepository(); + + $path_prefix = null; + if ($repository) { + $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); + + return $all_paths; + } + +} diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php index 15cf219f7b..23f5db9151 100644 --- a/src/applications/differential/storage/DifferentialRevision.php +++ b/src/applications/differential/storage/DifferentialRevision.php @@ -1022,16 +1022,9 @@ final class DifferentialRevision extends DifferentialDAO $engine->destroyObject($diff); } - $conn_w = $this->establishConnection('w'); - - // we have to do paths a little differently as they do not have - // an id or phid column for delete() to act on - $dummy_path = new DifferentialAffectedPath(); - queryfx( - $conn_w, - 'DELETE FROM %T WHERE revisionID = %d', - $dummy_path->getTableName(), - $this->getID()); + id(new DifferentialAffectedPathEngine()) + ->setRevision($this) + ->destroyAffectedPaths(); $viewstate_query = id(new DifferentialViewStateQuery()) ->setViewer($viewer)