/** * @task internal */ private function buildJoinsClause($conn_r) { $joins = array(); if ($this->pathIDs) { $path_table = new DifferentialAffectedPath(); $joins[] = qsprintf($conn_r, 'JOIN %T p ON p.revisionID = r.id', $path_table->getTableName()); } if ($this->commitHashes) { $joins[] = qsprintf($conn_r, 'JOIN %T hash_rel ON hash_rel.revisionID = r.id', ArcanistDifferentialRevisionHash::TABLE_NAME); } if ($this->ccs) { $joins[] = qsprintf($conn_r, 'JOIN %T cc_rel ON cc_rel.revisionID = r.id ' . 'AND cc_rel.relation = %s ' . 'AND cc_rel.objectPHID in (%Ls)', DifferentialRevision::RELATIONSHIP_TABLE, DifferentialRevision::RELATION_SUBSCRIBED, $this->ccs); } if ($this->reviewers) { $joins[] = qsprintf($conn_r, 'JOIN %T reviewer_rel ON reviewer_rel.revisionID = r.id ' . 'AND reviewer_rel.relation = %s ' . 'AND reviewer_rel.objectPHID in (%Ls)', DifferentialRevision::RELATIONSHIP_TABLE, DifferentialRevision::RELATION_REVIEWER, $this->reviewers); } if ($this->subscribers) { $joins[] = qsprintf($conn_r, 'JOIN %T sub_rel ON sub_rel.revisionID = r.id ' . 'AND sub_rel.relation IN (%Ls) ' . 'AND sub_rel.objectPHID in (%Ls)', DifferentialRevision::RELATIONSHIP_TABLE, array(DifferentialRevision::RELATION_SUBSCRIBED, DifferentialRevision::RELATION_REVIEWER), $this->subscribers); } if ($this->responsibles) { $joins[] = qsprintf($conn_r, 'LEFT JOIN %T responsibles_rel ON responsibles_rel.revisionID = r.id ' . 'AND responsibles_rel.relation = %s ' . 'AND responsibles_rel.objectPHID in (%Ls)', DifferentialRevision::RELATIONSHIP_TABLE, DifferentialRevision::RELATION_REVIEWER, $this->responsibles); } if ($this->draftAuthors) { $joins[] = qsprintf($conn_r, 'LEFT JOIN %T inline_comment ON inline_comment.revisionID = r.id ' . 'AND inline_comment.commentID IS NULL ' . 'AND inline_comment.authorPHID IN (%Ls)', id(new DifferentialInlineComment())->getTableName(), $this->draftAuthors); } $joins = implode(' ', $joins); return $joins; }
/** * @task internal */ private function buildJoinsClause($conn_r) { $joins = array(); if ($this->pathIDs) { $path_table = new DifferentialAffectedPath(); $joins[] = qsprintf($conn_r, 'JOIN %T p ON p.revisionID = r.id', $path_table->getTableName()); } if ($this->commitHashes) { $joins[] = qsprintf($conn_r, 'JOIN %T hash_rel ON hash_rel.revisionID = r.id', ArcanistDifferentialRevisionHash::TABLE_NAME); } if ($this->ccs) { $joins[] = qsprintf($conn_r, 'JOIN %T e_ccs ON e_ccs.src = r.phid ' . 'AND e_ccs.type = %s ' . 'AND e_ccs.dst in (%Ls)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER, $this->ccs); } if ($this->reviewers) { $joins[] = qsprintf($conn_r, 'JOIN %T e_reviewers ON e_reviewers.src = r.phid ' . 'AND e_reviewers.type = %s ' . 'AND e_reviewers.dst in (%Ls)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER, $this->reviewers); } if ($this->draftAuthors) { $differential_draft = new DifferentialDraft(); $joins[] = qsprintf($conn_r, 'JOIN %T has_draft ON has_draft.objectPHID = r.phid ' . 'AND has_draft.authorPHID IN (%Ls)', $differential_draft->getTableName(), $this->draftAuthors); } $joins = implode(' ', $joins); return $joins; }
/** * 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)); } }
public function destroyObjectPermanently(PhabricatorDestructionEngine $engine) { $this->openTransaction(); $diffs = id(new DifferentialDiffQuery())->setViewer($engine->getViewer())->withRevisionIDs(array($this->getID()))->execute(); foreach ($diffs as $diff) { $engine->destroyObject($diff); } $conn_w = $this->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE revisionID = %d', self::TABLE_COMMIT, $this->getID()); // we have to do paths a little differentally 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()); $this->delete(); $this->saveTransaction(); }
/** * @task internal */ private function buildJoinsClause($conn_r) { $joins = array(); if ($this->pathIDs) { $path_table = new DifferentialAffectedPath(); $joins[] = qsprintf($conn_r, 'JOIN %T p ON p.revisionID = r.id', $path_table->getTableName()); } if ($this->commitHashes) { $joins[] = qsprintf($conn_r, 'JOIN %T hash_rel ON hash_rel.revisionID = r.id', ArcanistDifferentialRevisionHash::TABLE_NAME); } if ($this->ccs) { $joins[] = qsprintf($conn_r, 'JOIN %T e_ccs ON e_ccs.src = r.phid ' . 'AND e_ccs.type = %s ' . 'AND e_ccs.dst in (%Ls)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorObjectHasSubscriberEdgeType::EDGECONST, $this->ccs); } if ($this->reviewers) { $joins[] = qsprintf($conn_r, 'JOIN %T e_reviewers ON e_reviewers.src = r.phid ' . 'AND e_reviewers.type = %s ' . 'AND e_reviewers.dst in (%Ls)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, DifferentialRevisionHasReviewerEdgeType::EDGECONST, $this->reviewers); } if ($this->draftAuthors) { $differential_draft = new DifferentialDraft(); $joins[] = qsprintf($conn_r, 'JOIN %T has_draft ON has_draft.objectPHID = r.phid ' . 'AND has_draft.authorPHID IN (%Ls)', $differential_draft->getTableName(), $this->draftAuthors); } if ($this->commitPHIDs) { $joins[] = qsprintf($conn_r, 'JOIN %T commits ON commits.revisionID = r.id', DifferentialRevision::TABLE_COMMIT); } $joins[] = $this->buildJoinClauseParts($conn_r); return $this->formatJoinClause($joins); }
public function delete() { $this->openTransaction(); $diffs = $this->loadDiffs(); foreach ($diffs as $diff) { $diff->delete(); } $conn_w = $this->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE revisionID = %d', self::RELATIONSHIP_TABLE, $this->getID()); queryfx($conn_w, 'DELETE FROM %T WHERE revisionID = %d', self::TABLE_COMMIT, $this->getID()); $comments = id(new DifferentialComment())->loadAllWhere('revisionID = %d', $this->getID()); foreach ($comments as $comment) { $comment->delete(); } $inlines = id(new DifferentialInlineComment())->loadAllWhere('revisionID = %d', $this->getID()); foreach ($inlines as $inline) { $inline->delete(); } $fields = id(new DifferentialAuxiliaryField())->loadAllWhere('revisionPHID = %s', $this->getPHID()); foreach ($fields as $field) { $field->delete(); } // we have to do paths a little differentally 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()); $result = parent::delete(); $this->saveTransaction(); return $result; }
/** * 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)); } }
public function destroyObjectPermanently(PhabricatorDestructionEngine $engine) { $this->openTransaction(); $diffs = id(new DifferentialDiffQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withRevisionIDs(array($this->getID()))->execute(); foreach ($diffs as $diff) { $engine->destroyObject($diff); } $conn_w = $this->establishConnection('w'); queryfx($conn_w, 'DELETE FROM %T WHERE revisionID = %d', self::TABLE_COMMIT, $this->getID()); try { $inlines = id(new DifferentialInlineCommentQuery())->withRevisionIDs(array($this->getID()))->execute(); foreach ($inlines as $inline) { $inline->delete(); } } catch (PhabricatorEmptyQueryException $ex) { // TODO: There's still some funky legacy wrapping going on here, and // we might catch a raw query exception. } // we have to do paths a little differentally 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()); $this->delete(); $this->saveTransaction(); }